Index: stable/12/usr.bin/posixshmcontrol/posixshmcontrol.1 =================================================================== --- stable/12/usr.bin/posixshmcontrol/posixshmcontrol.1 (revision 365993) +++ stable/12/usr.bin/posixshmcontrol/posixshmcontrol.1 (revision 365994) @@ -1,154 +1,154 @@ .\" Copyright (c) 2019 The FreeBSD Foundation, Inc. .\" .\" This documentation was written by .\" Konstantin Belousov under sponsorship .\" from the FreeBSD Foundation. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd March 18, 2020 .Dt POSIXSHMCONTROL 1 .Os .Sh NAME .Nm posixshmcontrol .Nd Control POSIX shared memory segments .Sh SYNOPSIS .Nm .Ar create .Op Fl m Ar mode .Op Pa path \&... .Nm .Ar rm .Op Pa path \&... .Nm .Ar ls .Op Fl h .Op Fl n .Nm .Ar dump .Op Pa path \&... .Nm .Ar stat .Op Fl h .Op Fl n .Op Pa path \&... .Nm .Ar truncate .Op Fl s Ar length .Op Pa path \&... .Sh DESCRIPTION The .Nm command manipulates the named POSIX shared memory segments. It allows inspecting existing segments, dumping their metadata or contents, and unlinking them. .Pp Unlinking removes the name from the system and, when the last process unmaps the segment and closes file descriptor pointing to the segment, frees underlying memory. .Pp The number of hard links as displayed by the .Ic stat subcommand, is equal to the number of references to the underlying VM object. It is almost always equal to the number of mappings +1, except for transient references. .Pp The following subcommands are provided: .Bl -tag -width truncate .It Ic create Create segments with the specified paths, if not exist. The .Ar mode optional numerical argument specifies initial access mode. .It Ic rm Unlink the paths specified. .It Ic ls List all linked named shared memory segments visible to the caller. For each segment, the user and group owner, size, and path are displayed. .It Ic dump Output raw bytes values from the segment to standard output. .It Ic stat Print metadata for the specified path, in the format similar to the .Xr stat 1 utility. .It Ic truncate Change the length of the segments. Argument to the .Fl s option specifies new length. The human-friendly 'k', 'm', 'g' suffixes can be used, see .Xr expand_number 3 . If the option is not specified, assumed length is zero. .El .Pp For some commands, the following options may be provided: .Bl -tag -width XXX .It Fl h If specified, requests human-readable display of size, see .Xr humanize_number 3 . .It Fl n Prevent translation of owner and group into symbolic names using name-switch services, instead the raw numeric values are printed. .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES .Bl -bullet .It To show content of the shared memory segment with the path .Pa /1 , use the command -.Dl "posixshmcontrol dump /q | hexdump -C" +.Dl "posixshmcontrol dump /1 | hexdump -C" .It To create a segment with the path .Pa /2 and then enlarge it to 1M, use the sequence of commands .Dl "posixshmcontrol create /2" .Dl "posixshmcontrol truncate -s 1m /2" .El .Sh SEE ALSO .Xr hexdump 1 , .Xr stat 1 , .Xr ftruncate 2 , .Xr read 2 , .Xr shm_open 2 , .Xr shm_unlink 2 , .Xr stat 2 , .Xr expand_number 3 , .Xr humanize_number 3 , .Xr sysctl 3 .Sh HISTORY The .Nm command appeared in .Fx 12.1 . .Sh AUTHORS The .Nm command and this manual page were written by .An Konstantin Belousov Aq Mt kib@freebsd.org under sponsorship from The .Fx Foundation. Index: stable/12/usr.bin/posixshmcontrol/posixshmcontrol.c =================================================================== --- stable/12/usr.bin/posixshmcontrol/posixshmcontrol.c (revision 365993) +++ stable/12/usr.bin/posixshmcontrol/posixshmcontrol.c (revision 365994) @@ -1,481 +1,506 @@ /*- * Copyright (c) 2019 The FreeBSD Foundation * * This software was developed by Konstantin Belousov * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void usage(void) { fprintf(stderr, "Usage:\n" "posixshmcontrol create [-m ] ...\n" "posixshmcontrol rm ...\n" "posixshmcontrol ls [-h] [-n]\n" "posixshmcontrol dump ...\n" "posixshmcontrol stat [-h] [-n] ...\n" "posixshmcontrol truncate [-s ] ...\n"); } static int create_one_shm(const char *path, long mode) { int fd; fd = shm_open(path, O_RDWR | O_CREAT, mode); if (fd == -1) { warn("create %s", path); return (1); } close(fd); return (0); } static int create_shm(int argc, char **argv) { char *end; long mode; int c, i, ret, ret1; mode = 0600; while ((c = getopt(argc, argv, "m:")) != -1) { switch (c) { case 'm': errno = 0; mode = strtol(optarg, &end, 0); if (mode == 0 && errno != 0) err(1, "mode:"); if (*end != '\0') errx(1, "non-integer mode"); break; case '?': default: usage(); return (2); } } - argc -= optind; argv += optind; + + if (argc == 0) { + usage(); + return (2); + } + ret = 0; for (i = 0; i < argc; i++) { ret1 = create_one_shm(argv[i], mode); if (ret1 != 0 && ret == 0) ret = ret1; } return (ret); } static int delete_one_shm(const char *path) { int error, ret; error = shm_unlink(path); if (error != 0) { warn("unlink of %s failed", path); ret = 1; } else { ret = 0; } return (ret); } static int delete_shm(int argc, char **argv) { int i, ret, ret1; + if (argc == 1) { + usage(); + return (2); + } + ret = 0; for (i = 1; i < argc; i++) { ret1 = delete_one_shm(argv[i]); if (ret1 != 0 && ret == 0) ret = ret1; } return (ret); } static const char listmib[] = "kern.ipc.posix_shm_list"; static void shm_decode_mode(mode_t m, char *str) { int i; i = 0; str[i++] = (m & S_IRUSR) != 0 ? 'r' : '-'; str[i++] = (m & S_IWUSR) != 0 ? 'w' : '-'; str[i++] = (m & S_IXUSR) != 0 ? 'x' : '-'; str[i++] = (m & S_IRGRP) != 0 ? 'r' : '-'; str[i++] = (m & S_IWGRP) != 0 ? 'w' : '-'; str[i++] = (m & S_IXGRP) != 0 ? 'x' : '-'; str[i++] = (m & S_IROTH) != 0 ? 'r' : '-'; str[i++] = (m & S_IWOTH) != 0 ? 'w' : '-'; str[i++] = (m & S_IXOTH) != 0 ? 'x' : '-'; str[i] = '\0'; } static int list_shm(int argc, char **argv) { char *buf, *bp, sizebuf[8], str[10]; const struct kinfo_file *kif; struct stat st; int c, error, fd, mib[3], ret; size_t len, miblen; bool hsize, uname; hsize = false; uname = true; while ((c = getopt(argc, argv, "hn")) != -1) { switch (c) { case 'h': hsize = true; break; case 'n': uname = false; break; default: usage(); return (2); } } if (argc != optind) { usage(); return (2); } miblen = nitems(mib); error = sysctlnametomib(listmib, mib, &miblen); if (error == -1) { warn("cannot translate %s", listmib); return (1); } len = 0; error = sysctl(mib, miblen, NULL, &len, NULL, 0); if (error == -1) { warn("cannot get %s length", listmib); return (1); } len = len * 4 / 3; buf = malloc(len); if (buf == NULL) { warn("malloc"); return (1); } error = sysctl(mib, miblen, buf, &len, NULL, 0); if (error != 0) { warn("reading %s", listmib); ret = 1; goto out; } ret = 0; printf("MODE \tOWNER\tGROUP\tSIZE\tPATH\n"); for (bp = buf; bp < buf + len; bp += kif->kf_structsize) { kif = (const struct kinfo_file *)(void *)bp; if (kif->kf_structsize == 0) break; fd = shm_open(kif->kf_path, O_RDONLY, 0); if (fd == -1) { warn("open %s", kif->kf_path); ret = 1; continue; } error = fstat(fd, &st); close(fd); if (error != 0) { warn("stat %s", kif->kf_path); ret = 1; continue; } shm_decode_mode(kif->kf_un.kf_file.kf_file_mode, str); printf("%s\t", str); if (uname) { printf("%s\t%s\t", user_from_uid(st.st_uid, 0), group_from_gid(st.st_gid, 0)); } else { printf("%d\t%d\t", st.st_uid, st.st_gid); } if (hsize) { humanize_number(sizebuf, sizeof(sizebuf), kif->kf_un.kf_file.kf_file_size, "", HN_AUTOSCALE, HN_NOSPACE); printf("%s\t", sizebuf); } else { printf("%jd\t", (uintmax_t)kif->kf_un.kf_file.kf_file_size); } printf("%s\n", kif->kf_path); } out: free(buf); return (ret); } static int read_one_shm(const char *path) { char buf[4096]; ssize_t size, se; int fd, ret; ret = 1; fd = shm_open(path, O_RDONLY, 0); if (fd == -1) { warn("open %s", path); goto out; } for (;;) { size = read(fd, buf, sizeof(buf)); if (size > 0) { se = fwrite(buf, 1, size, stdout); if (se < size) { warnx("short write to stdout"); goto out; } } if (size == (ssize_t)sizeof(buf)) continue; if (size >= 0 && size < (ssize_t)sizeof(buf)) { ret = 0; goto out; } warn("read from %s", path); goto out; } out: close(fd); return (ret); } static int read_shm(int argc, char **argv) { int i, ret, ret1; + if (argc == 1) { + usage(); + return (2); + } + ret = 0; for (i = 1; i < argc; i++) { ret1 = read_one_shm(argv[i]); if (ret1 != 0 && ret == 0) ret = ret1; } return (ret); } static int stat_one_shm(const char *path, bool hsize, bool uname) { char sizebuf[8]; struct stat st; int error, fd, ret; fd = shm_open(path, O_RDONLY, 0); if (fd == -1) { warn("open %s", path); return (1); } ret = 0; error = fstat(fd, &st); if (error == -1) { warn("stat %s", path); ret = 1; } else { printf("path\t%s\n", path); printf("inode\t%jd\n", (uintmax_t)st.st_ino); printf("mode\t%#o\n", st.st_mode); printf("nlink\t%jd\n", (uintmax_t)st.st_nlink); if (uname) { printf("owner\t%s\n", user_from_uid(st.st_uid, 0)); printf("group\t%s\n", group_from_gid(st.st_gid, 0)); } else { printf("uid\t%d\n", st.st_uid); printf("gid\t%d\n", st.st_gid); } if (hsize) { humanize_number(sizebuf, sizeof(sizebuf), st.st_size, "", HN_AUTOSCALE, HN_NOSPACE); printf("size\t%s\n", sizebuf); } else { printf("size\t%jd\n", (uintmax_t)st.st_size); } printf("atime\t%ld.%09ld\n", (long)st.st_atime, (long)st.st_atim.tv_nsec); printf("mtime\t%ld.%09ld\n", (long)st.st_mtime, (long)st.st_mtim.tv_nsec); printf("ctime\t%ld.%09ld\n", (long)st.st_ctime, (long)st.st_ctim.tv_nsec); printf("birth\t%ld.%09ld\n", (long)st.st_birthtim.tv_sec, (long)st.st_birthtim.tv_nsec); } close(fd); return (ret); } static int stat_shm(int argc, char **argv) { int c, i, ret, ret1; bool hsize, uname; hsize = false; uname = true; while ((c = getopt(argc, argv, "hn")) != -1) { switch (c) { case 'h': hsize = true; break; case 'n': uname = false; break; default: usage(); return (2); } } argc -= optind; argv += optind; + if (argc == 0) { + usage(); + return (2); + } + ret = 0; for (i = 0; i < argc; i++) { ret1 = stat_one_shm(argv[i], hsize, uname); if (ret1 != 0 && ret == 0) ret = ret1; } return (ret); } static int truncate_one_shm(const char *path, uint64_t newsize) { int error, fd, ret; ret = 0; fd = shm_open(path, O_RDWR, 0); if (fd == -1) { warn("open %s", path); return (1); } error = ftruncate(fd, newsize); if (error == -1) { warn("truncate %s", path); ret = 1; } close(fd); return (ret); } static int truncate_shm(int argc, char **argv) { uint64_t newsize; int c, i, ret, ret1; newsize = 0; while ((c = getopt(argc, argv, "s:")) != -1) { switch (c) { case 's': if (expand_number(optarg, &newsize) == -1) - err(1, "size:"); + err(1, "size"); break; case '?': default: return (2); } } - argc -= optind; argv += optind; + + if (argc == 0) { + usage(); + return (2); + } + ret = 0; for (i = 0; i < argc; i++) { ret1 = truncate_one_shm(argv[i], newsize); if (ret1 != 0 && ret == 0) ret = ret1; } return (ret); } struct opmode { const char *cmd; int (*impl)(int argc, char **argv); }; static const struct opmode opmodes[] = { { .cmd = "create", .impl = create_shm}, { .cmd = "rm", .impl = delete_shm, }, { .cmd = "list", .impl = list_shm }, { .cmd = "ls", .impl = list_shm }, { .cmd = "dump", .impl = read_shm, }, { .cmd = "stat", .impl = stat_shm, }, { .cmd = "truncate", .impl = truncate_shm, }, }; int main(int argc, char *argv[]) { const struct opmode *opmode; int i, ret; ret = 0; opmode = NULL; if (argc < 2) { usage(); exit(2); } for (i = 0; i < (int)nitems(opmodes); i++) { if (strcmp(argv[1], opmodes[i].cmd) == 0) { opmode = &opmodes[i]; break; } } if (opmode == NULL) { usage(); exit(2); } ret = opmode->impl(argc - 1, argv + 1); exit(ret); } Index: stable/12 =================================================================== --- stable/12 (revision 365993) +++ stable/12 (revision 365994) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r365749