1 /*
2 * Copyright (c) 2025 Rick Macklem
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 #include <sys/param.h>
8 #include <sys/wait.h>
9 #include <err.h>
10 #include <fcntl.h>
11 #include <paths.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17
18 static void
usage(void)19 usage(void)
20 {
21 (void)fprintf(stderr, "usage: runat <file> "
22 "<shell command>\n");
23 exit(1);
24 }
25
26 int
main(int argc,char * argv[])27 main(int argc, char *argv[])
28 {
29 int i, file_fd, nameddir_fd, outsiz;
30 char *buf;
31 long named_enabled;
32 size_t pos, siz;
33
34 if (argc <= 2)
35 usage();
36 argv++;
37 argc--;
38 if (argc < 2)
39 usage();
40
41 named_enabled = pathconf(argv[0], _PC_NAMEDATTR_ENABLED);
42 if (named_enabled <= 0)
43 errx(1, "Named attributes not enabled for %s", argv[0]);
44
45 /* Generate the command string for "sh". */
46 siz = 0;
47 for (i = 1; i < argc; i++)
48 siz += strlen(argv[i]) + 1;
49 buf = malloc(siz);
50 if (buf == NULL)
51 errx(1, "Cannot malloc");
52 pos = 0;
53 for (i = 1; i < argc; i++) {
54 outsiz = snprintf(&buf[pos], siz, "%s ", argv[i]);
55 if (outsiz <= 0)
56 errx(1, "snprintf failed: returned %d", outsiz);
57 if ((size_t)outsiz > siz)
58 errx(1, "Arguments too large");
59 pos += outsiz;
60 siz -= outsiz;
61 }
62 buf[pos - 1] = '\0';
63
64 file_fd = open(argv[0], O_RDONLY | O_CLOEXEC, 0);
65 if (file_fd < 0)
66 err(1, "Cannot open %s", argv[0]);
67 nameddir_fd = openat(file_fd, ".", O_RDONLY | O_CLOEXEC | O_NAMEDATTR,
68 0);
69 if (nameddir_fd < 0)
70 err(1, "Cannot open named attribute directory "
71 "for %s", argv[0]);
72
73 if (fchdir(nameddir_fd) < 0)
74 err(1, "Cannot fchdir to named attribute dir");
75
76 execl(_PATH_BSHELL, "sh", "-c", buf, NULL);
77 err(1, "Could not exec %s", _PATH_BSHELL);
78 }
79