serdo.c (2684B) download
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
17const char* current_prog(void) {
18 return "serdo";
19}
20
21char* envp[MAXENV + 2];
22int envc;
23
24int continueonerror;
25
26extern const struct builtin {
27 const char* name;
28 int (*func)(int argv, char** argc);
29} builtins[];
30
31static 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
59static 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
103int 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
119int 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}