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 19 usage(void) 20 { 21 (void)fprintf(stderr, "usage: runat <file> " 22 "<shell command>\n"); 23 exit(1); 24 } 25 26 int 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