Mercurial > sci
comparison scictl/scictl.c @ 22:dd078aea5d02
misc: use project/worker name as primary key
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 21 Jul 2022 20:23:22 +0200 |
parents | de4bf839b565 |
children | 2cb228f23f53 |
comparison
equal
deleted
inserted
replaced
21:ec30e1b078a9 | 22:dd078aea5d02 |
---|---|
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 */ | 17 */ |
18 | 18 |
19 #include <err.h> | 19 #include <limits.h> |
20 #include <errno.h> | |
20 #include <stdio.h> | 21 #include <stdio.h> |
21 #include <stdlib.h> | 22 #include <stdlib.h> |
22 #include <string.h> | 23 #include <string.h> |
23 #include <stdnoreturn.h> | |
24 #include <unistd.h> | 24 #include <unistd.h> |
25 | 25 |
26 #include "apic.h" | |
26 #include "config.h" | 27 #include "config.h" |
27 #include "req.h" | |
28 #include "types.h" | 28 #include "types.h" |
29 #include "util.h" | 29 #include "util.h" |
30 | 30 |
31 noreturn static void | 31 static void |
32 usage(void) | 32 usage(void) |
33 { | 33 { |
34 fprintf(stderr, "usage: %s [-s sock] command [args...]\n", getprogname()); | 34 fprintf(stderr, "usage: %s [-u baseurl] command [args...]\n", getprogname()); |
35 exit(1); | 35 exit(1); |
36 } | 36 } |
37 | 37 |
38 noreturn static void | 38 static void |
39 help(void) | 39 help(void) |
40 { | 40 { |
41 fprintf(stderr, "usage: %s job-add project tag\n", getprogname()); | 41 fprintf(stderr, "usage: scictl job-add project tag\n"); |
42 fprintf(stderr, " %s job-todo worker\n", getprogname()); | 42 fprintf(stderr, " scictl job-todo worker\n"); |
43 fprintf(stderr, " %s jobresult-add id worker exitcode console\n", getprogname()); | 43 fprintf(stderr, " scictl jobresult-add id worker exitcode console\n"); |
44 fprintf(stderr, " %s project-add name desc url script\n", getprogname()); | 44 fprintf(stderr, " scictl project-add name desc url script\n"); |
45 fprintf(stderr, " %s project-info name\n", getprogname()); | 45 fprintf(stderr, " scictl project-info name\n"); |
46 fprintf(stderr, " %s project-list\n", getprogname()); | 46 fprintf(stderr, " scictl project-list\n"); |
47 fprintf(stderr, " %s project-update name key value\n", getprogname()); | 47 fprintf(stderr, " scictl project-update name key value\n"); |
48 fprintf(stderr, " %s worker-add name desc\n", getprogname()); | 48 fprintf(stderr, " scictl worker-add name desc\n"); |
49 fprintf(stderr, " %s worker-list\n", getprogname()); | 49 fprintf(stderr, " scictl worker-list\n"); |
50 exit(0); | 50 exit(0); |
51 } | |
52 | |
53 static inline void | |
54 replace(char **str, const char *new) | |
55 { | |
56 free(*str); | |
57 *str = util_strdup(new); | |
58 } | |
59 | |
60 long long | |
61 toint(const char *s) | |
62 { | |
63 long long v; | |
64 const char *err; | |
65 | |
66 v = util_strtonum(s, 0, LLONG_MAX, &err); | |
67 | |
68 if (err) | |
69 util_die("abort: %s\n", err); | |
70 | |
71 return v; | |
51 } | 72 } |
52 | 73 |
53 static char * | 74 static char * |
54 readfile(const char *path) | 75 readfile(const char *path) |
55 { | 76 { |
56 FILE *fp, *str; | 77 FILE *fp, *str; |
57 char buf[BUFSIZ], *console; | 78 char buf[BUFSIZ], *console = NULL; |
58 size_t nr; | 79 size_t nr, consolesz = 0; |
59 | 80 |
60 if (strcmp(path, "-") == 0) | 81 if (strcmp(path, "-") == 0) |
61 fp = stdin; | 82 fp = stdin; |
62 else if (!(fp = fopen(path, "r"))) | 83 else if (!(fp = fopen(path, "r"))) |
63 err(1, "%s", path); | 84 util_die("abort: %s: %s\n", path, strerror(errno)); |
64 | 85 |
65 console = util_calloc(1, SCI_MSG_MAX); | 86 if (!(str = open_memstream(&console, &consolesz))) |
66 | 87 util_die("abort: open_memstream: %s\n", strerror(errno)); |
67 if (!(str = fmemopen(console, SCI_MSG_MAX, "w"))) | |
68 err(1, "fmemopen"); | |
69 | 88 |
70 while ((nr = fread(buf, 1, sizeof (buf), fp)) > 0) | 89 while ((nr = fread(buf, 1, sizeof (buf), fp)) > 0) |
71 fwrite(buf, 1, nr, str); | 90 fwrite(buf, 1, nr, str); |
72 | 91 |
73 if ((ferror(fp) && !feof(fp)) || (ferror(str) && !feof(str))) { | 92 if ((ferror(fp) && !feof(fp)) || (ferror(str) && !feof(str))) |
74 free(console); | 93 util_die("abort: %s\n", strerror(errno)); |
75 console = NULL; | |
76 } | |
77 | 94 |
78 fclose(str); | 95 fclose(str); |
79 fclose(fp); | 96 fclose(fp); |
80 | 97 |
81 return console; | 98 return console; |
85 extract(char *s, size_t w, size_t n, void *data) | 102 extract(char *s, size_t w, size_t n, void *data) |
86 { | 103 { |
87 return fwrite(s, w, n, data); | 104 return fwrite(s, w, n, data); |
88 } | 105 } |
89 | 106 |
90 static json_t * | 107 static void |
91 parse(const char *data) | |
92 { | |
93 json_t *doc; | |
94 json_error_t err; | |
95 | |
96 if (!(json_loads(doc, 0, &err))) | |
97 die("abort: unable to parse JSON: %s\n", err.text); | |
98 | |
99 return doc; | |
100 } | |
101 | |
102 static json_t * | |
103 get(const char *url) | |
104 { | |
105 CURL *curl; | |
106 CURLcode code; | |
107 FILE *fp; | |
108 char buf[HTTP_BUF_MAX]; | |
109 long ret; | |
110 | |
111 if (!(fp = fmemopen(buf, sizeof (buf), "w"))) | |
112 die("abort: %s", strerror(errno)); | |
113 | |
114 curl = curl_easy_init(); | |
115 curl_easy_setopt(curl, CURLOPT_URL, url); | |
116 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, extract); | |
117 curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); | |
118 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3L); | |
119 code = curl_easy_perform(curl); | |
120 | |
121 if (code != CURLE_OK) | |
122 die("abort: %s", curl_easy_strerror(code)); | |
123 | |
124 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret); | |
125 | |
126 if (ret != 200) | |
127 die("abort: HTTP %ld\n", ret); | |
128 | |
129 curl_easy_cleanup(curl); | |
130 fclose(fp); | |
131 | |
132 return parse(buf); | |
133 } | |
134 | |
135 static struct req | |
136 cmd_job_add(int argc, char **argv) | 108 cmd_job_add(int argc, char **argv) |
137 { | 109 { |
138 struct job job = {0}; | 110 struct job job = {0}; |
139 struct project project = {0}; | 111 struct apic req; |
112 | |
113 if (argc < 3) | |
114 usage(); | |
115 | |
116 job.project_name = util_strdup(argv[1]); | |
117 job.tag = util_strdup(argv[2]); | |
118 | |
119 if (apic_job_add(&req, &job) < 0) | |
120 util_die("abort: %s\n", req.error); | |
121 | |
122 apic_finish(&req); | |
123 job_finish(&job); | |
124 } | |
125 | |
126 static void | |
127 cmd_job_todo(int argc, char **argv) | |
128 { | |
129 struct job jobs[SCI_JOB_LIST_MAX] = {0}; | |
130 size_t jobsz; | |
131 struct apic req; | |
140 | 132 |
141 if (argc < 2) | 133 if (argc < 2) |
142 usage(); | 134 usage(); |
143 | 135 |
144 project.name = argv[0]; | 136 if ((jobsz = apic_job_todo(&req, jobs, UTIL_SIZE(jobs), toint(argv[1])))) |
145 | 137 util_die("abort: %s\n", req.error); |
146 if (_project_find(&project, argv[0])).status) | |
147 return rp; | |
148 | |
149 job.project_id = project.id; | |
150 job.tag = argv[1]; | |
151 | |
152 rj = req_job_add(&job); | |
153 req_finish(&rp); | |
154 | |
155 return rj; | |
156 } | |
157 | |
158 static struct req | |
159 cmd_job_todo(int argc, char **argv) | |
160 { | |
161 struct project projects[SCI_PROJECT_MAX] = {0}; | |
162 struct job jobs[SCI_JOB_LIST_MAX] = {0}; | |
163 struct req rp, rj; | |
164 size_t projectsz = UTIL_SIZE(projects), jobsz = UTIL_SIZE(jobs); | |
165 | |
166 if (argc < 1) | |
167 usage(); | |
168 | |
169 /* First retrieve projects for a better listing. */ | |
170 if ((rp = req_project_list(projects, &projectsz)).status) | |
171 return rp; | |
172 | |
173 if ((rj = req_job_todo(jobs, &jobsz, argv[0])).status) { | |
174 req_finish(&rp); | |
175 return rj; | |
176 } | |
177 | 138 |
178 for (size_t i = 0; i < jobsz; ++i) { | 139 for (size_t i = 0; i < jobsz; ++i) { |
179 const char *project = "unknown"; | 140 printf("%-16s%jd\n", "id:", jobs[i].id); |
180 | |
181 /* Find project if exists (it should). */ | |
182 for (size_t p = 0; p < projectsz; ++p) { | |
183 if (projects[p].id == jobs[i].project_id) { | |
184 project = projects[p].name; | |
185 break; | |
186 } | |
187 } | |
188 | |
189 printf("%-16s%d\n", "id:", jobs[i].id); | |
190 printf("%-16s%s\n", "tag:", jobs[i].tag); | 141 printf("%-16s%s\n", "tag:", jobs[i].tag); |
191 printf("%-16s%s\n", "project:", project); | 142 printf("%-16s%s\n", "project:", jobs[i].project_name); |
192 | 143 |
193 if (i + 1 < jobsz) | 144 if (i + 1 < jobsz) |
194 printf("\n"); | 145 printf("\n"); |
195 } | 146 |
196 | 147 job_finish(&jobs[i]); |
197 req_finish(&rp); | 148 } |
198 | 149 |
199 return rj; | 150 apic_finish(&req); |
200 } | 151 } |
201 | 152 |
202 static struct req | 153 static void |
203 cmd_jobresult_add(int argc, char **argv) | 154 cmd_jobresult_add(int argc, char **argv) |
204 { | 155 { |
205 struct jobresult res = {0}; | 156 struct jobresult res = {0}; |
206 struct worker wk = {0}; | 157 struct apic req; |
207 struct req rw, rj; | |
208 char *log; | |
209 | 158 |
210 if (argc < 5) | 159 if (argc < 5) |
211 usage(); | 160 usage(); |
212 | 161 |
213 /* Find worker id. */ | 162 res.job_id = toint(argv[1]); |
214 if ((rw = req_worker_find(&wk, argv[1])).status) | 163 res.worker_name = util_strdup(argv[2]); |
215 return rw; | 164 res.exitcode = toint(argv[3]); |
216 | 165 res.log = readfile(argv[4]); |
217 res.job_id = strtoll(argv[0], NULL, 10); | 166 |
218 res.exitcode = strtoll(argv[2], NULL, 10); | 167 if (apic_jobresult_add(&req, &res) < 0) |
219 res.worker_id = wk.id; | 168 util_die("abort: unable to add job result: %s\n", req.error); |
220 res.log = log = readfile(argv[3]); | 169 |
221 rj = req_jobresult_add(&res); | 170 apic_finish(&req); |
222 | 171 jobresult_finish(&res); |
223 free(log); | 172 } |
224 req_finish(&rw); | 173 |
225 | 174 static void |
226 return rj; | |
227 } | |
228 | |
229 static struct req | |
230 cmd_project_add(int argc, char **argv) | 175 cmd_project_add(int argc, char **argv) |
231 { | 176 { |
232 struct project pc = {0}; | 177 struct project pc = {0}; |
233 struct req res; | 178 struct apic req; |
234 char *script; | 179 |
180 if (argc < 5) | |
181 usage(); | |
182 | |
183 pc.name = util_strdup(argv[1]); | |
184 pc.desc = util_strdup(argv[2]); | |
185 pc.url = util_strdup(argv[3]); | |
186 pc.script = readfile(argv[4]); | |
187 | |
188 if (apic_project_save(&req, &pc) < 0) | |
189 util_die("abort: unable to create project: %s\n", req.error); | |
190 | |
191 apic_finish(&req); | |
192 project_finish(&pc); | |
193 } | |
194 | |
195 static void | |
196 cmd_project_update(int argc, char **argv) | |
197 { | |
198 struct project pc; | |
199 struct apic req; | |
235 | 200 |
236 if (argc < 4) | 201 if (argc < 4) |
237 usage(); | 202 usage(); |
238 | 203 |
239 pc.name = argv[0]; | 204 if (apic_project_find(&req, &pc, argv[1]) < 0) |
240 pc.desc = argv[1]; | 205 util_die("abort: unable to find project: %s\n", req.error); |
241 pc.url = argv[2]; | 206 |
242 pc.script = script = readfile(argv[3]); | 207 if (strcmp(argv[2], "name") == 0) |
243 res = req_project_add(&pc); | 208 replace(&pc.name, argv[3]); |
244 | 209 else if (strcmp(argv[2], "desc") == 0) |
245 free(script); | 210 replace(&pc.desc, argv[3]); |
246 | 211 else if (strcmp(argv[2], "url") == 0) |
247 return res; | 212 replace(&pc.url, argv[3]); |
248 } | 213 else if (strcmp(argv[2], "script") == 0) |
249 | 214 replace(&pc.script, readfile(argv[3])); |
250 static struct req | 215 |
251 cmd_project_update(int argc, char **argv) | 216 if (apic_project_save(&req, &pc) < 0) |
252 { | 217 util_die("abort: unable to save project: %s\n", req.error); |
253 struct project pc; | 218 |
254 struct req rget, rsend; | 219 apic_finish(&req); |
255 char *script = NULL; | 220 project_finish(&pc); |
256 | 221 } |
257 if (argc < 3) | 222 |
258 help(); | 223 static void |
259 | |
260 if ((rget = req_project_find(&pc, argv[0])).status) | |
261 return rget; | |
262 | |
263 if (strcmp(argv[1], "name") == 0) | |
264 pc.name = argv[2]; | |
265 else if (strcmp(argv[1], "desc") == 0) | |
266 pc.desc = argv[2]; | |
267 else if (strcmp(argv[1], "url") == 0) | |
268 pc.url = argv[2]; | |
269 else if (strcmp(argv[1], "script") == 0) | |
270 pc.script = script = readfile(argv[2]); | |
271 | |
272 rsend = req_project_update(&pc); | |
273 | |
274 req_finish(&rget); | |
275 free(script); | |
276 | |
277 return rsend; | |
278 } | |
279 | |
280 static struct req | |
281 cmd_project_info(int argc, char **argv) | 224 cmd_project_info(int argc, char **argv) |
282 { | 225 { |
283 struct project project = {0}; | 226 struct project project = {0}; |
284 struct req req; | 227 struct apic req; |
285 | 228 |
286 if (argc < 1) | 229 if (argc < 2) |
287 usage(); | 230 usage(); |
288 if ((req = req_project_find(&project, argv[0])).status) | 231 if (apic_project_find(&req, &project, argv[1]) < 0) |
289 return req; | 232 util_die("abort: unable to find project: %s\n", req.error); |
290 | 233 |
291 printf("%-16s%d\n", "id:", project.id); | |
292 printf("%-16s%s\n", "name:", project.name); | 234 printf("%-16s%s\n", "name:", project.name); |
293 printf("%-16s%s\n", "desc:", project.desc); | 235 printf("%-16s%s\n", "desc:", project.desc); |
294 printf("%-16s%s\n", "url:", project.url); | 236 printf("%-16s%s\n", "url:", project.url); |
295 printf("\n"); | 237 printf("\n"); |
296 printf("%s", project.script); | 238 printf("%s", project.script); |
297 | 239 |
298 return req; | 240 apic_finish(&req); |
299 } | 241 project_finish(&project); |
300 | 242 } |
301 static struct req | 243 |
244 static void | |
302 cmd_project_list(int argc, char **argv) | 245 cmd_project_list(int argc, char **argv) |
303 { | 246 { |
304 (void)argc; | 247 (void)argc; |
305 (void)argv; | 248 (void)argv; |
306 | 249 |
307 struct project projects[SCI_PROJECT_MAX] = {0}; | 250 struct project projects[SCI_PROJECT_MAX] = {0}; |
308 struct req req; | 251 struct apic req; |
309 size_t projectsz = UTIL_SIZE(projects); | 252 ssize_t projectsz; |
310 | 253 |
311 if ((req = req_project_list(projects, &projectsz)).status) | 254 if ((projectsz = apic_project_list(&req, projects, UTIL_SIZE(projects))) < 0) |
312 return req; | 255 util_die("abort: unable to list projects: %s\n", req.error); |
313 | 256 |
314 for (size_t i = 0; i < projectsz; ++i) { | 257 for (size_t i = 0; i < projectsz; ++i) { |
315 printf("%-16s%d\n", "id:", projects[i].id); | |
316 printf("%-16s%s\n", "name:", projects[i].name); | 258 printf("%-16s%s\n", "name:", projects[i].name); |
317 printf("%-16s%s\n", "desc:", projects[i].desc); | 259 printf("%-16s%s\n", "desc:", projects[i].desc); |
318 printf("%-16s%s\n", "url:", projects[i].url); | 260 printf("%-16s%s\n", "url:", projects[i].url); |
319 | 261 |
320 if (i + 1 < projectsz) | 262 if (i + 1 < projectsz) |
321 printf("\n"); | 263 printf("\n"); |
322 } | 264 |
323 | 265 project_finish(&projects[i]); |
324 return req; | 266 } |
325 } | 267 |
326 | 268 apic_finish(&req); |
327 static struct req | 269 } |
270 | |
271 static void | |
328 cmd_worker_add(int argc, char **argv) | 272 cmd_worker_add(int argc, char **argv) |
329 { | 273 { |
330 struct worker wk = {0}; | 274 struct worker wk = {0}; |
331 | 275 struct apic req; |
332 if (argc < 2) | 276 |
333 usage(); | 277 if (argc < 3) |
334 | 278 usage(); |
335 wk.name = argv[0]; | 279 |
336 wk.desc = argv[1]; | 280 wk.name = util_strdup(argv[1]); |
337 | 281 wk.desc = util_strdup(argv[2]); |
338 return req_worker_add(&wk); | 282 |
339 } | 283 if (apic_worker_save(&req, &wk) < 0) |
340 | 284 util_die("abort: unable to save worker: %s\n", req.error); |
341 static struct req | 285 |
286 worker_finish(&wk); | |
287 apic_finish(&req); | |
288 } | |
289 | |
290 static void | |
342 cmd_worker_list(int argc, char **argv) | 291 cmd_worker_list(int argc, char **argv) |
343 { | 292 { |
344 (void)argc; | 293 (void)argc; |
345 (void)argv; | 294 (void)argv; |
346 | 295 |
347 struct worker wk[SCI_WORKER_MAX]; | 296 struct worker wk[SCI_WORKER_MAX]; |
348 struct req req; | 297 struct apic req; |
349 size_t wksz = UTIL_SIZE(wk); | 298 ssize_t wksz; |
350 | 299 |
351 if ((req = req_worker_list(wk, &wksz)).status) | 300 if ((wksz = apic_worker_list(&req, wk, UTIL_SIZE(wk))) < 0) |
352 return req; | 301 util_die("abort: unable to list worker: %s\n", req.error); |
353 | 302 |
354 for (size_t i = 0; i < wksz; ++i) { | 303 for (size_t i = 0; i < wksz; ++i) { |
355 printf("%-16s%d\n", "id:", wk[i].id); | |
356 printf("%-16s%s\n", "name:", wk[i].name); | 304 printf("%-16s%s\n", "name:", wk[i].name); |
357 printf("%-16s%s\n", "desc:", wk[i].desc); | 305 printf("%-16s%s\n", "desc:", wk[i].desc); |
358 | 306 |
359 if (i + 1 < wksz) | 307 if (i + 1 < wksz) |
360 printf("\n"); | 308 printf("\n"); |
361 } | 309 |
362 | 310 worker_finish(&wk[i]); |
363 return req; | 311 } |
312 | |
313 apic_finish(&req); | |
364 } | 314 } |
365 | 315 |
366 static struct { | 316 static struct { |
367 const char *name; | 317 const char *name; |
368 struct req (*exec)(int, char **); | 318 void (*exec)(int, char **); |
369 } commands[] = { | 319 } commands[] = { |
370 { "job-add", cmd_job_add }, | 320 { "job-add", cmd_job_add }, |
371 { "job-todo", cmd_job_todo }, | 321 { "job-todo", cmd_job_todo }, |
372 { "jobresult-add", cmd_jobresult_add }, | 322 { "jobresult-add", cmd_jobresult_add }, |
373 { "project-add", cmd_project_add }, | 323 { "project-add", cmd_project_add }, |
380 }; | 330 }; |
381 | 331 |
382 int | 332 int |
383 main(int argc, char **argv) | 333 main(int argc, char **argv) |
384 { | 334 { |
385 int ch, cmdfound = 0; | 335 int ch; |
386 | 336 |
387 setprogname("scictl"); | 337 opterr = 0; |
388 | 338 setenv("POSIXLY_CORRECT", "1", 1); |
389 while ((ch = getopt(argc, argv, "s:")) != -1) { | 339 |
340 while ((ch = getopt(argc, argv, "u:")) != -1) { | |
390 switch (ch) { | 341 switch (ch) { |
391 case 's': | 342 case 'u': |
392 req_set_path(optarg); | 343 util_strlcpy(apiconf.baseurl, optarg, sizeof (apiconf.baseurl)); |
344 break; | |
345 case '?': | |
346 util_die("abort: invalid option: %c\n", ch); | |
347 break; | |
348 case ':': | |
349 util_die("abort: missing value for option %c\n", ch); | |
393 break; | 350 break; |
394 default: | 351 default: |
395 break; | 352 break; |
396 } | 353 } |
397 } | 354 } |
398 | 355 |
399 argc -= optind; | 356 argc -= optind; |
400 argv += optind; | 357 argv += optind; |
401 | 358 |
402 if (argc <= 0) | 359 optind = 1; |
360 | |
361 if (argc < 1) | |
403 usage(); | 362 usage(); |
404 if (strcmp(argv[0], "help") == 0) | 363 if (strcmp(argv[0], "help") == 0) |
405 help(); | 364 help(); |
406 | 365 |
407 for (size_t i = 0; commands[i].name; ++i) { | 366 for (size_t i = 0; commands[i].name; ++i) { |
408 struct req res; | |
409 | |
410 if (strcmp(commands[i].name, argv[0]) == 0) { | 367 if (strcmp(commands[i].name, argv[0]) == 0) { |
411 res = commands[i].exec(--argc, ++argv); | 368 commands[i].exec(argc, argv); |
412 cmdfound = 1; | 369 return 0; |
413 | |
414 if (res.status) | |
415 warnx("%s", json_string_value(json_object_get(res.msg, "error"))); | |
416 | |
417 req_finish(&res); | |
418 break; | |
419 } | 370 } |
420 } | 371 } |
421 | 372 |
422 if (!cmdfound) | 373 util_die("abort: invalid command: %s\n", argv[0]); |
423 errx(1, "abort: command %s not found", argv[0]); | 374 } |
424 } |