Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcoshell/coopen.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
* open a new coshell
26
*/
27
28
#include "colib.h"
29
30
#include <namval.h>
31
#include <proc.h>
32
#include <sfdisc.h>
33
#include <tok.h>
34
35
static const Namval_t options[] =
36
{
37
"cross", CO_CROSS,
38
"debug", CO_DEBUG,
39
"devfd", CO_DEVFD,
40
"ignore", CO_IGNORE,
41
"orphan", CO_ORPHAN,
42
"silent", CO_SILENT,
43
"separate", CO_SEPARATE,
44
"service", CO_SERVICE,
45
0, 0
46
};
47
48
Costate_t state = { "libcoshell:coshell" };
49
50
/*
51
* called when ident sequence hung
52
*/
53
54
static void
55
hung(int sig)
56
{
57
NoP(sig);
58
close(sffileno(state.current->msgfp));
59
}
60
61
/*
62
* close all open coshells
63
*/
64
65
static void
66
clean(void)
67
{
68
coclose(NiL);
69
}
70
71
#ifdef SIGCONT
72
73
/*
74
* pass job control signals to the coshell and self
75
*/
76
77
static void
78
stop(int sig)
79
{
80
cokill(NiL, NiL, sig);
81
signal(sig, SIG_DFL);
82
sigunblock(sig);
83
kill(getpid(), sig);
84
cokill(NiL, NiL, SIGCONT);
85
signal(sig, stop);
86
}
87
88
#endif
89
90
/*
91
* called by stropt() to set options
92
*/
93
94
static int
95
setopt(void* handle, register const void* p, int n, const char* v)
96
{
97
Coshell_t* co = (Coshell_t*)handle;
98
Coservice_t* cs;
99
char* s;
100
char** a;
101
102
NoP(v);
103
if (p)
104
{
105
if (n)
106
{
107
co->flags |= ((Namval_t*)p)->value;
108
if (((Namval_t*)p)->value == CO_SERVICE && v && (cs = vmnewof(co->vm, 0, Coservice_t, 1, 2 * strlen(v))))
109
{
110
a = cs->argv;
111
*a++ = s = cs->path = cs->name = (char*)(cs + 1);
112
while (*s = *v++)
113
if (*s++ == ':')
114
{
115
*(s - 1) = 0;
116
if (*v == '-')
117
{
118
v++;
119
if (*v == '-')
120
v++;
121
}
122
if (strneq(v, "command=", 8))
123
cs->path = s + 8;
124
else if (strneq(v, "state=", 6))
125
cs->db = s + 6;
126
else if (strneq(v, "db=", 3))
127
cs->db = s + 3;
128
else if (a < &cs->argv[elementsof(cs->argv)-2] && *v && *v != ':')
129
{
130
*a++ = s;
131
*s++ = '-';
132
*s++ = '-';
133
}
134
}
135
if (cs->db)
136
*a++ = cs->db;
137
*a = 0;
138
cs->next = co->service;
139
co->service = cs;
140
}
141
}
142
else
143
co->mask |= ((Namval_t*)p)->value;
144
}
145
return 0;
146
}
147
148
Coshell_t*
149
coopen(const char* path, int flags, const char* attributes)
150
{
151
register Coshell_t* co;
152
register char* s;
153
register int i;
154
char* t;
155
int n;
156
Proc_t* proc;
157
Cojob_t* cj;
158
Vmalloc_t* vm;
159
Sfio_t* sp;
160
Sig_handler_t handler;
161
int pio[4];
162
long ops[5];
163
char devfd[16];
164
char evbuf[sizeof(CO_ENV_MSGFD) + 8];
165
char* av[8];
166
char* ev[2];
167
168
static char* sh[] = { 0, 0, "ksh", "sh", "/bin/sh" };
169
170
if (!state.type && (!(s = getenv(CO_ENV_TYPE)) || !(state.type = strdup(s))))
171
state.type = "";
172
if ((flags & CO_ANY) && (co = state.coshells))
173
return co;
174
if (!(vm = vmopen(Vmdcheap, Vmbest, 0)) || !(co = vmnewof(vm, 0, Coshell_t, 1, 0)))
175
{
176
if (vm)
177
vmclose(vm);
178
errormsg(state.lib, ERROR_LIBRARY|2, "out of space");
179
return 0;
180
}
181
co->vm = vm;
182
co->index = ++state.index;
183
stropt(getenv(CO_ENV_OPTIONS), options, sizeof(*options), setopt, co);
184
if (attributes)
185
stropt(attributes, options, sizeof(*options), setopt, co);
186
co->flags |= ((flags | CO_DEVFD) & ~co->mask);
187
if (co->flags & CO_SEPARATE)
188
{
189
co->flags &= ~CO_SEPARATE;
190
co->mode |= CO_MODE_SEPARATE;
191
}
192
co->flags |= CO_INIT;
193
if (co->mode & CO_MODE_SEPARATE)
194
{
195
flags = 0;
196
proc = 0;
197
}
198
else
199
{
200
for (i = 0; i < elementsof(pio); i++)
201
pio[i] = -1;
202
if (pipe(&pio[0]) < 0 || pipe(&pio[2]) < 0)
203
{
204
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot allocate pipes");
205
goto bad;
206
}
207
if (flags & CO_SHELL)
208
for (i = 0; i < elementsof(pio); i++)
209
if (pio[i] < 10 && (n = fcntl(pio[i], F_DUPFD, 10)) >= 0)
210
{
211
close(pio[i]);
212
pio[i] = n;
213
}
214
co->cmdfd = pio[1];
215
co->gsmfd = pio[3];
216
if (!(co->msgfp = sfnew(NiL, NiL, 256, pio[2], SF_READ)))
217
{
218
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot allocate message stream");
219
goto bad;
220
}
221
sfdcslow(co->msgfp);
222
ops[0] = PROC_FD_DUP(pio[0], 0, PROC_FD_PARENT);
223
ops[1] = PROC_FD_CLOSE(pio[1], PROC_FD_CHILD);
224
ops[2] = PROC_FD_CLOSE(pio[2], PROC_FD_CHILD);
225
ops[3] = PROC_FD_CLOSE(pio[3], PROC_FD_PARENT);
226
ops[4] = 0;
227
sfsprintf(devfd, sizeof(devfd), "/dev/fd/%d", pio[0]);
228
flags = !access(devfd, F_OK);
229
}
230
sh[0] = (char*)path;
231
sh[1] = getenv(CO_ENV_SHELL);
232
for (i = 0; i < elementsof(sh); i++)
233
if ((s = sh[i]) && *s && (s = strdup(s)))
234
{
235
if ((n = tokscan(s, NiL, " %v ", av, elementsof(av) - 1)) > 0)
236
{
237
if (t = strrchr(s = av[0], '/'))
238
av[0] = t + 1;
239
if (flags || (co->flags & CO_DEVFD) && strmatch(s, "*ksh*"))
240
av[n++] = devfd;
241
av[n] = 0;
242
sfsprintf(evbuf, sizeof(evbuf), "%s=%d", CO_ENV_MSGFD, co->gsmfd);
243
ev[0] = evbuf;
244
ev[1] = 0;
245
if ((co->mode & CO_MODE_SEPARATE) || (proc = procopen(s, av, ev, ops, (co->flags & (CO_SHELL|CO_ORPHAN)) ? (PROC_ORPHAN|PROC_DAEMON|PROC_IGNORE) : (PROC_DAEMON|PROC_IGNORE))))
246
{
247
if (!state.sh)
248
state.sh = strdup(s);
249
free(s);
250
if (proc)
251
{
252
co->pid = proc->pid;
253
procfree(proc);
254
}
255
break;
256
}
257
}
258
free(s);
259
}
260
if (i >= elementsof(sh))
261
{
262
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot execute");
263
goto bad;
264
}
265
if (!(co->mode & CO_MODE_SEPARATE))
266
{
267
/*
268
* send the shell identification sequence
269
*/
270
271
if (!(sp = sfstropen()))
272
{
273
errormsg(state.lib, ERROR_LIBRARY|2, "out of buffer space");
274
goto bad;
275
}
276
sfprintf(sp, "#%05d\n%s='", 0, CO_ENV_ATTRIBUTES);
277
if (t = getenv(CO_ENV_ATTRIBUTES))
278
{
279
coquote(sp, t, 0);
280
if (attributes)
281
sfprintf(sp, ",");
282
}
283
if (attributes)
284
coquote(sp, attributes, 0);
285
sfprintf(sp, "'\n");
286
sfprintf(sp, coident, CO_ENV_MSGFD, pio[3], CO_ENV_MSGFD, CO_ENV_MSGFD, CO_ENV_MSGFD);
287
i = sfstrtell(sp);
288
sfstrseek(sp, 0, SEEK_SET);
289
sfprintf(sp, "#%05d\n", i - 7);
290
i = write(co->cmdfd, sfstrbase(sp), i) != i;
291
sfstrclose(sp);
292
if (i)
293
{
294
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot write initialization message");
295
goto nope;
296
}
297
state.current = co;
298
handler = signal(SIGALRM, hung);
299
i = alarm(30);
300
if (!(s = sfgetr(co->msgfp, '\n', 1)))
301
{
302
if (errno == EINTR)
303
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "identification message read timeout");
304
goto nope;
305
}
306
alarm(i);
307
signal(SIGALRM, handler);
308
if (co->flags & CO_DEBUG)
309
errormsg(state.lib, 2, "coshell %d shell path %s identification \"%s\"", co->index, state.sh, s);
310
switch (*s)
311
{
312
case 'o':
313
co->flags |= CO_OSH;
314
/*FALLTHROUGH*/
315
case 'b':
316
s = cobinit;
317
break;
318
case 'k':
319
co->flags |= CO_KSH;
320
s = cokinit;
321
break;
322
case 'i': /* NOTE: 'i' is obsolete */
323
case 's':
324
co->flags |= CO_SERVER;
325
co->pid = 0;
326
for (;;)
327
{
328
if (t = strchr(s, ','))
329
*t = 0;
330
if (streq(s, CO_OPT_ACK))
331
co->mode |= CO_MODE_ACK;
332
else if (streq(s, CO_OPT_INDIRECT))
333
co->mode |= CO_MODE_INDIRECT;
334
if (!(s = t))
335
break;
336
s++;
337
}
338
if (!(co->mode & CO_MODE_INDIRECT))
339
wait(NiL);
340
break;
341
default:
342
goto nope;
343
}
344
if (s)
345
{
346
if (!(cj = coexec(co, s, 0, NiL, NiL, NiL)) || cowait(co, cj, -1) != cj)
347
{
348
errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "initialization message exec error");
349
goto nope;
350
}
351
co->total = 0;
352
co->user = 0;
353
co->sys = 0;
354
}
355
}
356
co->flags &= ~CO_INIT;
357
fcntl(pio[1], F_SETFD, FD_CLOEXEC);
358
fcntl(pio[2], F_SETFD, FD_CLOEXEC);
359
co->next = state.coshells;
360
state.coshells = co;
361
if (!(co->flags & CO_SHELL))
362
{
363
#ifdef SIGCONT
364
#ifdef SIGTSTP
365
signal(SIGTSTP, stop);
366
#endif
367
#ifdef SIGTTIN
368
signal(SIGTTIN, stop);
369
#endif
370
#ifdef SIGTTOU
371
signal(SIGTTOU, stop);
372
#endif
373
#endif
374
if (!state.init)
375
{
376
state.init = 1;
377
atexit(clean);
378
}
379
}
380
return co;
381
bad:
382
n = errno;
383
if (co->msgfp)
384
{
385
sfclose(co->msgfp);
386
pio[2] = -1;
387
}
388
for (i = 0; i < elementsof(pio); i++)
389
if (pio[i] >= 0)
390
close(pio[i]);
391
coclose(co);
392
errno = n;
393
return 0;
394
nope:
395
i = errno;
396
if (!(s = sh[1]) || (s = (t = strrchr(s, '/')) ? (t + 1) : s) && !strmatch(s, "?(k)sh") && !streq(s, CO_ID))
397
error(2, "export %s={ksh,sh,%s}", CO_ENV_SHELL, CO_ID);
398
coclose(co);
399
errno = i;
400
return 0;
401
}
402
403
/*
404
* set coshell attributes
405
*/
406
407
int
408
coattr(Coshell_t* co, const char* attributes)
409
{
410
return 0;
411
}
412
413