comparison scictl.c @ 3:215c0c3b3609

misc: use JSON everywhere (scictl/sciwebd)
author David Demelier <markand@malikania.fr>
date Mon, 14 Jun 2021 22:08:24 +0200
parents 5fa3d2f479b2
children 9c4fea43803c
comparison
equal deleted inserted replaced
2:5fa3d2f479b2 3:215c0c3b3609
1 #define _BSD_SOURCE
2 #include <err.h> 1 #include <err.h>
3 #include <stdio.h> 2 #include <stdio.h>
4 #include <stdlib.h> 3 #include <stdlib.h>
5 #include <string.h> 4 #include <string.h>
6 #include <stdnoreturn.h> 5 #include <stdnoreturn.h>
7 #include <unistd.h> 6 #include <unistd.h>
8 7
9 #include "config.h" 8 #include "config.h"
10 #include "project.h"
11 #include "job.h"
12 #include "req.h" 9 #include "req.h"
10 #include "types.h"
13 #include "util.h" 11 #include "util.h"
14 #include "worker.h"
15 12
16 noreturn static void 13 noreturn static void
17 usage(void) 14 usage(void)
18 { 15 {
19 fprintf(stderr, "usage: %s [-s sock] command [args...]\n", getprogname()); 16 fprintf(stderr, "usage: %s [-s sock] command [args...]\n", getprogname());
21 } 18 }
22 19
23 noreturn static void 20 noreturn static void
24 help(void) 21 help(void)
25 { 22 {
26 fprintf(stderr, "usage: %s job-queue project tag\n", getprogname()); 23 fprintf(stderr, "usage: %s job-add project tag\n", getprogname());
27 fprintf(stderr, " %s job-list worker\n", getprogname()); 24 fprintf(stderr, " %s job-todo worker\n", getprogname());
28 fprintf(stderr, " %s job-save id worker status retcode console\n", getprogname()); 25 fprintf(stderr, " %s jobresult-add id worker exitcode console\n", getprogname());
29 fprintf(stderr, " %s project-add name desc url script\n", getprogname()); 26 fprintf(stderr, " %s project-add name desc url script\n", getprogname());
30 fprintf(stderr, " %s project-list\n", getprogname()); 27 fprintf(stderr, " %s project-list\n", getprogname());
31 fprintf(stderr, " %s script-get project\n", getprogname());
32 fprintf(stderr, " %s worker-add name desc\n", getprogname()); 28 fprintf(stderr, " %s worker-add name desc\n", getprogname());
33 fprintf(stderr, " %s worker-list\n", getprogname()); 29 fprintf(stderr, " %s worker-list\n", getprogname());
34 exit(0); 30 exit(0);
35 } 31 }
36 32
37 static char * 33 static char *
38 readfile(const char *path) 34 readfile(const char *path)
39 { 35 {
40 FILE *fp, *str; 36 FILE *fp, *str;
41 static char console[SCI_MSG_MAX]; 37 char buf[BUFSIZ], *console;
42 char buf[BUFSIZ], *ret = console;
43 size_t nr; 38 size_t nr;
44 39
45 if (strcmp(path, "-") == 0) 40 if (strcmp(path, "-") == 0)
46 fp = stdin; 41 fp = stdin;
47 else if (!(fp = fopen(path, "r"))) 42 else if (!(fp = fopen(path, "r")))
48 err(1, "%s", path); 43 err(1, "%s", path);
49 44
50 if (!(str = fmemopen(console, sizeof (console), "w"))) 45 console = util_calloc(1, SCI_MSG_MAX);
46
47 if (!(str = fmemopen(console, SCI_MSG_MAX, "w")))
51 err(1, "fmemopen"); 48 err(1, "fmemopen");
52 49
53 while ((nr = fread(buf, 1, sizeof (buf), fp)) > 0) 50 while ((nr = fread(buf, 1, sizeof (buf), fp)) > 0)
54 fwrite(buf, 1, nr, str); 51 fwrite(buf, 1, nr, str);
55 52
56 if ((ferror(fp) && !feof(fp)) || (ferror(str) && !feof(str))) 53 if ((ferror(fp) && !feof(fp)) || (ferror(str) && !feof(str))) {
57 ret = NULL; 54 free(console);
55 console = NULL;
56 }
58 57
59 fclose(str); 58 fclose(str);
60 fclose(fp); 59 fclose(fp);
61 60
62 return ret; 61 return console;
63 } 62 }
64 63
65 static struct req 64 static struct req
66 cmd_job_queue(int argc, char **argv) 65 cmd_job_add(int argc, char **argv)
67 { 66 {
68 struct job job = {0}; 67 struct job job = {0};
68 struct project project = {0};
69 struct req rp, rj;
69 70
70 if (argc < 2) 71 if (argc < 2)
71 usage(); 72 usage();
72 73
73 strlcpy(job.project.name, argv[0], sizeof (job.project.name)); 74 if ((rp = req_project_find(&project, argv[0])).status)
74 strlcpy(job.tag, argv[1], sizeof (job.tag)); 75 return rp;
75 76
76 return req_job_queue(&job); 77 job.project_id = project.id;
77 } 78 job.tag = argv[1];
78 79
79 static struct req 80 rj = req_job_add(&job);
80 cmd_job_list(int argc, char **argv) 81 req_finish(&rp);
81 { 82
82 struct job_result jobs[SCI_JOB_LIST_MAX]; 83 return rj;
83 size_t jobsz = UTIL_SIZE(jobs); 84 }
85
86 static struct req
87 cmd_job_todo(int argc, char **argv)
88 {
89 struct project projects[SCI_PROJECT_MAX] = {0};
90 struct job jobs[SCI_JOB_LIST_MAX] = {0};
91 struct req rp, rj;
92 size_t projectsz = UTIL_SIZE(projects), jobsz = UTIL_SIZE(jobs);
93
94 if (argc < 1)
95 usage();
96
97 /* First retrieve projects for a better listing. */
98 if ((rp = req_project_list(projects, &projectsz)).status)
99 return rp;
100
101 if ((rj = req_job_todo(jobs, &jobsz, argv[0])).status) {
102 req_finish(&rp);
103 return rj;
104 }
105
106 for (size_t i = 0; i < jobsz; ++i) {
107 const char *project = "unknown";
108
109 /* Find project if exists (it should). */
110 for (size_t i = 0; i < projectsz; ++i) {
111 if (projects[i].id == jobs[i].project_id) {
112 project = projects[i].name;
113 break;
114 }
115 }
116
117 printf("%-16s%d\n", "id:", jobs[i].id);
118 printf("%-16s%s\n", "tag:", jobs[i].tag);
119 printf("%-16s%s\n", "project:", project);
120
121 if (i + 1 < jobsz)
122 printf("\n");
123 }
124
125 req_finish(&rp);
126
127 return rj;
128 }
129
130 static struct req
131 cmd_jobresult_add(int argc, char **argv)
132 {
133 struct jobresult res = {0};
134 struct worker wk = {0};
135 struct req rw, rj;
136 char *log;
137
138 if (argc < 5)
139 usage();
140
141 /* Find worker id. */
142 if ((rw = req_worker_find(&wk, argv[1])).status)
143 return rw;
144
145 res.job_id = strtoll(argv[0], NULL, 10);
146 res.exitcode = strtoll(argv[2], NULL, 10);
147 res.worker_id = wk.id;
148 res.log = log = readfile(argv[3]);
149 rj = req_jobresult_add(&res);
150
151 free(log);
152 req_finish(&rw);
153
154 return rj;
155 }
156
157 static struct req
158 cmd_project_add(int argc, char **argv)
159 {
160 struct project pc = {0};
161 struct req res;
162 char *script;
163
164 if (argc < 4)
165 usage();
166
167 pc.name = argv[0];
168 pc.desc = argv[1];
169 pc.url = argv[2];
170 pc.script = script = readfile(argv[3]);
171 res = req_project_add(&pc);
172
173 free(script);
174
175 return res;
176 }
177
178 static struct req
179 cmd_project_find(int argc, char **argv)
180 {
181 struct project project = {0};
84 struct req req; 182 struct req req;
85 183
86 if (argc < 1) 184 if (argc < 1)
87 usage(); 185 usage();
88 186 if ((req = req_project_find(&project, argv[0])).status)
89 if ((req = req_job_list(jobs, &jobsz, argv[0])).status)
90 return req; 187 return req;
91 188
92 printf("%-16s%-16s%s\n", "ID", "TAG", "PROJECT"); 189 printf("%-16s%s\n", "name:", project.name);
93 190 printf("%-16s%s\n", "desc:", project.desc);
94 for (size_t i = 0; i < jobsz; ++i) { 191 printf("%-16s%s\n", "url:", project.url);
95 printf("%-16lld%-16s%s\n", (long long int)jobs[i].job.id, 192 printf("\n");
96 jobs[i].job.tag, jobs[i].job.project.name); 193 printf("%s", project.script);
97 }
98 194
99 return req; 195 return req;
100 }
101
102 static struct req
103 cmd_job_save(int argc, char **argv)
104 {
105 struct job_result res = {0};
106
107 if (argc < 5)
108 usage();
109
110 res.job.id = strtoll(argv[0], NULL, 10);
111 res.status = strtoll(argv[2], NULL, 10);
112 res.retcode = strtoll(argv[3], NULL, 10);
113 res.console = readfile(argv[4]);
114 strlcpy(res.worker.name, argv[1], sizeof (res.worker.name));
115
116 return req_job_save(&res);
117 }
118
119 static struct req
120 cmd_project_add(int argc, char **argv)
121 {
122 struct project pc;
123
124 if (argc < 4)
125 usage();
126
127 memset(&pc, 0, sizeof (pc));
128 strlcpy(pc.name, argv[0], sizeof (pc.name));
129 strlcpy(pc.desc, argv[1], sizeof (pc.desc));
130 strlcpy(pc.url, argv[2], sizeof (pc.url));
131 strlcpy(pc.script, argv[3], sizeof (pc.script));
132
133 return req_project_add(&pc);
134 } 196 }
135 197
136 static struct req 198 static struct req
137 cmd_project_list(int argc, char **argv) 199 cmd_project_list(int argc, char **argv)
138 { 200 {
139 (void)argc; 201 (void)argc;
140 (void)argv; 202 (void)argv;
141 203
142 struct project pc[SCI_PROJECT_MAX]; 204 struct project projects[SCI_PROJECT_MAX] = {0};
143 struct req req; 205 struct req req;
144 size_t pcsz = UTIL_SIZE(pc); 206 size_t projectsz = UTIL_SIZE(projects);
145 207
146 memset(pc, 0, sizeof (pc)); 208 if ((req = req_project_list(projects, &projectsz)).status)
147
148 if ((req = req_project_list(pc, &pcsz)).status)
149 return req; 209 return req;
150 210
151 printf("%-16s%-24s%-20s%s\n", "NAME", "DESCRIPTION", "URL", "SCRIPT"); 211 for (size_t i = 0; i < projectsz; ++i) {
152 212 printf("%-16s%s\n", "name:", projects[i].name);
153 for (size_t i = 0; i < pcsz; ++i) 213 printf("%-16s%s\n", "desc:", projects[i].desc);
154 printf("%-16s%-24s%-20s%s\n", pc[i].name, pc[i].desc, 214 printf("%-16s%s\n", "url:", projects[i].url);
155 pc[i].url, pc[i].script); 215
216 if (i + 1 < projectsz)
217 printf("\n");
218 }
156 219
157 return req; 220 return req;
158 } 221 }
159 222
160 static struct req 223 static struct req
161 cmd_script_get(int argc, char **argv)
162 {
163 char script[SCI_MSG_MAX];
164 struct req req;
165
166 if (argc < 1)
167 usage();
168 if ((req = req_script_get(argv[0], script, sizeof (script))).status)
169 return req;
170
171 printf("%s", script);
172
173 /*
174 * Don't break up the terminal output if the script does not contain a
175 * final new line.
176 */
177 if (script[strlen(script) - 1] != '\n')
178 printf("\n");
179
180 return req;
181 }
182
183 static struct req
184 cmd_worker_add(int argc, char **argv) 224 cmd_worker_add(int argc, char **argv)
185 { 225 {
186 struct worker wk; 226 struct worker wk = {0};
187 227
188 if (argc < 2) 228 if (argc < 2)
189 usage(); 229 usage();
190 230
191 memset(&wk, 0, sizeof (wk)); 231 wk.name = argv[0];
192 strlcpy(wk.name, argv[0], sizeof (wk.name)); 232 wk.desc = argv[1];
193 strlcpy(wk.desc, argv[1], sizeof (wk.desc));
194 233
195 return req_worker_add(&wk); 234 return req_worker_add(&wk);
196 } 235 }
197 236
198 static struct req 237 static struct req
206 size_t wksz = UTIL_SIZE(wk); 245 size_t wksz = UTIL_SIZE(wk);
207 246
208 if ((req = req_worker_list(wk, &wksz)).status) 247 if ((req = req_worker_list(wk, &wksz)).status)
209 return req; 248 return req;
210 249
211 printf("%-16s%s\n", "NAME", "DESCRIPTION"); 250 for (size_t i = 0; i < wksz; ++i) {
212 251 printf("%-16s%s\n", "name:", wk[i].name);
213 for (size_t i = 0; i < wksz; ++i) 252 printf("%-16s%s\n", "desc:", wk[i].desc);
214 printf("%-16s%s\n", wk[i].name, wk[i].desc); 253
254 if (i + 1 < wksz)
255 printf("\n");
256 }
215 257
216 return req; 258 return req;
217 } 259 }
218 260
219 static struct { 261 static struct {
220 const char *name; 262 const char *name;
221 struct req (*exec)(int, char **); 263 struct req (*exec)(int, char **);
222 } commands[] = { 264 } commands[] = {
223 { "job-queue", cmd_job_queue }, 265 { "job-add", cmd_job_add },
224 { "job-list", cmd_job_list }, 266 { "job-todo", cmd_job_todo },
225 { "job-save", cmd_job_save }, 267 { "jobresult-add", cmd_jobresult_add },
226 { "project-add", cmd_project_add }, 268 { "project-add", cmd_project_add },
269 { "project-find", cmd_project_find },
227 { "project-list", cmd_project_list }, 270 { "project-list", cmd_project_list },
228 { "script-get", cmd_script_get },
229 { "worker-add", cmd_worker_add }, 271 { "worker-add", cmd_worker_add },
230 { "worker-list", cmd_worker_list }, 272 { "worker-list", cmd_worker_list },
231 { NULL, NULL } 273 { NULL, NULL }
232 }; 274 };
233 275
234 int 276 int
235 main(int argc, char **argv) 277 main(int argc, char **argv)
236 { 278 {
237 const char *sock = VARDIR "/run/sci.sock";
238 int ch, cmdfound = 0; 279 int ch, cmdfound = 0;
239 280
240 setprogname("scictl"); 281 setprogname("scictl");
241 282
242 while ((ch = getopt(argc, argv, "s:")) != -1) { 283 while ((ch = getopt(argc, argv, "s:")) != -1) {
243 switch (ch) { 284 switch (ch) {
244 case 's': 285 case 's':
245 sock = optarg; 286 req_set_path(optarg);
246 break; 287 break;
247 default: 288 default:
248 break; 289 break;
249 } 290 }
250 } 291 }
254 295
255 if (argc <= 0) 296 if (argc <= 0)
256 usage(); 297 usage();
257 if (strcmp(argv[0], "help") == 0) 298 if (strcmp(argv[0], "help") == 0)
258 help(); 299 help();
259 if (req_connect(sock) < 0)
260 err(1, "%s", sock);
261 300
262 for (size_t i = 0; commands[i].name; ++i) { 301 for (size_t i = 0; commands[i].name; ++i) {
263 struct req res; 302 struct req res;
264 303
265 if (strcmp(commands[i].name, argv[0]) == 0) { 304 if (strcmp(commands[i].name, argv[0]) == 0) {
266 res = commands[i].exec(--argc, ++argv); 305 res = commands[i].exec(--argc, ++argv);
267 cmdfound = 1; 306 cmdfound = 1;
268 307
308 #if 0
269 if (res.status) 309 if (res.status)
270 warnx("%s", res.msg); 310 warnx("%s", res.msg);
271 311 #endif
312
313 req_finish(&res);
272 break; 314 break;
273 } 315 }
274 } 316 }
275 317
276 if (!cmdfound) 318 if (!cmdfound)
277 errx(1, "abort: command %s not found", argv[0]); 319 errx(1, "abort: command %s not found", argv[0]);
278 320 }
279 req_finish();
280 }