Author: kib
Date: Thu May 23 14:33:01 2019
New Revision: 348167
URL: https://svnweb.freebsd.org/changeset/base/348167

Log:
  Add posixshmcontrol(1), an utility to manipulate posix shared memory segments.
  
  See usage for the command line structure.  Man page will come shortly.
  
  Reviewed by:  jilles, tmunro
  Sponsored by: The FreeBSD Foundation
  MFC after:    1 week
  Differential revision:        https://reviews.freebsd.org/D20258

Added:
  head/usr.bin/posixshmcontrol/
  head/usr.bin/posixshmcontrol/Makefile   (contents, props changed)
  head/usr.bin/posixshmcontrol/posixshmcontrol.c   (contents, props changed)
Modified:
  head/usr.bin/Makefile

Modified: head/usr.bin/Makefile
==============================================================================
--- head/usr.bin/Makefile       Thu May 23 14:21:23 2019        (r348166)
+++ head/usr.bin/Makefile       Thu May 23 14:33:01 2019        (r348167)
@@ -114,6 +114,7 @@ SUBDIR=     alias \
        patch \
        pathchk \
        perror \
+       posixshmcontrol \
        pr \
        printenv \
        printf \

Added: head/usr.bin/posixshmcontrol/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/posixshmcontrol/Makefile       Thu May 23 14:33:01 2019        
(r348167)
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+PROG=   posixshmcontrol
+LIBADD=        util
+WARNS?=        6
+MAN=
+
+.include <bsd.prog.mk>

Added: head/usr.bin/posixshmcontrol/posixshmcontrol.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/usr.bin/posixshmcontrol/posixshmcontrol.c      Thu May 23 14:33:01 
2019        (r348167)
@@ -0,0 +1,480 @@
+/*-
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov <k...@freebsd.org>
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <err.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <libutil.h>
+#include <pwd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void
+usage(void)
+{
+
+       fprintf(stderr, "Usage:\n"
+           "posixshmcontrol create [-m <mode>] <path> ...\n"
+           "posixshmcontrol rm <path> ...\n"
+           "posixshmcontrol ls [-h] [-n]\n"
+           "posixshmcontrol dump <path> ...\n"
+           "posixshmcontrol stat [-h] [-n] <path> ...\n"
+           "posixshmcontrol truncate [-s <newlen>] <path> ...\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;
+       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;
+
+       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], c;
+       const struct kinfo_file *kif;
+       struct stat st;
+       int 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;
+
+       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;
+
+       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:");
+                       break;
+               case '?':
+               default:
+                       return (2);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       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 = "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);
+}
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to