1*49a6e16fSderaadt /* $OpenBSD: fstest.c,v 1.7 2021/12/13 16:56:49 deraadt Exp $ */
2ec7c50bfSpedro
3ec7c50bfSpedro /*
4ec7c50bfSpedro * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5ec7c50bfSpedro * All rights reserved.
6ec7c50bfSpedro *
7ec7c50bfSpedro * Redistribution and use in source and binary forms, with or without
8ec7c50bfSpedro * modification, are permitted provided that the following conditions
9ec7c50bfSpedro * are met:
10ec7c50bfSpedro * 1. Redistributions of source code must retain the above copyright
11ec7c50bfSpedro * notice, this list of conditions and the following disclaimer.
12ec7c50bfSpedro * 2. Redistributions in binary form must reproduce the above copyright
13ec7c50bfSpedro * notice, this list of conditions and the following disclaimer in the
14ec7c50bfSpedro * documentation and/or other materials provided with the distribution.
15ec7c50bfSpedro *
16ec7c50bfSpedro * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17ec7c50bfSpedro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ec7c50bfSpedro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ec7c50bfSpedro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20ec7c50bfSpedro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ec7c50bfSpedro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ec7c50bfSpedro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ec7c50bfSpedro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ec7c50bfSpedro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ec7c50bfSpedro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ec7c50bfSpedro * SUCH DAMAGE.
27ec7c50bfSpedro *
28ec7c50bfSpedro * $FreeBSD: src/tools/regression/fstest/fstest.c,v 1.1 2007/01/17 01:42:07 pjd Exp $
29ec7c50bfSpedro */
30ec7c50bfSpedro
31*49a6e16fSderaadt #include <sys/types.h>
32ec7c50bfSpedro #include <sys/stat.h>
3337dd51d1Sthib #include <sys/sysctl.h>
3437dd51d1Sthib
35ec7c50bfSpedro #include <stdio.h>
36ec7c50bfSpedro #include <stdlib.h>
37ec7c50bfSpedro #include <unistd.h>
38ec7c50bfSpedro #include <fcntl.h>
39ec7c50bfSpedro #include <grp.h>
40ec7c50bfSpedro #include <string.h>
41ec7c50bfSpedro #include <ctype.h>
42ec7c50bfSpedro #include <errno.h>
43ec7c50bfSpedro #include <assert.h>
44ec7c50bfSpedro
45ec7c50bfSpedro enum action {
46ec7c50bfSpedro ACTION_OPEN,
47ec7c50bfSpedro ACTION_CREATE,
48ec7c50bfSpedro ACTION_UNLINK,
49ec7c50bfSpedro ACTION_MKDIR,
50ec7c50bfSpedro ACTION_RMDIR,
51ec7c50bfSpedro ACTION_LINK,
52ec7c50bfSpedro ACTION_SYMLINK,
53ec7c50bfSpedro ACTION_RENAME,
54ec7c50bfSpedro ACTION_MKFIFO,
55ec7c50bfSpedro ACTION_CHMOD,
56ec7c50bfSpedro ACTION_CHOWN,
57ec7c50bfSpedro ACTION_LCHOWN,
58ec7c50bfSpedro ACTION_CHFLAGS,
590350e6d8Sbluhm ACTION_LCHFLAGS,
60ec7c50bfSpedro ACTION_TRUNCATE,
61ec7c50bfSpedro ACTION_STAT,
62ec7c50bfSpedro ACTION_LSTAT,
63ec7c50bfSpedro };
64ec7c50bfSpedro
65ec7c50bfSpedro #define TYPE_NONE 0x0000
66ec7c50bfSpedro #define TYPE_STRING 0x0001
67ec7c50bfSpedro #define TYPE_NUMBER 0x0002
68ec7c50bfSpedro #define TYPE_OPTIONAL 0x0100
69ec7c50bfSpedro #define MAX_ARGS 8
70ec7c50bfSpedro
71ec7c50bfSpedro struct syscall_desc {
72ec7c50bfSpedro char *sd_name;
73ec7c50bfSpedro enum action sd_action;
74ec7c50bfSpedro int sd_args[MAX_ARGS];
75ec7c50bfSpedro };
76ec7c50bfSpedro
77ec7c50bfSpedro static struct syscall_desc syscalls[] = {
78ec7c50bfSpedro { "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING,
79ec7c50bfSpedro TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
80ec7c50bfSpedro { "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
81ec7c50bfSpedro { "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } },
82ec7c50bfSpedro { "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
83ec7c50bfSpedro { "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } },
84ec7c50bfSpedro { "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
85ec7c50bfSpedro { "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
86ec7c50bfSpedro { "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
87ec7c50bfSpedro { "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
88ec7c50bfSpedro { "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
89ec7c50bfSpedro { "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER,
90ec7c50bfSpedro TYPE_NUMBER, TYPE_NONE } },
91ec7c50bfSpedro { "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER,
92ec7c50bfSpedro TYPE_NUMBER, TYPE_NONE } },
93ec7c50bfSpedro { "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
940350e6d8Sbluhm { "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING,
950350e6d8Sbluhm TYPE_NONE } },
96ec7c50bfSpedro { "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER,
97ec7c50bfSpedro TYPE_NONE } },
98ec7c50bfSpedro { "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
99ec7c50bfSpedro { "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
100ec7c50bfSpedro { NULL, -1, { TYPE_NONE } }
101ec7c50bfSpedro };
102ec7c50bfSpedro
103ec7c50bfSpedro struct flag {
104ec7c50bfSpedro long long f_flag;
105ec7c50bfSpedro char *f_str;
106ec7c50bfSpedro };
107ec7c50bfSpedro
108ec7c50bfSpedro static struct flag open_flags[] = {
109ec7c50bfSpedro { O_RDONLY, "O_RDONLY" },
110ec7c50bfSpedro { O_WRONLY, "O_WRONLY" },
111ec7c50bfSpedro { O_RDWR, "O_RDWR" },
112ec7c50bfSpedro { O_NONBLOCK, "O_NONBLOCK" },
113ec7c50bfSpedro { O_APPEND, "O_APPEND" },
114ec7c50bfSpedro { O_CREAT, "O_CREAT" },
115ec7c50bfSpedro { O_TRUNC, "O_TRUNC" },
116ec7c50bfSpedro { O_EXCL, "O_EXCL" },
117ec7c50bfSpedro { O_SHLOCK, "O_SHLOCK" },
118ec7c50bfSpedro { O_EXLOCK, "O_EXLOCK" },
119ec7c50bfSpedro { O_FSYNC, "O_FSYNC" },
120ec7c50bfSpedro { O_SYNC, "O_SYNC" },
121ec7c50bfSpedro { O_NOFOLLOW, "O_NOFOLLOW" },
122ec7c50bfSpedro { O_NOCTTY, "O_NOCTTY" },
123ec7c50bfSpedro { 0, NULL }
124ec7c50bfSpedro };
125ec7c50bfSpedro
126ec7c50bfSpedro static struct flag chflags_flags[] = {
127ec7c50bfSpedro { UF_NODUMP, "UF_NODUMP" },
128ec7c50bfSpedro { UF_IMMUTABLE, "UF_IMMUTABLE" },
129ec7c50bfSpedro { UF_APPEND, "UF_APPEND" },
130ec7c50bfSpedro { UF_OPAQUE, "UF_OPAQUE" },
131ec7c50bfSpedro { SF_ARCHIVED, "SF_ARCHIVED" },
132ec7c50bfSpedro { SF_IMMUTABLE, "SF_IMMUTABLE" },
133ec7c50bfSpedro { SF_APPEND, "SF_APPEND" },
134ec7c50bfSpedro { 0, NULL }
135ec7c50bfSpedro };
136ec7c50bfSpedro
137ec7c50bfSpedro static const char *err2str(int error);
13837dd51d1Sthib int use_appimm; /* use the SF_APPEND and SF_IMMUTABLE chflags */
139ec7c50bfSpedro
140ec7c50bfSpedro __dead static void
usage(void)141ec7c50bfSpedro usage(void)
142ec7c50bfSpedro {
143ec7c50bfSpedro fprintf(stderr, "usage: fstest [-u uid] [-g gid1[,gid2[...]]] syscall "
144ec7c50bfSpedro "args ...\n");
145ec7c50bfSpedro exit(1);
146ec7c50bfSpedro }
147ec7c50bfSpedro
148ec7c50bfSpedro static long long
str2flags(struct flag * tflags,char * sflags)149ec7c50bfSpedro str2flags(struct flag *tflags, char *sflags)
150ec7c50bfSpedro {
151ec7c50bfSpedro long long flags = 0;
152ec7c50bfSpedro unsigned int i;
153ec7c50bfSpedro char *f;
154ec7c50bfSpedro
155ec7c50bfSpedro for (f = strtok(sflags, ","); f != NULL; f = strtok(NULL, ",")) {
156ec7c50bfSpedro /* Support magic 'none' flag which just reset all flags. */
157ec7c50bfSpedro if (strcmp(f, "none") == 0)
158ec7c50bfSpedro return (0);
159ec7c50bfSpedro for (i = 0; tflags[i].f_str != NULL; i++) {
160ec7c50bfSpedro if (strcmp(tflags[i].f_str, f) == 0)
161ec7c50bfSpedro break;
162ec7c50bfSpedro }
163ec7c50bfSpedro if (tflags[i].f_str == NULL) {
164ec7c50bfSpedro fprintf(stderr, "unknown flag '%s'\n", f);
165ec7c50bfSpedro exit(1);
166ec7c50bfSpedro }
167ec7c50bfSpedro flags |= tflags[i].f_flag;
168ec7c50bfSpedro }
169ec7c50bfSpedro return (flags);
170ec7c50bfSpedro }
171ec7c50bfSpedro
172ec7c50bfSpedro static char *
flags2str(struct flag * tflags,long long flags)173ec7c50bfSpedro flags2str(struct flag *tflags, long long flags)
174ec7c50bfSpedro {
175ec7c50bfSpedro static char sflags[1024];
176ec7c50bfSpedro unsigned int i;
177ec7c50bfSpedro
178ec7c50bfSpedro sflags[0] = '\0';
179ec7c50bfSpedro for (i = 0; tflags[i].f_str != NULL; i++) {
180ec7c50bfSpedro if (flags & tflags[i].f_flag) {
181ec7c50bfSpedro if (sflags[0] != '\0')
182ec7c50bfSpedro strlcat(sflags, ",", sizeof(sflags));
183ec7c50bfSpedro strlcat(sflags, tflags[i].f_str, sizeof(sflags));
184ec7c50bfSpedro }
185ec7c50bfSpedro }
186ec7c50bfSpedro if (sflags[0] == '\0')
187ec7c50bfSpedro strlcpy(sflags, "none", sizeof(sflags));
188ec7c50bfSpedro return (sflags);
189ec7c50bfSpedro }
190ec7c50bfSpedro
191ec7c50bfSpedro static struct syscall_desc *
find_syscall(const char * name)192ec7c50bfSpedro find_syscall(const char *name)
193ec7c50bfSpedro {
194ec7c50bfSpedro int i;
195ec7c50bfSpedro
196ec7c50bfSpedro for (i = 0; syscalls[i].sd_name != NULL; i++) {
197ec7c50bfSpedro if (strcmp(syscalls[i].sd_name, name) == 0)
198ec7c50bfSpedro return (&syscalls[i]);
199ec7c50bfSpedro }
200ec7c50bfSpedro return (NULL);
201ec7c50bfSpedro }
202ec7c50bfSpedro
203ec7c50bfSpedro static void
show_stat(struct stat * sp,const char * what)204ec7c50bfSpedro show_stat(struct stat *sp, const char *what)
205ec7c50bfSpedro {
206ec7c50bfSpedro
207ec7c50bfSpedro if (strcmp(what, "mode") == 0)
208ec7c50bfSpedro printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS));
209ec7c50bfSpedro else if (strcmp(what, "inode") == 0)
210404bddbdSguenther printf("%llu", (unsigned long long)sp->st_ino);
211ec7c50bfSpedro else if (strcmp(what, "nlink") == 0)
212ec7c50bfSpedro printf("%lld", (long long)sp->st_nlink);
213ec7c50bfSpedro else if (strcmp(what, "uid") == 0)
214ec7c50bfSpedro printf("%d", (int)sp->st_uid);
215ec7c50bfSpedro else if (strcmp(what, "gid") == 0)
216ec7c50bfSpedro printf("%d", (int)sp->st_gid);
217ec7c50bfSpedro else if (strcmp(what, "size") == 0)
218ec7c50bfSpedro printf("%lld", (long long)sp->st_size);
219ec7c50bfSpedro else if (strcmp(what, "blocks") == 0)
220ec7c50bfSpedro printf("%lld", (long long)sp->st_blocks);
221ec7c50bfSpedro else if (strcmp(what, "atime") == 0)
222ec7c50bfSpedro printf("%lld", (long long)sp->st_atime);
223ec7c50bfSpedro else if (strcmp(what, "mtime") == 0)
224ec7c50bfSpedro printf("%lld", (long long)sp->st_mtime);
225ec7c50bfSpedro else if (strcmp(what, "ctime") == 0)
226ec7c50bfSpedro printf("%lld", (long long)sp->st_ctime);
227ec7c50bfSpedro else if (strcmp(what, "flags") == 0)
228ec7c50bfSpedro printf("%s", flags2str(chflags_flags, sp->st_flags));
229ec7c50bfSpedro else if (strcmp(what, "type") == 0) {
230ec7c50bfSpedro switch (sp->st_mode & S_IFMT) {
231ec7c50bfSpedro case S_IFIFO:
232ec7c50bfSpedro printf("fifo");
233ec7c50bfSpedro break;
234ec7c50bfSpedro case S_IFCHR:
235ec7c50bfSpedro printf("char");
236ec7c50bfSpedro break;
237ec7c50bfSpedro case S_IFDIR:
238ec7c50bfSpedro printf("dir");
239ec7c50bfSpedro break;
240ec7c50bfSpedro case S_IFBLK:
241ec7c50bfSpedro printf("block");
242ec7c50bfSpedro break;
243ec7c50bfSpedro case S_IFREG:
244ec7c50bfSpedro printf("regular");
245ec7c50bfSpedro break;
246ec7c50bfSpedro case S_IFLNK:
247ec7c50bfSpedro printf("symlink");
248ec7c50bfSpedro break;
249ec7c50bfSpedro case S_IFSOCK:
250ec7c50bfSpedro printf("socket");
251ec7c50bfSpedro break;
252ec7c50bfSpedro default:
253ec7c50bfSpedro printf("unknown");
254ec7c50bfSpedro break;
255ec7c50bfSpedro }
256ec7c50bfSpedro } else {
257ec7c50bfSpedro printf("unknown");
258ec7c50bfSpedro }
259ec7c50bfSpedro }
260ec7c50bfSpedro
261ec7c50bfSpedro static void
show_stats(struct stat * sp,char * what)262ec7c50bfSpedro show_stats(struct stat *sp, char *what)
263ec7c50bfSpedro {
264ec7c50bfSpedro const char *s = "";
265ec7c50bfSpedro char *w;
266ec7c50bfSpedro
267ec7c50bfSpedro for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) {
268ec7c50bfSpedro printf("%s", s);
269ec7c50bfSpedro show_stat(sp, w);
270ec7c50bfSpedro s = ",";
271ec7c50bfSpedro }
272ec7c50bfSpedro printf("\n");
273ec7c50bfSpedro }
274ec7c50bfSpedro
275ec7c50bfSpedro static unsigned int
call_syscall(struct syscall_desc * scall,char * argv[])276ec7c50bfSpedro call_syscall(struct syscall_desc *scall, char *argv[])
277ec7c50bfSpedro {
278ec7c50bfSpedro struct stat sb;
279ec7c50bfSpedro long long flags;
280ec7c50bfSpedro unsigned int i;
281ec7c50bfSpedro char *endp;
282ec7c50bfSpedro int rval;
283ec7c50bfSpedro union {
284ec7c50bfSpedro char *str;
285ec7c50bfSpedro long long num;
286ec7c50bfSpedro } args[MAX_ARGS];
28737dd51d1Sthib unsigned int ch_flags;
288ec7c50bfSpedro
289ec7c50bfSpedro /*
290ec7c50bfSpedro * Verify correctness of the arguments.
291ec7c50bfSpedro */
292ec7c50bfSpedro for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) {
293ec7c50bfSpedro if (scall->sd_args[i] == TYPE_NONE) {
294ec7c50bfSpedro if (argv[i] == NULL || strcmp(argv[i], ":") == 0)
295ec7c50bfSpedro break;
296ec7c50bfSpedro fprintf(stderr, "too many arguments [%s]\n", argv[i]);
297ec7c50bfSpedro exit(1);
298ec7c50bfSpedro } else {
299ec7c50bfSpedro if (argv[i] == NULL || strcmp(argv[i], ":") == 0) {
300ec7c50bfSpedro if (scall->sd_args[i] & TYPE_OPTIONAL)
301ec7c50bfSpedro break;
302ec7c50bfSpedro fprintf(stderr, "too few arguments\n");
303ec7c50bfSpedro exit(1);
304ec7c50bfSpedro }
305ec7c50bfSpedro if (scall->sd_args[i] & TYPE_STRING) {
306ec7c50bfSpedro if (strcmp(argv[i], "NULL") == 0)
307ec7c50bfSpedro args[i].str = NULL;
308ec7c50bfSpedro else if (strcmp(argv[i], "DEADCODE") == 0)
309ec7c50bfSpedro args[i].str = (void *)0xdeadc0de;
310ec7c50bfSpedro else
311ec7c50bfSpedro args[i].str = argv[i];
312ec7c50bfSpedro } else if (scall->sd_args[i] & TYPE_NUMBER) {
313ec7c50bfSpedro args[i].num = strtoll(argv[i], &endp, 0);
314ec7c50bfSpedro if (*endp != '\0' &&
315ec7c50bfSpedro !isspace((unsigned char)*endp)) {
316ec7c50bfSpedro fprintf(stderr, "invalid argument %u, "
317ec7c50bfSpedro "number expected [%s]\n", i, endp);
318ec7c50bfSpedro exit(1);
319ec7c50bfSpedro }
320ec7c50bfSpedro }
321ec7c50bfSpedro }
322ec7c50bfSpedro }
323ec7c50bfSpedro /*
324ec7c50bfSpedro * Call the given syscall.
325ec7c50bfSpedro */
326ec7c50bfSpedro #define NUM(n) (args[(n)].num)
327ec7c50bfSpedro #define STR(n) (args[(n)].str)
328ec7c50bfSpedro switch (scall->sd_action) {
329ec7c50bfSpedro case ACTION_OPEN:
330ec7c50bfSpedro flags = str2flags(open_flags, STR(1));
331ec7c50bfSpedro if (flags & O_CREAT) {
332ec7c50bfSpedro if (i == 2) {
333ec7c50bfSpedro fprintf(stderr, "too few arguments\n");
334ec7c50bfSpedro exit(1);
335ec7c50bfSpedro }
336ec7c50bfSpedro rval = open(STR(0), flags, (mode_t)NUM(2));
337ec7c50bfSpedro } else {
338ec7c50bfSpedro if (i == 3) {
339ec7c50bfSpedro fprintf(stderr, "too many arguments\n");
340ec7c50bfSpedro exit(1);
341ec7c50bfSpedro }
342ec7c50bfSpedro rval = open(STR(0), flags);
343ec7c50bfSpedro }
344ec7c50bfSpedro break;
345ec7c50bfSpedro case ACTION_CREATE:
346ec7c50bfSpedro rval = open(STR(0), O_CREAT | O_EXCL, NUM(1));
347ec7c50bfSpedro if (rval >= 0)
348ec7c50bfSpedro close(rval);
349ec7c50bfSpedro break;
350ec7c50bfSpedro case ACTION_UNLINK:
351ec7c50bfSpedro rval = unlink(STR(0));
352ec7c50bfSpedro break;
353ec7c50bfSpedro case ACTION_MKDIR:
354ec7c50bfSpedro rval = mkdir(STR(0), NUM(1));
355ec7c50bfSpedro break;
356ec7c50bfSpedro case ACTION_RMDIR:
357ec7c50bfSpedro rval = rmdir(STR(0));
358ec7c50bfSpedro break;
359ec7c50bfSpedro case ACTION_LINK:
360ec7c50bfSpedro rval = link(STR(0), STR(1));
361ec7c50bfSpedro break;
362ec7c50bfSpedro case ACTION_SYMLINK:
363ec7c50bfSpedro rval = symlink(STR(0), STR(1));
364ec7c50bfSpedro break;
365ec7c50bfSpedro case ACTION_RENAME:
366ec7c50bfSpedro rval = rename(STR(0), STR(1));
367ec7c50bfSpedro break;
368ec7c50bfSpedro case ACTION_MKFIFO:
369ec7c50bfSpedro rval = mkfifo(STR(0), NUM(1));
370ec7c50bfSpedro break;
371ec7c50bfSpedro case ACTION_CHMOD:
372ec7c50bfSpedro rval = chmod(STR(0), NUM(1));
373ec7c50bfSpedro break;
374ec7c50bfSpedro case ACTION_CHOWN:
375ec7c50bfSpedro rval = chown(STR(0), NUM(1), NUM(2));
376ec7c50bfSpedro break;
377ec7c50bfSpedro case ACTION_LCHOWN:
378ec7c50bfSpedro rval = lchown(STR(0), NUM(1), NUM(2));
379ec7c50bfSpedro break;
380ec7c50bfSpedro case ACTION_CHFLAGS:
38137dd51d1Sthib ch_flags = str2flags(chflags_flags, STR(1));
38237dd51d1Sthib if (!use_appimm)
38337dd51d1Sthib ch_flags &= ~(SF_APPEND|SF_IMMUTABLE);
38437dd51d1Sthib rval = chflags(STR(0), ch_flags);
385ec7c50bfSpedro break;
3860350e6d8Sbluhm case ACTION_LCHFLAGS:
3870350e6d8Sbluhm ch_flags = str2flags(chflags_flags, STR(1));
3880350e6d8Sbluhm if (!use_appimm)
3890350e6d8Sbluhm ch_flags &= ~(SF_APPEND|SF_IMMUTABLE);
3900350e6d8Sbluhm rval = chflagsat(AT_FDCWD, STR(0), ch_flags,
3910350e6d8Sbluhm AT_SYMLINK_NOFOLLOW);
3920350e6d8Sbluhm break;
393ec7c50bfSpedro case ACTION_TRUNCATE:
394ec7c50bfSpedro rval = truncate(STR(0), NUM(1));
395ec7c50bfSpedro break;
396ec7c50bfSpedro case ACTION_STAT:
397ec7c50bfSpedro rval = stat(STR(0), &sb);
398ec7c50bfSpedro if (rval == 0) {
399ec7c50bfSpedro show_stats(&sb, STR(1));
400ec7c50bfSpedro return (i);
401ec7c50bfSpedro }
402ec7c50bfSpedro break;
403ec7c50bfSpedro case ACTION_LSTAT:
404ec7c50bfSpedro rval = lstat(STR(0), &sb);
405ec7c50bfSpedro if (rval == 0) {
406ec7c50bfSpedro show_stats(&sb, STR(1));
407ec7c50bfSpedro return (i);
408ec7c50bfSpedro }
409ec7c50bfSpedro break;
410ec7c50bfSpedro default:
411ec7c50bfSpedro fprintf(stderr, "unsupported syscall\n");
412ec7c50bfSpedro exit(1);
413ec7c50bfSpedro }
414ec7c50bfSpedro #undef STR
415ec7c50bfSpedro #undef NUM
416ec7c50bfSpedro if (rval < 0) {
417d59dbe75Sbluhm printf("%s\n", err2str(errno));
418ec7c50bfSpedro exit(1);
419ec7c50bfSpedro }
420ec7c50bfSpedro printf("0\n");
421ec7c50bfSpedro return (i);
422ec7c50bfSpedro }
423ec7c50bfSpedro
424ec7c50bfSpedro static void
set_gids(char * gids)425ec7c50bfSpedro set_gids(char *gids)
426ec7c50bfSpedro {
427ec7c50bfSpedro gid_t *gidset;
428ec7c50bfSpedro long ngroups;
429ec7c50bfSpedro char *g, *endp;
430ec7c50bfSpedro unsigned i;
431ec7c50bfSpedro
432ec7c50bfSpedro ngroups = sysconf(_SC_NGROUPS_MAX);
433ec7c50bfSpedro assert(ngroups > 0);
43424b9810bSdoug gidset = reallocarray(NULL, ngroups, sizeof(*gidset));
435ec7c50bfSpedro assert(gidset != NULL);
436ec7c50bfSpedro for (i = 0, g = strtok(gids, ","); g != NULL;
437ec7c50bfSpedro g = strtok(NULL, ","), i++) {
438ec7c50bfSpedro if (i >= ngroups) {
439ec7c50bfSpedro fprintf(stderr, "too many gids\n");
440ec7c50bfSpedro exit(1);
441ec7c50bfSpedro }
442ec7c50bfSpedro gidset[i] = strtol(g, &endp, 0);
443ec7c50bfSpedro if (*endp != '\0' && !isspace((unsigned char)*endp)) {
444ec7c50bfSpedro fprintf(stderr, "invalid gid '%s' - number expected\n",
445ec7c50bfSpedro g);
446ec7c50bfSpedro exit(1);
447ec7c50bfSpedro }
448ec7c50bfSpedro }
449ec7c50bfSpedro if (setgroups(i, gidset) < 0) {
450ec7c50bfSpedro fprintf(stderr, "cannot change groups: %s\n", strerror(errno));
451ec7c50bfSpedro exit(1);
452ec7c50bfSpedro }
453ec7c50bfSpedro free(gidset);
454ec7c50bfSpedro }
455ec7c50bfSpedro
456ec7c50bfSpedro int
main(int argc,char * argv[])457ec7c50bfSpedro main(int argc, char *argv[])
458ec7c50bfSpedro {
459ec7c50bfSpedro struct syscall_desc *scall;
460ec7c50bfSpedro unsigned int n;
461ec7c50bfSpedro char *gids, *endp;
462ec7c50bfSpedro int uid, umsk, ch;
46337dd51d1Sthib int mib[2];
46437dd51d1Sthib size_t len;
46537dd51d1Sthib int securelevel;
466ec7c50bfSpedro
467ec7c50bfSpedro uid = -1;
468ec7c50bfSpedro gids = NULL;
469ec7c50bfSpedro umsk = 0;
470ec7c50bfSpedro
471ec7c50bfSpedro while ((ch = getopt(argc, argv, "g:u:U:")) != -1) {
472ec7c50bfSpedro switch(ch) {
473ec7c50bfSpedro case 'g':
474ec7c50bfSpedro gids = optarg;
475ec7c50bfSpedro break;
476ec7c50bfSpedro case 'u':
477ec7c50bfSpedro uid = (int)strtol(optarg, &endp, 0);
478ec7c50bfSpedro if (*endp != '\0' && !isspace((unsigned char)*endp)) {
479ec7c50bfSpedro fprintf(stderr, "invalid uid '%s' - number "
480ec7c50bfSpedro "expected\n", optarg);
481ec7c50bfSpedro exit(1);
482ec7c50bfSpedro }
483ec7c50bfSpedro break;
484ec7c50bfSpedro case 'U':
485ec7c50bfSpedro umsk = (int)strtol(optarg, &endp, 0);
486ec7c50bfSpedro if (*endp != '\0' && !isspace((unsigned char)*endp)) {
487ec7c50bfSpedro fprintf(stderr, "invalid umask '%s' - number "
488ec7c50bfSpedro "expected\n", optarg);
489ec7c50bfSpedro exit(1);
490ec7c50bfSpedro }
491ec7c50bfSpedro break;
492ec7c50bfSpedro default:
493ec7c50bfSpedro usage();
494ec7c50bfSpedro }
495ec7c50bfSpedro }
496ec7c50bfSpedro argc -= optind;
497ec7c50bfSpedro argv += optind;
498ec7c50bfSpedro
499ec7c50bfSpedro if (argc < 1) {
500ec7c50bfSpedro fprintf(stderr, "too few arguments\n");
501ec7c50bfSpedro usage();
502ec7c50bfSpedro }
503ec7c50bfSpedro
504d59dbe75Sbluhm if (gids != NULL)
505ec7c50bfSpedro set_gids(gids);
506ec7c50bfSpedro if (uid != -1) {
507ec7c50bfSpedro if (setuid(uid) < 0) {
508ec7c50bfSpedro fprintf(stderr, "cannot change uid: %s\n",
509ec7c50bfSpedro strerror(errno));
510ec7c50bfSpedro exit(1);
511ec7c50bfSpedro }
512ec7c50bfSpedro }
513ec7c50bfSpedro
51437dd51d1Sthib /*
51537dd51d1Sthib * Find out if we should use the SF_IMMUTABLE and SF_APPEND flags;
51637dd51d1Sthib * Since we run by default on kern.securelevel=1 these cause false
51737dd51d1Sthib * positives.
51837dd51d1Sthib */
51937dd51d1Sthib mib[0] = CTL_KERN;
52037dd51d1Sthib mib[1] = KERN_SECURELVL;
52137dd51d1Sthib len = sizeof(securelevel);
52237dd51d1Sthib if (sysctl(mib, 2, &securelevel, &len, NULL, 0) == -1) {
52337dd51d1Sthib fprintf(stderr, "cannot get kernel securelevel\n");
52437dd51d1Sthib exit(1);
52537dd51d1Sthib }
52637dd51d1Sthib if (securelevel == 0 || securelevel == -1)
52737dd51d1Sthib use_appimm = 1;
52837dd51d1Sthib else
52937dd51d1Sthib use_appimm = 0;
53037dd51d1Sthib
531ec7c50bfSpedro /* Change umask to requested value or to 0, if not requested. */
532ec7c50bfSpedro umask(umsk);
533ec7c50bfSpedro
534ec7c50bfSpedro for (;;) {
535ec7c50bfSpedro scall = find_syscall(argv[0]);
536ec7c50bfSpedro if (scall == NULL) {
5370350e6d8Sbluhm fprintf(stderr, "syscall '%s' not supported\n",
5380350e6d8Sbluhm argv[0]);
539ec7c50bfSpedro exit(1);
540ec7c50bfSpedro }
541ec7c50bfSpedro argc++;
542ec7c50bfSpedro argv++;
543ec7c50bfSpedro n = call_syscall(scall, argv);
544ec7c50bfSpedro argc += n;
545ec7c50bfSpedro argv += n;
546ec7c50bfSpedro if (argv[0] == NULL)
547ec7c50bfSpedro break;
548ec7c50bfSpedro argc++;
549ec7c50bfSpedro argv++;
550ec7c50bfSpedro }
551ec7c50bfSpedro
552ec7c50bfSpedro exit(0);
553ec7c50bfSpedro }
554ec7c50bfSpedro
555ec7c50bfSpedro static const char *
err2str(int error)556ec7c50bfSpedro err2str(int error)
557ec7c50bfSpedro {
558ec7c50bfSpedro static char errnum[8];
559ec7c50bfSpedro
560ec7c50bfSpedro switch (error) {
561ec7c50bfSpedro case EPERM:
562ec7c50bfSpedro return ("EPERM");
563ec7c50bfSpedro case ENOENT:
564ec7c50bfSpedro return ("ENOENT");
565ec7c50bfSpedro case ESRCH:
566ec7c50bfSpedro return ("ESRCH");
567ec7c50bfSpedro case EINTR:
568ec7c50bfSpedro return ("EINTR");
569ec7c50bfSpedro case EIO:
570ec7c50bfSpedro return ("EIO");
571ec7c50bfSpedro case ENXIO:
572ec7c50bfSpedro return ("ENXIO");
573ec7c50bfSpedro case E2BIG:
574ec7c50bfSpedro return ("E2BIG");
575ec7c50bfSpedro case ENOEXEC:
576ec7c50bfSpedro return ("ENOEXEC");
577ec7c50bfSpedro case EBADF:
578ec7c50bfSpedro return ("EBADF");
579ec7c50bfSpedro case ECHILD:
580ec7c50bfSpedro return ("ECHILD");
581ec7c50bfSpedro case EDEADLK:
582ec7c50bfSpedro return ("EDEADLK");
583ec7c50bfSpedro case ENOMEM:
584ec7c50bfSpedro return ("ENOMEM");
585ec7c50bfSpedro case EACCES:
586ec7c50bfSpedro return ("EACCES");
587ec7c50bfSpedro case EFAULT:
588ec7c50bfSpedro return ("EFAULT");
589ec7c50bfSpedro case ENOTBLK:
590ec7c50bfSpedro return ("ENOTBLK");
591ec7c50bfSpedro case EBUSY:
592ec7c50bfSpedro return ("EBUSY");
593ec7c50bfSpedro case EEXIST:
594ec7c50bfSpedro return ("EEXIST");
595ec7c50bfSpedro case EXDEV:
596ec7c50bfSpedro return ("EXDEV");
597ec7c50bfSpedro case ENODEV:
598ec7c50bfSpedro return ("ENODEV");
599ec7c50bfSpedro case ENOTDIR:
600ec7c50bfSpedro return ("ENOTDIR");
601ec7c50bfSpedro case EISDIR:
602ec7c50bfSpedro return ("EISDIR");
603ec7c50bfSpedro case EINVAL:
604ec7c50bfSpedro return ("EINVAL");
605ec7c50bfSpedro case ENFILE:
606ec7c50bfSpedro return ("ENFILE");
607ec7c50bfSpedro case EMFILE:
608ec7c50bfSpedro return ("EMFILE");
609ec7c50bfSpedro case ENOTTY:
610ec7c50bfSpedro return ("ENOTTY");
611ec7c50bfSpedro case ETXTBSY:
612ec7c50bfSpedro return ("ETXTBSY");
613ec7c50bfSpedro case EFBIG:
614ec7c50bfSpedro return ("EFBIG");
615ec7c50bfSpedro case ENOSPC:
616ec7c50bfSpedro return ("ENOSPC");
617ec7c50bfSpedro case ESPIPE:
618ec7c50bfSpedro return ("ESPIPE");
619ec7c50bfSpedro case EROFS:
620ec7c50bfSpedro return ("EROFS");
621ec7c50bfSpedro case EMLINK:
622ec7c50bfSpedro return ("EMLINK");
623ec7c50bfSpedro case EPIPE:
624ec7c50bfSpedro return ("EPIPE");
625ec7c50bfSpedro case EDOM:
626ec7c50bfSpedro return ("EDOM");
627ec7c50bfSpedro case ERANGE:
628ec7c50bfSpedro return ("ERANGE");
629ec7c50bfSpedro case EAGAIN:
630ec7c50bfSpedro return ("EAGAIN");
631ec7c50bfSpedro case EINPROGRESS:
632ec7c50bfSpedro return ("EINPROGRESS");
633ec7c50bfSpedro case EALREADY:
634ec7c50bfSpedro return ("EALREADY");
635ec7c50bfSpedro case ENOTSOCK:
636ec7c50bfSpedro return ("ENOTSOCK");
637ec7c50bfSpedro case EDESTADDRREQ:
638ec7c50bfSpedro return ("EDESTADDRREQ");
639ec7c50bfSpedro case EMSGSIZE:
640ec7c50bfSpedro return ("EMSGSIZE");
641ec7c50bfSpedro case EPROTOTYPE:
642ec7c50bfSpedro return ("EPROTOTYPE");
643ec7c50bfSpedro case ENOPROTOOPT:
644ec7c50bfSpedro return ("ENOPROTOOPT");
645ec7c50bfSpedro case EPROTONOSUPPORT:
646ec7c50bfSpedro return ("EPROTONOSUPPORT");
647ec7c50bfSpedro case ESOCKTNOSUPPORT:
648ec7c50bfSpedro return ("ESOCKTNOSUPPORT");
649ec7c50bfSpedro case EOPNOTSUPP:
650ec7c50bfSpedro return ("EOPNOTSUPP");
651ec7c50bfSpedro case EPFNOSUPPORT:
652ec7c50bfSpedro return ("EPFNOSUPPORT");
653ec7c50bfSpedro case EAFNOSUPPORT:
654ec7c50bfSpedro return ("EAFNOSUPPORT");
655ec7c50bfSpedro case EADDRINUSE:
656ec7c50bfSpedro return ("EADDRINUSE");
657ec7c50bfSpedro case EADDRNOTAVAIL:
658ec7c50bfSpedro return ("EADDRNOTAVAIL");
659ec7c50bfSpedro case ENETDOWN:
660ec7c50bfSpedro return ("ENETDOWN");
661ec7c50bfSpedro case ENETUNREACH:
662ec7c50bfSpedro return ("ENETUNREACH");
663ec7c50bfSpedro case ENETRESET:
664ec7c50bfSpedro return ("ENETRESET");
665ec7c50bfSpedro case ECONNABORTED:
666ec7c50bfSpedro return ("ECONNABORTED");
667ec7c50bfSpedro case ECONNRESET:
668ec7c50bfSpedro return ("ECONNRESET");
669ec7c50bfSpedro case ENOBUFS:
670ec7c50bfSpedro return ("ENOBUFS");
671ec7c50bfSpedro case EISCONN:
672ec7c50bfSpedro return ("EISCONN");
673ec7c50bfSpedro case ENOTCONN:
674ec7c50bfSpedro return ("ENOTCONN");
675ec7c50bfSpedro case ESHUTDOWN:
676ec7c50bfSpedro return ("ESHUTDOWN");
677ec7c50bfSpedro case ETOOMANYREFS:
678ec7c50bfSpedro return ("ETOOMANYREFS");
679ec7c50bfSpedro case ETIMEDOUT:
680ec7c50bfSpedro return ("ETIMEDOUT");
681ec7c50bfSpedro case ECONNREFUSED:
682ec7c50bfSpedro return ("ECONNREFUSED");
683ec7c50bfSpedro case ELOOP:
684ec7c50bfSpedro return ("ELOOP");
685ec7c50bfSpedro case ENAMETOOLONG:
686ec7c50bfSpedro return ("ENAMETOOLONG");
687ec7c50bfSpedro case EHOSTDOWN:
688ec7c50bfSpedro return ("EHOSTDOWN");
689ec7c50bfSpedro case EHOSTUNREACH:
690ec7c50bfSpedro return ("EHOSTUNREACH");
691ec7c50bfSpedro case ENOTEMPTY:
692ec7c50bfSpedro return ("ENOTEMPTY");
693ec7c50bfSpedro case EPROCLIM:
694ec7c50bfSpedro return ("EPROCLIM");
695ec7c50bfSpedro case EUSERS:
696ec7c50bfSpedro return ("EUSERS");
697ec7c50bfSpedro case EDQUOT:
698ec7c50bfSpedro return ("EDQUOT");
699ec7c50bfSpedro case ESTALE:
700ec7c50bfSpedro return ("ESTALE");
701ec7c50bfSpedro case EREMOTE:
702ec7c50bfSpedro return ("EREMOTE");
703ec7c50bfSpedro case EBADRPC:
704ec7c50bfSpedro return ("EBADRPC");
705ec7c50bfSpedro case ERPCMISMATCH:
706ec7c50bfSpedro return ("ERPCMISMATCH");
707ec7c50bfSpedro case EPROGUNAVAIL:
708ec7c50bfSpedro return ("EPROGUNAVAIL");
709ec7c50bfSpedro case EPROGMISMATCH:
710ec7c50bfSpedro return ("EPROGMISMATCH");
711ec7c50bfSpedro case EPROCUNAVAIL:
712ec7c50bfSpedro return ("EPROCUNAVAIL");
713ec7c50bfSpedro case ENOLCK:
714ec7c50bfSpedro return ("ENOLCK");
715ec7c50bfSpedro case ENOSYS:
716ec7c50bfSpedro return ("ENOSYS");
717ec7c50bfSpedro case EFTYPE:
718ec7c50bfSpedro return ("EFTYPE");
719ec7c50bfSpedro case EAUTH:
720ec7c50bfSpedro return ("EAUTH");
721ec7c50bfSpedro case ENEEDAUTH:
722ec7c50bfSpedro return ("ENEEDAUTH");
723ec7c50bfSpedro case EILSEQ:
724ec7c50bfSpedro return ("EILSEQ");
725ec7c50bfSpedro case ENOATTR:
726ec7c50bfSpedro return ("ENOATTR");
727ec7c50bfSpedro default:
728ec7c50bfSpedro snprintf(errnum, sizeof(errnum), "%d", error);
729ec7c50bfSpedro return (errnum);
730ec7c50bfSpedro }
731ec7c50bfSpedro }
732