Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 May 2019 14:33:02 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r348167 - in head/usr.bin: . posixshmcontrol
Message-ID:  <201905231433.x4NEX2QF042023@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <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);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905231433.x4NEX2QF042023>