enviro.c (2353B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <regex.h> 6 #include <fcntl.h> 7 #include <sys/stat.h> 8 9 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) 10 11 __attribute__((noreturn)) 12 void die(char const* msg) 13 { 14 fprintf(stderr, "enviro: %s\n", msg); 15 exit(1); 16 } 17 18 __attribute__((noreturn)) 19 void errorno_die(char const* msg) 20 { 21 perror(msg); 22 exit(1); 23 } 24 25 __attribute__((noreturn)) 26 void regex_die(int e, regex_t const* r, char const* msg) 27 { 28 size_t size = regerror(e, r, NULL, 0); 29 char* buf = malloc(size); 30 31 regerror(e, r, buf, size); 32 fprintf(stderr, "%s: %s\n", msg, buf); 33 exit(1); 34 } 35 36 int regexec_or_die(const regex_t *restrict preg, const char *restrict string, size_t nmatch, regmatch_t pmatch[restrict], int eflags) 37 { 38 int e = regexec(preg, string, nmatch, pmatch, eflags); 39 switch (e) 40 { 41 case REG_NOMATCH: 42 case 0: 43 return e; 44 45 default: 46 regex_die(e, preg, "regexec"); 47 } 48 } 49 50 char const usage[] = 51 "USAGE:\n" 52 "\tenviro (file | -) command [args...]\n" 53 "\nSUMMARY:\n" 54 "\tRun command with the environment from a file or stdin\n"; 55 56 char const* regexes[] = 57 { 58 "^[[:blank:]]*(#.*)?\n$", 59 "^[[:blank:]]*([[:alnum:]_.,]+=.*)\n$", 60 }; 61 62 regex_t r[ARRAY_SIZE(regexes)]; 63 64 int main(int argc, char* argv[]) 65 { 66 FILE* f = stdin; 67 68 for (unsigned i = 0; i < ARRAY_SIZE(r); ++i) 69 { 70 int e = regcomp(r + i, regexes[i], REG_EXTENDED | REG_NEWLINE); 71 if (e) 72 regex_die(e, r + i, "regcomp"); 73 } 74 75 if (argc < 3) 76 { 77 fputs(usage, stderr); 78 return 1; 79 } 80 81 if (strcmp("-", argv[1])) 82 { 83 struct stat s; 84 int fd = open(argv[1], O_RDONLY); 85 86 if (fd < 0) 87 errorno_die("open"); 88 89 if (fstat(fd, &s)) 90 errorno_die("fstat"); 91 92 if ((s.st_mode & S_IFMT) == S_IFDIR) 93 { 94 fprintf(stderr, "enviro: '%s' is a directory\n", argv[1]); 95 exit(1); 96 } 97 98 f = fdopen(fd, "r"); 99 if (!f) 100 errorno_die("fdopen"); 101 } 102 103 clearenv(); 104 105 for (;;) 106 { 107 char* line = NULL; 108 size_t size = 0; 109 regmatch_t m[2]; 110 111 if (getline(&line, &size, f) == -1) 112 break; 113 114 if (!regexec_or_die(&r[0], line, 0, NULL, 0)) 115 continue; 116 117 if (regexec_or_die(r+1, line, ARRAY_SIZE(m), m, 0)) 118 { 119 fprintf(stderr, "enviro: bad format: %s\n", line); 120 return 1; 121 } 122 123 if (m[1].rm_so == -1) 124 die("bad match"); 125 126 line[m[1].rm_eo] = '\0'; 127 128 if (putenv(line + m[1].rm_so)) 129 errorno_die("putenv"); 130 } 131 132 execvp(argv[2], argv + 2); 133 errorno_die("execvp"); 134 }