]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/posixshmcontrol/posixshmcontrol.c
contrib/tzdata: import tzdata 2022b and 2022c
[FreeBSD/FreeBSD.git] / usr.bin / posixshmcontrol / posixshmcontrol.c
1 /*-
2  * Copyright (c) 2019 The FreeBSD Foundation
3  *
4  * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
5  * under sponsorship from the FreeBSD Foundation.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35 #include <sys/sysctl.h>
36 #include <sys/user.h>
37 #include <err.h>
38 #include <fcntl.h>
39 #include <grp.h>
40 #include <libutil.h>
41 #include <pwd.h>
42 #include <stdbool.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 static void
49 usage(void)
50 {
51
52         fprintf(stderr, "Usage:\n"
53             "posixshmcontrol create [-m <mode>] <path> ...\n"
54             "posixshmcontrol rm <path> ...\n"
55             "posixshmcontrol ls [-h] [-n]\n"
56             "posixshmcontrol dump <path> ...\n"
57             "posixshmcontrol stat [-h] [-n] <path> ...\n"
58             "posixshmcontrol truncate [-s <newlen>] <path> ...\n");
59 }
60
61 static int
62 create_one_shm(const char *path, long mode)
63 {
64         int fd;
65
66         fd = shm_open(path, O_RDWR | O_CREAT, mode);
67         if (fd == -1) {
68                 warn("create %s", path);
69                 return (1);
70         }
71         close(fd);
72         return (0);
73 }
74
75 static int
76 create_shm(int argc, char **argv)
77 {
78         char *end;
79         long mode;
80         int c, i, ret, ret1;
81
82         mode = 0600;
83         while ((c = getopt(argc, argv, "m:")) != -1) {
84                 switch (c) {
85                 case 'm':
86                         errno = 0;
87                         mode = strtol(optarg, &end, 0);
88                         if (mode == 0 && errno != 0)
89                                 err(1, "mode:");
90                         if (*end != '\0')
91                                 errx(1, "non-integer mode");
92                         break;
93                 case '?':
94                 default:
95                         usage();
96                         return (2);
97                 }
98         }
99         argc -= optind;
100         argv += optind;
101
102         if (argc == 0) {
103                 usage();
104                 return (2);
105         }
106
107         ret = 0;
108         for (i = 0; i < argc; i++) {
109                 ret1 = create_one_shm(argv[i], mode);
110                 if (ret1 != 0 && ret == 0)
111                         ret = ret1;
112         }
113         return (ret);
114 }
115
116 static int
117 delete_one_shm(const char *path)
118 {
119         int error, ret;
120
121         error = shm_unlink(path);
122         if (error != 0) {
123                 warn("unlink of %s failed", path);
124                 ret = 1;
125         } else {
126                 ret = 0;
127         }
128         return (ret);
129 }
130
131 static int
132 delete_shm(int argc, char **argv)
133 {
134         int i, ret, ret1;
135
136         if (argc == 1) {
137                 usage();
138                 return (2);
139         }
140
141         ret = 0;
142         for (i = 1; i < argc; i++) {
143                 ret1 = delete_one_shm(argv[i]);
144                 if (ret1 != 0 && ret == 0)
145                         ret = ret1;
146         }
147         return (ret);
148 }
149
150 static const char listmib[] = "kern.ipc.posix_shm_list";
151
152 static void
153 shm_decode_mode(mode_t m, char *str)
154 {
155         int i;
156
157         i = 0;
158         str[i++] = (m & S_IRUSR) != 0 ? 'r' : '-';
159         str[i++] = (m & S_IWUSR) != 0 ? 'w' : '-';
160         str[i++] = (m & S_IXUSR) != 0 ? 'x' : '-';
161         str[i++] = (m & S_IRGRP) != 0 ? 'r' : '-';
162         str[i++] = (m & S_IWGRP) != 0 ? 'w' : '-';
163         str[i++] = (m & S_IXGRP) != 0 ? 'x' : '-';
164         str[i++] = (m & S_IROTH) != 0 ? 'r' : '-';
165         str[i++] = (m & S_IWOTH) != 0 ? 'w' : '-';
166         str[i++] = (m & S_IXOTH) != 0 ? 'x' : '-';
167         str[i] = '\0';
168 }
169
170 static int
171 list_shm(int argc, char **argv)
172 {
173         char *buf, *bp, sizebuf[8], str[10];
174         const struct kinfo_file *kif;
175         struct stat st;
176         int c, error, fd, mib[3], ret;
177         size_t len, miblen;
178         bool hsize, uname;
179
180         hsize = false;
181         uname = true;
182
183         while ((c = getopt(argc, argv, "hn")) != -1) {
184                 switch (c) {
185                 case 'h':
186                         hsize = true;
187                         break;
188                 case 'n':
189                         uname = false;
190                         break;
191                 default:
192                         usage();
193                         return (2);
194                 }
195         }
196         if (argc != optind) {
197                 usage();
198                 return (2);
199         }
200
201         miblen = nitems(mib);
202         error = sysctlnametomib(listmib, mib, &miblen);
203         if (error == -1) {
204                 warn("cannot translate %s", listmib);
205                 return (1);
206         }
207         len = 0;
208         error = sysctl(mib, miblen, NULL, &len, NULL, 0);
209         if (error == -1) {
210                 warn("cannot get %s length", listmib);
211                 return (1);
212         }
213         len = len * 4 / 3;
214         buf = malloc(len);
215         if (buf == NULL) {
216                 warn("malloc");
217                 return (1);
218         }
219         error = sysctl(mib, miblen, buf, &len, NULL, 0);
220         if (error != 0) {
221                 warn("reading %s", listmib);
222                 ret = 1;
223                 goto out;
224         }
225         ret = 0;
226         printf("MODE    \tOWNER\tGROUP\tSIZE\tPATH\n");
227         for (bp = buf; bp < buf + len; bp += kif->kf_structsize) {
228                 kif = (const struct kinfo_file *)(void *)bp;
229                 if (kif->kf_structsize == 0)
230                         break;
231                 fd = shm_open(kif->kf_path, O_RDONLY, 0);
232                 if (fd == -1) {
233                         warn("open %s", kif->kf_path);
234                         ret = 1;
235                         continue;
236                 }
237                 error = fstat(fd, &st);
238                 close(fd);
239                 if (error != 0) {
240                         warn("stat %s", kif->kf_path);
241                         ret = 1;
242                         continue;
243                 }
244                 shm_decode_mode(kif->kf_un.kf_file.kf_file_mode, str);
245                 printf("%s\t", str);
246                 if (uname) {
247                         printf("%s\t%s\t", user_from_uid(st.st_uid, 0),
248                             group_from_gid(st.st_gid, 0));
249                 } else {
250                         printf("%d\t%d\t", st.st_uid, st.st_gid);
251                 }
252                 if (hsize) {
253                         humanize_number(sizebuf, sizeof(sizebuf),
254                             kif->kf_un.kf_file.kf_file_size, "", HN_AUTOSCALE,
255                             HN_NOSPACE);
256                         printf("%s\t", sizebuf);
257                 } else {
258                         printf("%jd\t",
259                             (uintmax_t)kif->kf_un.kf_file.kf_file_size);
260                 }
261                 printf("%s\n", kif->kf_path);
262         }
263 out:
264         free(buf);
265         return (ret);
266 }
267
268 static int
269 read_one_shm(const char *path)
270 {
271         char buf[4096];
272         ssize_t size, se;
273         int fd, ret;
274
275         ret = 1;
276         fd = shm_open(path, O_RDONLY, 0);
277         if (fd == -1) {
278                 warn("open %s", path);
279                 goto out;
280         }
281         for (;;) {
282                 size = read(fd, buf, sizeof(buf));
283                 if (size > 0) {
284                         se = fwrite(buf, 1, size, stdout);
285                         if (se < size) {
286                                 warnx("short write to stdout");
287                                 goto out;
288                         }
289                 }
290                 if (size == (ssize_t)sizeof(buf))
291                         continue;
292                 if (size >= 0 && size < (ssize_t)sizeof(buf)) {
293                         ret = 0;
294                         goto out;
295                 }
296                 warn("read from %s", path);
297                 goto out;
298         }
299 out:
300         close(fd);
301         return (ret);
302 }
303
304 static int
305 read_shm(int argc, char **argv)
306 {
307         int i, ret, ret1;
308
309         if (argc == 1) {
310                 usage();
311                 return (2);
312         }
313
314         ret = 0;
315         for (i = 1; i < argc; i++) {
316                 ret1 = read_one_shm(argv[i]);
317                 if (ret1 != 0 && ret == 0)
318                         ret = ret1;
319         }
320         return (ret);
321 }
322
323 static int
324 stat_one_shm(const char *path, bool hsize, bool uname)
325 {
326         char sizebuf[8];
327         struct stat st;
328         int error, fd, ret;
329
330         fd = shm_open(path, O_RDONLY, 0);
331         if (fd == -1) {
332                 warn("open %s", path);
333                 return (1);
334         }
335         ret = 0;
336         error = fstat(fd, &st);
337         if (error == -1) {
338                 warn("stat %s", path);
339                 ret = 1;
340         } else {
341                 printf("path\t%s\n", path);
342                 printf("inode\t%jd\n", (uintmax_t)st.st_ino);
343                 printf("mode\t%#o\n", st.st_mode);
344                 printf("nlink\t%jd\n", (uintmax_t)st.st_nlink);
345                 if (uname) {
346                         printf("owner\t%s\n", user_from_uid(st.st_uid, 0));
347                         printf("group\t%s\n", group_from_gid(st.st_gid, 0));
348                 } else {
349                         printf("uid\t%d\n", st.st_uid);
350                         printf("gid\t%d\n", st.st_gid);
351                 }
352                 if (hsize) {
353                         humanize_number(sizebuf, sizeof(sizebuf),
354                             st.st_size, "", HN_AUTOSCALE, HN_NOSPACE);
355                         printf("size\t%s\n", sizebuf);
356                 } else {
357                         printf("size\t%jd\n", (uintmax_t)st.st_size);
358                 }
359                 printf("atime\t%ld.%09ld\n", (long)st.st_atime,
360                     (long)st.st_atim.tv_nsec);
361                 printf("mtime\t%ld.%09ld\n", (long)st.st_mtime,
362                     (long)st.st_mtim.tv_nsec);
363                 printf("ctime\t%ld.%09ld\n", (long)st.st_ctime,
364                     (long)st.st_ctim.tv_nsec);
365                 printf("birth\t%ld.%09ld\n", (long)st.st_birthtim.tv_sec,
366                     (long)st.st_birthtim.tv_nsec);
367         }
368         close(fd);
369         return (ret);
370 }
371
372 static int
373 stat_shm(int argc, char **argv)
374 {
375         int c, i, ret, ret1;
376         bool hsize, uname;
377
378         hsize = false;
379         uname = true;
380
381         while ((c = getopt(argc, argv, "hn")) != -1) {
382                 switch (c) {
383                 case 'h':
384                         hsize = true;
385                         break;
386                 case 'n':
387                         uname = false;
388                         break;
389                 default:
390                         usage();
391                         return (2);
392                 }
393         }
394         argc -= optind;
395         argv += optind;
396
397         if (argc == 0) {
398                 usage();
399                 return (2);
400         }
401
402         ret = 0;
403         for (i = 0; i < argc; i++) {
404                 ret1 = stat_one_shm(argv[i], hsize, uname);
405                 if (ret1 != 0 && ret == 0)
406                         ret = ret1;
407         }
408         return (ret);
409 }
410
411 static int
412 truncate_one_shm(const char *path, uint64_t newsize)
413 {
414         int error, fd, ret;
415
416         ret = 0;
417         fd = shm_open(path, O_RDWR, 0);
418         if (fd == -1) {
419                 warn("open %s", path);
420                 return (1);
421         }
422         error = ftruncate(fd, newsize);
423         if (error == -1) {
424                 warn("truncate %s", path);
425                 ret = 1;
426         }
427         close(fd);
428         return (ret);
429 }
430
431 static int
432 truncate_shm(int argc, char **argv)
433 {
434         uint64_t newsize;
435         int c, i, ret, ret1;
436
437         newsize = 0;
438         while ((c = getopt(argc, argv, "s:")) != -1) {
439                 switch (c) {
440                 case 's':
441                         if (expand_number(optarg, &newsize) == -1)
442                                 err(1, "size");
443                         break;
444                 case '?':
445                 default:
446                         return (2);
447                 }
448         }
449         argc -= optind;
450         argv += optind;
451
452         if (argc == 0) {
453                 usage();
454                 return (2);
455         }
456
457         ret = 0;
458         for (i = 0; i < argc; i++) {
459                 ret1 = truncate_one_shm(argv[i], newsize);
460                 if (ret1 != 0 && ret == 0)
461                         ret = ret1;
462         }
463         return (ret);
464 }
465
466 struct opmode {
467         const char *cmd;
468         int (*impl)(int argc, char **argv);
469 };
470
471 static const struct opmode opmodes[] = {
472         { .cmd = "create",      .impl = create_shm},
473         { .cmd = "rm",          .impl = delete_shm, },
474         { .cmd = "list",        .impl = list_shm },
475         { .cmd = "ls",          .impl = list_shm },
476         { .cmd = "dump",        .impl = read_shm, },
477         { .cmd = "stat",        .impl = stat_shm, },
478         { .cmd = "truncate",    .impl = truncate_shm, },
479 };
480
481 int
482 main(int argc, char *argv[])
483 {
484         const struct opmode *opmode;
485         int i, ret;
486
487         ret = 0;
488         opmode = NULL;
489
490         if (argc < 2) {
491                 usage();
492                 exit(2);
493         }
494         for (i = 0; i < (int)nitems(opmodes); i++) {
495                 if (strcmp(argv[1], opmodes[i].cmd) == 0) {
496                         opmode = &opmodes[i];
497                         break;
498                 }
499         }
500         if (opmode == NULL) {
501                 usage();
502                 exit(2);
503         }
504         ret = opmode->impl(argc - 1, argv + 1);
505         exit(ret);
506 }