summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2019-05-23 14:33:01 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2019-05-23 14:33:01 +0000
commit5f4592e46f8e46cb9a25ba1e56fa2dea8f286ed7 (patch)
tree5f500e014154498b86547e7715a8a0f7d36191a1 /usr.bin
parentecb53c096d011eb146fe8daccfce9b757be1fca9 (diff)
downloadsrc-test2-5f4592e46f8e46cb9a25ba1e56fa2dea8f286ed7.tar.gz
src-test2-5f4592e46f8e46cb9a25ba1e56fa2dea8f286ed7.zip
Notes
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/Makefile1
-rw-r--r--usr.bin/posixshmcontrol/Makefile8
-rw-r--r--usr.bin/posixshmcontrol/posixshmcontrol.c480
3 files changed, 489 insertions, 0 deletions
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index c9620c7b87a1..75ea3b7426a4 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -114,6 +114,7 @@ SUBDIR= alias \
patch \
pathchk \
perror \
+ posixshmcontrol \
pr \
printenv \
printf \
diff --git a/usr.bin/posixshmcontrol/Makefile b/usr.bin/posixshmcontrol/Makefile
new file mode 100644
index 000000000000..06d4caeabe59
--- /dev/null
+++ b/usr.bin/posixshmcontrol/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+PROG= posixshmcontrol
+LIBADD= util
+WARNS?= 6
+MAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/posixshmcontrol/posixshmcontrol.c b/usr.bin/posixshmcontrol/posixshmcontrol.c
new file mode 100644
index 000000000000..9d3848f87822
--- /dev/null
+++ b/usr.bin/posixshmcontrol/posixshmcontrol.c
@@ -0,0 +1,480 @@
+/*-
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov <kib@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);
+}