Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcoshell/coexec.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1990-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* send an action to the coshell for execution
26
*/
27
28
#include "colib.h"
29
30
#include <proc.h>
31
#include <ls.h>
32
33
static Cojob_t*
34
service(register Coshell_t* co, Coservice_t* cs, Cojob_t* cj, int flags, Sfio_t* sp)
35
{
36
Proc_t* proc;
37
size_t n;
38
int i;
39
int j;
40
int fds[2];
41
long ops[4];
42
char* s;
43
char** a;
44
45
if (flags & CO_DEBUG)
46
{
47
for (a = cs->argv; *a; a++)
48
sfprintf(sp, " %s", *a);
49
if (!(s = costash(sp)))
50
goto nospace;
51
errormsg(state.lib, ERROR_LIBRARY|2, "service %s:%s", cs->path, s);
52
}
53
if (pipe(fds) < 0)
54
{
55
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "%s: cannot allocate service pipe", cs->name);
56
return 0;
57
}
58
if (co->flags & CO_SHELL)
59
for (i = 0; i < elementsof(fds); i++)
60
if (fds[i] < 10 && (j = fcntl(fds[i], F_DUPFD, 10)) >= 0)
61
{
62
close(fds[i]);
63
fds[i] = j;
64
}
65
cs->fd = fds[1];
66
ops[0] = PROC_FD_DUP(fds[0], 0, PROC_FD_PARENT);
67
ops[1] = PROC_FD_CLOSE(fds[1], PROC_FD_CHILD);
68
ops[2] = PROC_FD_DUP(co->gsmfd, 1, 0);
69
ops[3] = 0;
70
if (!(proc = procopen(cs->path, cs->argv, NiL, ops, PROC_DAEMON|PROC_IGNORE)))
71
{
72
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "%s: cannot connect to %s service", cs->path, cs->name);
73
close(fds[0]);
74
close(fds[1]);
75
return 0;
76
}
77
fcntl(cs->fd, F_SETFD, FD_CLOEXEC);
78
cs->pid = proc->pid;
79
procfree(proc);
80
sfprintf(sp, "id=%d info\n", cj->id);
81
n = sfstrtell(sp);
82
if (!(s = costash(sp)))
83
goto bad;
84
if (write(cs->fd, s, n) != n || sfpoll(&co->msgfp, 1, 5 * 1000) <= 0)
85
goto bad;
86
cj->pid = 0;
87
cj->status = 0;
88
cj->local = 0;
89
cj->service = cs;
90
co->svc_outstanding++;
91
co->svc_running++;
92
if (!cowait(co, cj, -1))
93
goto bad;
94
return cj;
95
bad:
96
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "%s: service not responding", cs->name);
97
nospace:
98
cj->pid = CO_PID_FREE;
99
cs->pid = 0;
100
close(cs->fd);
101
cs->fd = -1;
102
return 0;
103
}
104
105
static Cojob_t*
106
request(register Coshell_t* co, Cojob_t* cj, Coservice_t* cs, const char* action, int flags)
107
{
108
ssize_t n;
109
ssize_t i;
110
Sfio_t* sp;
111
112
if (!(sp = sfstropen()))
113
{
114
errormsg(state.lib, ERROR_LIBRARY|2, "out of space");
115
return 0;
116
}
117
if (!cs->fd && !service(co, cs, cj, flags, sp))
118
goto bad;
119
if (!cs->pid)
120
goto bad;
121
if (flags & CO_DEBUG)
122
errormsg(state.lib, ERROR_LIBRARY|2, "job %d commands:\n\n%s %s\n", cj->id, cs->name, action);
123
if (!(flags & CO_SILENT))
124
sfprintf(sfstderr, "+ %s %s\n", cs->name, action);
125
sfprintf(sp, "id=%d %s\n", cj->id, action);
126
n = sfstrtell(sp);
127
action = sfstrbase(sp);
128
while ((i = write(cs->fd, action, n)) > 0 && (n -= i) > 0)
129
action += i;
130
sfstrclose(sp);
131
if (n)
132
goto bad;
133
sfclose(sp);
134
cj->pid = 0;
135
cj->status = 0;
136
cj->local = 0;
137
cj->service = cs;
138
co->svc_outstanding++;
139
co->svc_running++;
140
co->total++;
141
return cj;
142
bad:
143
cj->pid = CO_PID_FREE;
144
sfclose(sp);
145
return 0;
146
}
147
148
Cojob_t*
149
coexec(register Coshell_t* co, const char* action, int flags, const char* out, const char* err, const char* att)
150
{
151
register Cojob_t* cj;
152
register Sfio_t* sp;
153
register Coservice_t* cs;
154
int n;
155
int i;
156
int og;
157
int cg;
158
char* s;
159
char* t;
160
char* env;
161
char* red;
162
char* sh[4];
163
struct stat sto;
164
struct stat ste;
165
166
/*
167
* get a free job slot
168
*/
169
170
for (cj = co->jobs; cj; cj = cj->next)
171
if (cj->pid == CO_PID_FREE)
172
break;
173
if (cj)
174
cj->service = 0;
175
else if (!(cj = vmnewof(co->vm, 0, Cojob_t, 1, 0)))
176
return 0;
177
else
178
{
179
cj->coshell = co;
180
cj->pid = CO_PID_FREE;
181
cj->id = ++co->slots;
182
cj->next = co->jobs;
183
co->jobs = cj;
184
}
185
186
/*
187
* set the flags
188
*/
189
190
flags &= ~co->mask;
191
flags |= co->flags;
192
cj->flags = flags;
193
194
/*
195
* check service intercepts
196
*/
197
198
for (cs = co->service; cs; cs = cs->next)
199
{
200
for (s = cs->name, t = (char*)action; *s && *s == *t; s++, t++);
201
if (!*s && *t == ' ')
202
return request(co, cj, cs, t + 1, flags);
203
}
204
cj->flags &= ~CO_SERVICE;
205
red = (cj->flags & CO_APPEND) ? ">>" : ">";
206
207
/*
208
* package the action
209
*/
210
211
if (!(env = coinitialize(co, co->flags)))
212
return 0;
213
if (!(sp = sfstropen()))
214
return 0;
215
n = strlen(action);
216
if (co->flags & CO_SERVER)
217
{
218
/*
219
* leave it to server
220
*/
221
222
sfprintf(sp, "#%05d\ne %d %d %s %s %s",
223
0,
224
cj->id,
225
cj->flags,
226
state.pwd,
227
out,
228
err);
229
if (att)
230
sfprintf(sp, " (%d:%s)", strlen(att), att);
231
else
232
sfprintf(sp, " %s", att);
233
sfprintf(sp, " (%d:%s) (%d:%s)\n", strlen(env), env, n, action);
234
}
235
else if (co->flags & CO_INIT)
236
{
237
if (flags & CO_DEBUG)
238
sfprintf(sp, "set -x\n");
239
sfprintf(sp, "%s%s\necho x %d $? >&$%s\n",
240
env,
241
action,
242
cj->id,
243
CO_ENV_MSGFD);
244
}
245
else if (flags & CO_KSH)
246
{
247
#if !_lib_fork && defined(_map_spawnve)
248
Sfio_t* tp;
249
250
tp = sp;
251
if (!(sp = sfstropen()))
252
sp = tp;
253
#endif
254
sfprintf(sp, "{\ntrap 'set %s$?; trap \"\" 0; IFS=\"\n\"; print -u$%s x %d $1 $(times); exit $1' 0 HUP INT QUIT TERM%s\n%s%s%s",
255
(flags & CO_SILENT) ? "" : "+x ",
256
CO_ENV_MSGFD,
257
cj->id,
258
(flags & CO_IGNORE) ? "" : " ERR",
259
env,
260
n > CO_MAXEVAL ? "" : "eval '",
261
(flags & CO_SILENT) ? "" : "set -x\n");
262
if (n > CO_MAXEVAL)
263
sfputr(sp, action, -1);
264
else
265
{
266
coquote(sp, action, 0);
267
sfprintf(sp, "\n'");
268
}
269
sfprintf(sp, "\n} </dev/null");
270
if (out)
271
{
272
if (*out == '/')
273
sfprintf(sp, " %s%s", red, out);
274
else
275
sfprintf(sp, " %s%s/%s", red, state.pwd, out);
276
}
277
else if ((flags & CO_SERIALIZE) && (cj->out = pathtemp(NiL, 64, NiL, "coo", NiL)))
278
sfprintf(sp, " >%s", cj->out);
279
if (err)
280
{
281
if (out && streq(out, err))
282
sfprintf(sp, " 2>&1");
283
else if (*err == '/')
284
sfprintf(sp, " 2%s%s", red, err);
285
else
286
sfprintf(sp, " 2%s%s/%s", red, state.pwd, err);
287
}
288
else if (flags & CO_SERIALIZE)
289
{
290
if (!out && !fstat(1, &sto) && !fstat(2, &ste) && sto.st_dev == ste.st_dev && sto.st_ino == ste.st_ino)
291
sfprintf(sp, " 2>&1");
292
else if (cj->err = pathtemp(NiL, 64, NiL, "coe", NiL))
293
sfprintf(sp, " 2>%s", cj->err);
294
}
295
#if !_lib_fork && defined(_map_spawnve)
296
if (sp != tp)
297
{
298
sfprintf(tp, "%s -c '", state.sh);
299
if (!(s = costash(sp)))
300
return 0;
301
coquote(tp, s, 0);
302
sfprintf(tp, "'");
303
sfstrclose(sp);
304
sp = tp;
305
}
306
#endif
307
sfprintf(sp, " &\nprint -u$%s j %d $!\n",
308
CO_ENV_MSGFD,
309
cj->id);
310
}
311
else
312
{
313
#if !_lib_fork && defined(_map_spawnve)
314
Sfio_t* tp;
315
316
tp = sp;
317
if (!(sp = sfstropen())) sp = tp;
318
#endif
319
flags |= CO_IGNORE;
320
if (co->mode & CO_MODE_SEPARATE)
321
{
322
flags &= ~CO_SERIALIZE;
323
og = '{';
324
cg = '}';
325
}
326
else
327
{
328
og = '(';
329
cg = ')';
330
}
331
sfprintf(sp, "%c\n%s%sset -%s%s\n",
332
og,
333
env,
334
n > CO_MAXEVAL ? "" : "eval '",
335
(flags & CO_IGNORE) ? "" : "e",
336
(flags & CO_SILENT) ? "" : "x");
337
if (n > CO_MAXEVAL)
338
sfprintf(sp, "%s", action);
339
else
340
{
341
coquote(sp, action, 0);
342
sfprintf(sp, "\n'");
343
}
344
sfprintf(sp, "\n%c </dev/null", cg);
345
if (out)
346
{
347
if (*out == '/')
348
sfprintf(sp, " %s%s", red, out);
349
else
350
sfprintf(sp, " %s%s/%s", red, state.pwd, out);
351
}
352
else if ((flags & CO_SERIALIZE) && (cj->out = pathtemp(NiL, 64, NiL, "coo", NiL)))
353
sfprintf(sp, " >%s", cj->out);
354
if (err)
355
{
356
if (out && streq(out, err))
357
sfprintf(sp, " 2>&1");
358
else if (*err == '/')
359
sfprintf(sp, " 2%s%s", red, err);
360
else
361
sfprintf(sp, " 2%s%s/%s", red, state.pwd, err);
362
}
363
else if (flags & CO_SERIALIZE)
364
{
365
if (out)
366
sfprintf(sp, " 2>&1");
367
else if (cj->err = pathtemp(NiL, 64, NiL, "coe", NiL))
368
sfprintf(sp, " 2>%s", cj->err);
369
}
370
if (!(co->mode & CO_MODE_SEPARATE))
371
{
372
if (flags & CO_OSH)
373
sfprintf(sp, " && echo x %d 0 >&$%s || echo x %d $? >&$%s",
374
cj->id,
375
CO_ENV_MSGFD,
376
cj->id,
377
CO_ENV_MSGFD);
378
else
379
sfprintf(sp, " && echo x %d 0 `times` >&$%s || echo x %d $? `times` >&$%s",
380
cj->id,
381
CO_ENV_MSGFD,
382
cj->id,
383
CO_ENV_MSGFD);
384
}
385
#if !_lib_fork && defined(_map_spawnve)
386
if (sp != tp)
387
{
388
sfprintf(tp, "%s -c '", state.sh);
389
if (!(s = costash(sp)))
390
return 0;
391
coquote(tp, s, 0);
392
sfprintf(tp, "'");
393
sfstrclose(sp);
394
sp = tp;
395
}
396
#endif
397
if (!(co->mode & CO_MODE_SEPARATE))
398
sfprintf(sp, " &\necho j %d $! >&$%s\n",
399
cj->id,
400
CO_ENV_MSGFD);
401
}
402
n = sfstrtell(sp);
403
if (!costash(sp))
404
return 0;
405
if (flags & CO_SERVER)
406
sfprintf(sp, "#%05d\n", n - 7);
407
s = sfstrseek(sp, 0, SEEK_SET);
408
if (flags & CO_DEBUG)
409
errormsg(state.lib, ERROR_LIBRARY|2, "job %d commands:\n\n%s\n", cj->id, s);
410
if (co->mode & CO_MODE_SEPARATE)
411
{
412
sh[0] = state.sh;
413
sh[1] = "-c";
414
sh[2] = s;
415
sh[3] = 0;
416
cj->status = procrun(state.sh, sh, 0);
417
sfstrclose(sp);
418
cj->pid = CO_PID_ZOMBIE;
419
cj->local = 0;
420
co->outstanding++;
421
co->total++;
422
}
423
else
424
{
425
/*
426
* send it off
427
*/
428
429
while ((i = write(co->cmdfd, s, n)) > 0 && (n -= i) > 0)
430
s += i;
431
sfstrclose(sp);
432
if (n)
433
return 0;
434
435
/*
436
* it's a job
437
*/
438
439
cj->pid = 0;
440
cj->status = 0;
441
cj->local = 0;
442
co->outstanding++;
443
co->running++;
444
co->total++;
445
if (co->mode & CO_MODE_ACK)
446
cj = cowait(co, cj, -1);
447
}
448
return cj;
449
}
450
451