serdo.c (2684B)
1 #include "arg.h" 2 #define _GNU_SOURCE 3 4 #include <ctype.h> 5 #include <fcntl.h> 6 #include <fmt.h> 7 #include <linux/limits.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <sys/stat.h> 12 #include <sys/wait.h> 13 #include <unistd.h> 14 15 #define MAXENV 256 16 17 const char* current_prog(void) { 18 return "serdo"; 19 } 20 21 char* envp[MAXENV + 2]; 22 int envc; 23 24 int continueonerror; 25 26 extern const struct builtin { 27 const char* name; 28 int (*func)(int argv, char** argc); 29 } builtins[]; 30 31 static int spawn(int argc, char** argv) { 32 pid_t pid; 33 int status; 34 35 for (const struct builtin* bi = builtins; bi->name; bi++) { 36 if (!strcmp(argv[0], bi->name)) 37 return bi->func(argc, argv); 38 } 39 40 switch (pid = fork()) { 41 case -1: 42 fprint(1, "unable to fork: %r\n"); 43 exit(1); 44 case 0: 45 execvpe(argv[0], argv, envp); 46 fprint(1, "unable to exec: %r\n"); 47 _exit(1); 48 } 49 50 if (waitpid(pid, &status, 0) == -1) 51 fprint(1, "unable to waid for process: %r\n"); 52 53 if (!WIFEXITED(status)) 54 return -1; 55 56 return WEXITSTATUS(status); 57 } 58 59 static int doline(char* line, ssize_t line_size) { 60 int rc; 61 int i = 0; 62 int spacecount = 0; 63 int argc = 0; 64 char** argv; 65 66 while (isspace(line[i])) i++; 67 68 if (line[i] == '#') 69 return 0; 70 71 for (int j = i; j < line_size; j++) 72 if (isspace(line[j])) spacecount++; 73 74 argv = malloc((spacecount + 1) * sizeof(char*)); 75 76 while (i < line_size && line[i] != '\n') { 77 if (line[i] == '"') { 78 i++; 79 argv[argc++] = &line[i]; 80 while (i < line_size && line[i - 1] == '\\' && line[i] != '"') i++; 81 line[i++] = '\0'; 82 } else if (line[i] == '\'') { 83 i++; 84 argv[argc++] = &line[i]; 85 while (i < line_size && line[i - 1] == '\\' && line[i] != '\'') i++; 86 line[i++] = '\0'; 87 } else { 88 argv[argc++] = &line[i]; 89 while (i < line_size && !isspace(line[i])) i++; 90 line[i++] = '\0'; 91 } 92 93 while (i < line_size && isspace(line[i])) i++; 94 } 95 96 argv[argc] = NULL; 97 98 rc = spawn(argc, argv); 99 free(argv); 100 return rc; 101 } 102 103 int execute(FILE* file) { 104 int rc = 0; 105 char* line = NULL; 106 size_t line_alloc = 0; 107 ssize_t line_size; 108 109 while ((line_size = getline(&line, &line_alloc, file)) > 0) { 110 if ((rc = doline(line, line_size)) && !continueonerror) 111 break; 112 } 113 if (line) 114 free(line); 115 116 return rc; 117 } 118 119 int main(int argc, char* argv[], char* env[]) { 120 FILE* f; 121 (void) argc; 122 123 for (envc = 0; envc < MAXENV && env[envc]; ++envc) 124 envp[envc] = env[envc]; 125 126 envp[envc] = 0; 127 128 SHIFT(1); 129 130 if (argc > 1 && !strcmp(*argv, "-c")) { 131 continueonerror = 1; 132 SHIFT(1); 133 } 134 135 if (argc > 1) { 136 if (!(f = fopen(*argv, "r"))) { 137 fprint(1, "unable to open %s: %r\n", *argv); 138 return 1; 139 } 140 } else 141 f = stdin; 142 143 return execute(f); 144 }