Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/3d/init.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2012 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
* David Korn <[email protected]> *
19
* Eduardo Krell <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
24
/*
25
* 3d file system initialization
26
*/
27
28
#include "3d.h"
29
30
static const char id[] =
31
#if defined(__STDC__) || defined(__STDPP__)
32
"\n@(#)$Id: 3d [ "
33
#if DEBUG
34
"debug "
35
#endif
36
#if FS
37
"msg "
38
#endif
39
"safe "
40
#if VCS
41
"vcs "
42
#endif
43
"] (AT&T Research) 2012-06-25 $\0\n"
44
#else
45
"\n@(#)$Id: 3d (AT&T Research) 2011-06-25 $\0\n"
46
#endif
47
;
48
49
/*
50
* if _3d_2d!=0 && getenv(_3d_2d)==0 then 2d
51
*/
52
53
char* _3d_2d = 0;
54
55
/*
56
* 3d mount get and set access functions
57
*/
58
59
static int
60
get_fs(Fs_t* gs, register char* buf, const char* op, int flags)
61
{
62
register Fs_t* fs;
63
register int n;
64
register int sum = 0;
65
register unsigned long x;
66
int m;
67
#if FS
68
Mount_t* mp;
69
#endif
70
71
x = op ? getkey(op, op + strlen(op), 0) : 0;
72
for (fs = state.fs; fs < state.fs + elementsof(state.fs); fs++)
73
if (!(fs->flags & (FS_ERROR|FS_INIT)) && (fs->flags & (FS_BOUND|FS_OPEN)) && (!x || x == fs->key))
74
{
75
if (buf)
76
{
77
if (fs->flags & FS_BOUND) n = sfsprintf(buf, 0, "%-*s", fs->servicesize ? fs->servicesize : strlen(fs->service), fs->service);
78
else n = sfsprintf(buf, 0, "-");
79
n += sfsprintf(buf + n, 0, " /#%s/%s", gs->special, fs->special);
80
m = n;
81
#if FS
82
if (fs->ack)
83
{
84
n += sfsprintf(buf + n, 0, "/ack=");
85
n += msggetmask(buf + n, SHRT_MAX, fs->ack);
86
}
87
if (fs->call != ~0)
88
{
89
n += sfsprintf(buf + n, 0, "/call=");
90
n += msggetmask(buf + n, SHRT_MAX, fs->call);
91
}
92
if (fs->flags & FS_CLOSE)
93
n += sfsprintf(buf + n, 0, "/close");
94
if (fs->flags & FS_FLUSH)
95
n += sfsprintf(buf + n, 0, "/flush");
96
if (fs->flags & FS_GLOBAL)
97
{
98
n += sfsprintf(buf + n, 0, "/global");
99
if (!(fs->flags & FS_ACTIVE))
100
for (mp = state.global; mp; mp = mp->global)
101
if (mp->fs == fs && mp->channel && mp->channel != -1)
102
{
103
n += sfsprintf(buf + n, 0, "=%d.%d", state.pid, MSG_CHANNEL_SYS(mp->channel));
104
break;
105
}
106
}
107
if (fs->flags & FS_INTERACTIVE)
108
n += sfsprintf(buf + n, 0, "/interactive");
109
if (fs->match)
110
n += sfsprintf(buf + n, 0, "/match=%-*s", fs->matchsize ? fs->matchsize : strlen(fs->match), fs->match);
111
if (fs->flags & FS_MONITOR)
112
n += sfsprintf(buf + n, 0, "/monitor");
113
if (fs->flags & FS_NAME)
114
n += sfsprintf(buf + n, 0, "/name");
115
if (!(fs->flags & FS_ON))
116
n += sfsprintf(buf + n, 0, "/off");
117
if (fs->flags & FS_RECEIVE)
118
n += sfsprintf(buf + n, 0, "/receive");
119
if (fs->flags & FS_REGULAR)
120
n += sfsprintf(buf + n, 0, "/regular");
121
if (fs->retry)
122
n += sfsprintf(buf + n, 0, "/retry=%d", fs->retry);
123
if (fs->terse)
124
{
125
n += sfsprintf(buf + n, 0, "/terse=");
126
n += msggetmask(buf + n, SHRT_MAX, fs->terse);
127
}
128
if (fs->flags & FS_UNIQUE)
129
n += sfsprintf(buf + n, 0, "/unique");
130
if (fs->flags & FS_WRITE)
131
n += sfsprintf(buf + n, 0, "/write");
132
n += getattr(fs->attr, buf + n);
133
#endif
134
if ((flags & (MAP_EXEC|MAP_INIT)) && (fs->flags & FS_OPEN))
135
{
136
if (!(fs->flags & FS_CLOSE))
137
{
138
if (fs->fd >= RESERVED_FD)
139
n += sfsprintf(buf + n, 0, "/fd=%d", fs->fd);
140
}
141
else if ((flags & MAP_EXEC) && !(fs->flags & FS_BOUND))
142
n = 0;
143
}
144
if (n > m || (fs->flags & FS_BOUND))
145
{
146
buf += n++;
147
*buf++ = ' ';
148
}
149
else n = 0;
150
}
151
else n = ((fs->flags & FS_BOUND) ? (fs->servicesize ? fs->servicesize : strlen(fs->service)) : 0) +
152
gs->specialsize +
153
fs->specialsize +
154
#if FS
155
(fs->ack ? (msggetmask(NiL, 0, fs->ack) + 6) : 0) +
156
(fs->call != ~0 ? (msggetmask(NiL, 0, fs->call) + 6) : 0) +
157
((fs->flags & FS_CLOSE) ? 6 : 0) +
158
((fs->flags & FS_FLUSH) ? 6 : 0) +
159
((fs->flags & FS_GLOBAL) ? ((fs->flags & (FS_ACTIVE|FS_CLOSE)) ? 7 : 22) : 0) +
160
((fs->flags & FS_INTERACTIVE) ? 11 : 0) +
161
(fs->match ? ((fs->matchsize ? fs->matchsize : strlen(fs->match)) + 7) : 0) +
162
((fs->flags & FS_MONITOR) ? 0 : 8) +
163
((fs->flags & FS_NAME) ? 5 : 0) +
164
((fs->flags & FS_ON) ? 0 : 3) +
165
((fs->flags & FS_RECEIVE) ? 0 : 8) +
166
((fs->flags & FS_REGULAR) ? 0 : 8) +
167
(fs->retry ? 12 : 0) +
168
(fs->terse ? (msggetmask(NiL, 0, fs->terse) + 8) : 0) +
169
((fs->flags & FS_UNIQUE) ? 0 : 7) +
170
((fs->flags & FS_WRITE) ? 0 : 6) +
171
getattr(fs->attr, NiL) +
172
#endif
173
((flags & (MAP_EXEC|MAP_INIT)) && (fs->flags & (FS_CLOSE|FS_OPEN)) == FS_OPEN ? 10 : 0) +
174
6;
175
sum += n;
176
if (op)
177
{
178
state.visit.fs = fs;
179
break;
180
}
181
}
182
n = iterate(&state.vmount, mapget, buf, flags);
183
if (buf) buf += n;
184
sum += n;
185
state.visit.fs = 0;
186
return(sum);
187
}
188
189
/*
190
* return mask for msg calls in state.key.*
191
*/
192
193
static unsigned long
194
getmsgmask(const char* e)
195
{
196
register char* s;
197
register char* t;
198
register int c;
199
register unsigned long x = ~0;
200
201
if (!(s = state.key.invert)) s = state.key.value;
202
if (s != state.one)
203
{
204
for (t = s; t < (char*)e; t++)
205
if (*t == '/')
206
break;
207
if (c = *t) *t = 0;
208
x = msgsetmask(s);
209
if (c) *t = c;
210
}
211
return(state.key.invert ? ~x : x);
212
}
213
214
static int
215
set_fs(register Fs_t* fs, const char* arg, int argsize, const char* op, int opsize)
216
{
217
register Fs_t* ff;
218
register unsigned long x;
219
int n;
220
int old;
221
const char* oe;
222
#if FS
223
Mount_t* mp;
224
Mount_t* pm;
225
#endif
226
227
oe = op + (opsize ? opsize : strlen(op));
228
if (!(x = getkey(op, oe, 0)))
229
{
230
if (!*arg)
231
while (state.vmount.table->key)
232
search(&state.vmount, state.vmount.table->key, state.vmount.table->keysize, NiL, T_DELETE);
233
return(0);
234
}
235
for (ff = 0, fs = state.fs; fs < state.fs + elementsof(state.fs); fs++)
236
if ((fs->flags & (FS_BOUND|FS_INTERNAL)) && fs->key == x) break;
237
else if (!ff && !fs->flags) ff = fs;
238
if (fs >= state.fs + elementsof(state.fs))
239
{
240
if (!*arg && !state.key.next) return(0);
241
if (!(fs = ff)) return(-1);
242
fs->specialsize = state.key.next ? (state.key.next - (char*)op - 1) : opsize ? opsize : strlen(op);
243
if (fs->specialsize >= elementsof(fs->special))
244
fs->specialsize = elementsof(fs->special) - 1;
245
strncpy(fs->special, op, fs->specialsize);
246
fs->special[fs->specialsize] = 0;
247
fs->key = x;
248
fs->call = ~0;
249
old = 0;
250
}
251
else if (!*arg && !state.key.next)
252
{
253
fsdrop(fs, 1);
254
return(0);
255
}
256
else old = 1;
257
if (*arg)
258
{
259
n = argsize ? argsize : strlen(arg);
260
if (!fs->service || (fs->servicesize ? fs->servicesize : strlen(fs->service)) != n || strncmp(arg, fs->service, n))
261
{
262
fsdrop(fs, 1);
263
if (fs->servicesize = argsize) fs->service = (char*)arg;
264
else fs->service = strcpy(newof(0, char, n, 1), arg);
265
fs->flags |= FS_BOUND|FS_ON;
266
if (!(fs->flags & FS_INTERNAL)) fs->flags |= FS_FS;
267
if (fs == &state.fs[FS_safe] && !(fs->flags & FS_INIT))
268
state.safe = fs;
269
}
270
}
271
while ((op = (const char*)state.key.next) && (x = getkey(op, oe, 0)))
272
switch (x)
273
{
274
case HASHKEY2('f','d'):
275
fsdrop(fs, 0);
276
if ((fs->fd = strtol(state.key.value, NiL, 0)) > 0)
277
fsinit(fs, fs->fd);
278
break;
279
case HASHKEY3('o','f','f'):
280
if (state.key.invert) fs->flags |= FS_ON;
281
else fs->flags &= ~FS_ON;
282
break;
283
case HASHKEY2('o','n'):
284
if (state.key.invert) fs->flags &= ~FS_ON;
285
else fs->flags |= FS_ON;
286
break;
287
#if FS
288
case HASHKEY3('a','c','k'):
289
fs->ack = getmsgmask(oe);
290
break;
291
case HASHKEY6('a','c','t','i','v','e'):
292
if (!(fs->flags & FS_INTERNAL))
293
{
294
if (state.key.invert) fs->flags &= ~FS_ACTIVE;
295
else fs->flags |= FS_ACTIVE;
296
}
297
break;
298
case HASHKEY4('c','a','l','l'):
299
fs->call = getmsgmask(oe);
300
break;
301
case HASHKEY5('c','l','o','s','e'):
302
if (!(fs->flags & FS_INTERNAL))
303
{
304
if (state.key.invert) fs->flags &= ~FS_CLOSE;
305
else fs->flags |= FS_CLOSE;
306
}
307
break;
308
case HASHKEY5('f','l','u','s','h'):
309
if (state.key.invert) fs->flags &= ~FS_FLUSH;
310
else fs->flags |= FS_FLUSH;
311
break;
312
case HASHKEY4('f','o','r','k'):
313
if (!(fs->flags & FS_INTERNAL))
314
{
315
if (state.key.invert) fs->flags &= ~FS_FORK;
316
else fs->flags |= FS_FORK;
317
}
318
break;
319
case HASHKEY6('g','l','o','b','a','l'):
320
if (state.key.invert) fs->flags &= ~FS_GLOBAL;
321
else fs->flags |= FS_GLOBAL;
322
for (mp = state.global, pm = 0; mp && mp->fs != fs; pm = mp, mp = mp->global);
323
if (!mp)
324
{
325
if (!state.key.invert)
326
{
327
for (mp = state.mount; mp < state.mount + elementsof(state.mount) && mp->fs; mp++);
328
if (mp < state.mount + elementsof(state.mount))
329
{
330
mp->fs = fs;
331
mp->global = state.global;
332
state.global = mp;
333
if (state.key.value != state.one)
334
{
335
int n;
336
char* e;
337
338
n = strtol(state.key.value, &e, 0);
339
if (*e == '.' && n == state.pid && (n = strtol(e + 1, NiL, 0)))
340
mp->channel = MSG_CHANNEL(state.pid, n);
341
}
342
}
343
}
344
}
345
else if (state.key.invert)
346
{
347
mp->fs = 0;
348
if (pm) pm->global = mp->global;
349
else state.global = 0;
350
}
351
if (state.global && !state.cache) state.cache = 1;
352
break;
353
case HASHKEY6('i','n','t','e','r','a'):
354
if (state.key.invert) fs->flags &= ~FS_INTERACTIVE;
355
else fs->flags |= FS_INTERACTIVE;
356
break;
357
case HASHKEY4('l','o','a','d'):
358
if (!(fs->flags & (FS_INTERNAL|FS_LOAD)) && fs->service)
359
{
360
void* dll;
361
Fs_get_t get;
362
Fs_set_t set;
363
364
if ((dll = dlopen(fs->service, RTLD_LAZY)) && (set = (Fs_set_t)dlsym(dll, "set")))
365
{
366
fs->flags |= FS_LOAD|FS_INIT|FS_ON;
367
fs->set = set;
368
(*fs->set)(fs, state.null, 0, "init", 4);
369
if (get = (Fs_get_t)dlsym(dll, "get"))
370
fs->get = get;
371
}
372
}
373
break;
374
case HASHKEY5('m','a','t','c','h'):
375
if (fs->match)
376
{
377
if (fs->matchsize) fs->matchsize = 0;
378
else free(fs->match);
379
fs->match = 0;
380
}
381
if (!state.key.invert)
382
{
383
if (opsize)
384
{
385
fs->match = state.key.value;
386
fs->matchsize = state.key.valsize;
387
}
388
else fs->match = strcpy(newof(0, char, state.key.valsize, 1), state.key.value);
389
}
390
break;
391
case HASHKEY6('m','o','n','i','t','o'):
392
if (!(fs->flags & FS_INTERNAL))
393
{
394
if (state.key.invert) fs->flags &= ~FS_MONITOR;
395
else fs->flags |= FS_MONITOR;
396
}
397
break;
398
case HASHKEY4('n','a','m','e'):
399
if (!(fs->flags & FS_INTERNAL))
400
{
401
if (state.key.invert) fs->flags &= ~FS_NAME;
402
else fs->flags |= FS_NAME;
403
}
404
break;
405
case HASHKEY6('r','e','c','e','i','v'):
406
if (!(fs->flags & FS_INTERNAL))
407
{
408
if (state.key.invert) fs->flags &= ~FS_RECEIVE;
409
else fs->flags |= FS_RECEIVE;
410
}
411
break;
412
case HASHKEY6('r','e','g','u','l','a'):
413
if (state.key.invert) fs->flags &= ~FS_REGULAR;
414
else fs->flags |= FS_REGULAR;
415
break;
416
case HASHKEY5('r','e','t','r','y'):
417
fs->retry = strtol(state.key.value, NiL, 0);
418
break;
419
case HASHKEY5('t','e','r','s','e'):
420
fs->terse = getmsgmask(oe);
421
break;
422
case HASHKEY6('u','n','i','q','u','e'):
423
if (state.key.invert) fs->flags &= ~FS_UNIQUE;
424
else fs->flags |= FS_UNIQUE;
425
break;
426
case HASHKEY5('w','r','i','t','e'):
427
if (state.key.invert) fs->flags &= ~FS_WRITE;
428
else fs->flags |= FS_WRITE;
429
break;
430
default:
431
setattr(fs->attr, op, oe);
432
break;
433
#endif
434
}
435
if (!old)
436
{
437
#if FS
438
if ((fs->flags & (FS_ACTIVE|FS_MONITOR)) == FS_ACTIVE)
439
fs->call |= MSG_MASK(MSG_fork);
440
if (fs->flags & FS_NAME) state.call.name++;
441
else state.call.monitor++;
442
#endif
443
}
444
return(0);
445
}
446
447
static int
448
get_map(Fs_t* fs, register char* buf, const char* op, int flags)
449
{
450
register int n;
451
452
if (op) return(-1);
453
state.visit.prefix = fs->special;
454
state.visit.prelen = fs->specialsize + 4;
455
n = iterate(&state.vmap, mapget, buf, flags);
456
state.visit.prelen = 0;
457
state.visit.prefix = 0;
458
return(n);
459
}
460
461
static int
462
set_map(Fs_t* fs, const char* arg, int argsize, const char* op, int opsize)
463
{
464
NoP(fs);
465
return(mapset(&state.vmap, arg, argsize, op, opsize));
466
}
467
468
static int
469
get_safe(Fs_t* fs, register char* buf, const char* op, int flags)
470
{
471
register int n;
472
473
if (op) return(-1);
474
state.visit.prefix = fs->special;
475
state.visit.prelen = fs->specialsize + 4;
476
n = iterate(&state.vsafe, mapget, buf, flags);
477
state.visit.prelen = 0;
478
state.visit.prefix = 0;
479
return(n);
480
}
481
482
static int
483
set_safe(Fs_t* fs, const char* arg, int argsize, const char* op, int opsize)
484
{
485
NoP(fs);
486
return(mapset(&state.vsafe, arg, argsize, op, opsize));
487
}
488
489
static int
490
get_intercept(Fs_t* fs, register char* buf, const char* op, int flags)
491
{
492
register int n;
493
494
if (op)
495
return -1;
496
state.visit.prefix = fs->special;
497
state.visit.prelen = fs->specialsize + 4;
498
n = iterate(&state.vintercept, mapget, buf, flags);
499
state.visit.prelen = 0;
500
state.visit.prefix = 0;
501
return n;
502
}
503
504
typedef int (*Init_f)(int, const char*, int);
505
506
static int
507
set_intercept(Fs_t* fs, const char* arg, int argsize, const char* op, int opsize)
508
{
509
void* dll;
510
Init_f init;
511
char buf[PATH_MAX + 1];
512
513
static const char sym[] = "_3d_init";
514
515
NoP(fs);
516
if (!*arg || mapset(&state.vintercept, arg, argsize, op, opsize))
517
return -1;
518
if (argsize)
519
{
520
if (argsize > PATH_MAX)
521
return -1;
522
strncpy(buf, arg, argsize);
523
buf[argsize] = 0;
524
arg = (const char*)buf;
525
}
526
if (!(dll = dlopen(arg, RTLD_LAZY)))
527
{
528
error(2, "%s: %s", arg, dlerror());
529
return -1;
530
}
531
if (!(init = (Init_f)dlsym(dll, sym)))
532
{
533
error(2, "%s: %s: initialization function not found", arg, sym);
534
dlclose(dll);
535
return -1;
536
}
537
return (*init)(0, op, opsize);
538
}
539
540
#if FS
541
542
static void
543
bencode(char** b, char* e, register unsigned long n, int a, int r, int x)
544
{
545
register char* s;
546
register char* t;
547
register int m;
548
register int z;
549
char buf[16];
550
551
s = buf;
552
z = (1 << (r - (x != 0)));
553
do
554
{
555
m = n & ((1 << r) - 1);
556
*s++ = m + ((m >= z) ? x : a);
557
} while ((n >>= r) && s < &buf[sizeof(buf)]);
558
t = *b;
559
while (s > buf && t < e)
560
*t++ = *--s;
561
}
562
563
#endif
564
565
static int
566
get_option(register Fs_t* fs, register char* buf, const char* op, int flags)
567
{
568
register int c;
569
register int n;
570
register int sum = 0;
571
register unsigned long x;
572
char* b;
573
char* e;
574
int m;
575
576
x = op ? getkey(op, op + strlen(op), 0) : 0;
577
578
/*
579
* table version
580
*/
581
582
if (!x && (flags & (MAP_EXEC|MAP_INIT)) || x == HASHKEY6('v','e','r','s','i','o'))
583
{
584
if (buf)
585
{
586
n = sfsprintf(buf, 0, "- /#%s/version=%d ", fs->special, TABLE_VERSION);
587
buf += n;
588
}
589
else n = fs->specialsize + 18;
590
sum += n;
591
}
592
593
/*
594
* trace output -- special case to capture redirection early
595
*/
596
597
if (!x && (fs->flags & FS_BOUND))
598
{
599
if (buf)
600
{
601
n = sfsprintf(buf, 0, "%-*s /#%s/%s ", fs->servicesize ? fs->servicesize : strlen(fs->service), fs->service, state.fs[FS_fs].special, fs->special);
602
buf += n;
603
}
604
else n = (fs->servicesize ? fs->servicesize : strlen(fs->service)) + state.fs[FS_fs].specialsize + fs->specialsize + 4;
605
sum += n;
606
}
607
608
/*
609
* test mask
610
*/
611
612
if (!x && state.test || x == HASHKEY4('t','e','s','t'))
613
{
614
if (buf)
615
{
616
n = sfsprintf(buf, 0, "- /#%s/test=0%lo ", fs->special, state.test);
617
buf += n;
618
}
619
else n = fs->specialsize + 23;
620
sum += n;
621
}
622
623
/*
624
* readdir() view boundaries
625
*/
626
627
if (x == HASHKEY6('b','o','u','n','d','a'))
628
{
629
if (buf)
630
{
631
n = sfsprintf(buf, 0, "- /#%s/%sboundary ", fs->special, state.boundary ? state.null : "no");
632
buf += n;
633
}
634
else n = fs->specialsize + 16;
635
sum += n;
636
}
637
638
#if DEBUG
639
/*
640
* debug level
641
*/
642
643
if (!x && error_info.trace || x == HASHKEY5('d','e','b','u','g'))
644
{
645
if (buf)
646
{
647
n = sfsprintf(buf, 0, "- /#%s/debug=%d ", fs->special, -error_info.trace);
648
buf += n;
649
}
650
else n = fs->specialsize + 18;
651
sum += n;
652
}
653
#endif
654
655
/*
656
* license features
657
*/
658
659
if (!x && *state.license || x == HASHKEY6('l','i','c','e','n','s'))
660
{
661
if (buf)
662
{
663
n = sfsprintf(buf, 0, "- /#%s/license=%s ", fs->special, state.license);
664
buf += n;
665
}
666
else n = fs->specialsize + strlen(state.license) + 14;
667
sum += n;
668
}
669
670
/*
671
* 2d && 3d
672
*/
673
674
if (!x && (state.in_2d || state.limit < TABSIZE) || x == HASHKEY2(HASHKEYN('2'),'d') || x == HASHKEY2(HASHKEYN('3'),'d'))
675
{
676
if (buf)
677
{
678
n = (state.limit == TABSIZE) ? sfsprintf(buf, 0, "- /#%s/%cd ", fs->special, state.in_2d ? '2' : '3') : sfsprintf(buf, 0, "- /#%s/2d=%d ", fs->special, state.limit);
679
buf += n;
680
}
681
else n = fs->specialsize + (state.limit == TABSIZE) ? 8 : 11;
682
sum += n;
683
}
684
685
#if FS
686
687
/*
688
* file table
689
*/
690
691
if (state.cache && (!x && (flags & (MAP_EXEC|MAP_INIT)) || x == HASHKEY4('f','i','l','e')))
692
{
693
b = state.path.name;
694
e = b + sizeof(state.path.name) - 1;
695
c = -1;
696
for (n = m = 0; n <= state.cache; n++)
697
if (state.file[n].flags & FILE_CLOEXEC)
698
{
699
if ((flags & MAP_EXEC) && state.file[n].mount && fssys(state.file[n].mount, MSG_close))
700
fscall(state.file[n].mount, MSG_close, 0, n);
701
}
702
else if (state.file[n].flags & FILE_OPEN)
703
{
704
if ((x = n - m - 1) > 0)
705
bencode(&b, e, x, '0', 3, 0);
706
if (x = state.file[n].id.fid[0])
707
bencode(&b, e, x, 'a', 4, 0);
708
bencode(&b, e, state.file[n].id.fid[1], 'A', 4, 0);
709
if (state.file[n].mount && (x = state.file[n].mount - state.mount) != c)
710
bencode(&b, e, c = x, 'Q', 4, 'q');
711
m = n;
712
}
713
n = b - state.path.name;
714
*b = 0;
715
b = state.path.name;
716
if (n)
717
{
718
if (buf)
719
{
720
n = sfsprintf(buf, 0, "- /#%s/file=%s ", fs->special, b);
721
buf += n;
722
}
723
else n += fs->specialsize + 11;
724
sum += n;
725
}
726
}
727
728
#endif
729
730
/*
731
* fd table
732
*/
733
734
if (!x && (flags & (MAP_EXEC|MAP_INIT)) && state.table.fd != TABLE_FD || x == HASHKEY5('t','a','b','l','e'))
735
{
736
if (buf)
737
{
738
if ((n = FCNTL(TABLE_FD, F_GETFD, 0)) >= 0)
739
{
740
n = n ? -1 : FCNTL(TABLE_FD, F_DUPFD, RESERVED_FD);
741
CLOSE(TABLE_FD);
742
}
743
if (state.table.fd <= 0 || FCNTL(state.table.fd, F_DUPFD, TABLE_FD) < 0)
744
{
745
if (state.table.fd > 0)
746
cancel(&state.table.fd);
747
n = -1;
748
}
749
else
750
{
751
cancel(&state.table.fd);
752
state.table.fd = TABLE_FD;
753
reserve(&state.table.fd);
754
}
755
if (n < 0) n = 0;
756
else
757
{
758
n = sfsprintf(buf, 0, "- /#%s/table=%d ", fs->special, n);
759
buf += n;
760
}
761
}
762
else n = fs->specialsize + 18;
763
sum += n;
764
}
765
766
/*
767
* syscall count
768
*/
769
770
if (!x && state.trace.count || x == HASHKEY5('c','o','u','n','t'))
771
{
772
if (buf)
773
{
774
n = sfsprintf(buf, 0, "- /#%s/%scount ", fs->special, state.trace.count ? state.null : "no");
775
buf += n;
776
}
777
else n = fs->specialsize + 13;
778
sum += n;
779
}
780
781
/*
782
* syscall trace
783
*/
784
785
if (!x && state.trace.pid || x == HASHKEY5('t','r','a','c','e'))
786
{
787
if (buf)
788
{
789
n = sfsprintf(buf, 0, "- /#%s/trace=%u ", fs->special, state.trace.pid + ((flags & (MAP_EXEC|MAP_INIT)) && state.trace.pid <= 2));
790
buf += n;
791
}
792
else n = fs->specialsize + 18;
793
sum += n;
794
}
795
796
/*
797
* syscall calls
798
*/
799
800
if (state.trace.call != ~0 && (!x || x == HASHKEY4('c','a','l','l')))
801
{
802
if (buf)
803
{
804
n = sfsprintf(buf, 0, "- /#%s/call=", fs->special);
805
n += msggetmask(buf + n, SHRT_MAX, state.trace.call);
806
buf += n++;
807
*buf++ = ' ';
808
}
809
else n = fs->specialsize + msggetmask(NiL, 0, state.trace.call) + 12;
810
sum += n;
811
}
812
813
#if FS
814
815
/*
816
* message timeout
817
*/
818
819
if (!x && msg_info.timeout != MSG_TIMEOUT || x == HASHKEY6('t','i','m','e','o','u'))
820
{
821
if (buf)
822
{
823
n = sfsprintf(buf, 0, "- /#%s/timeout=%d ", fs->special, msg_info.timeout);
824
buf += n;
825
}
826
else n = fs->specialsize + 20;
827
sum += n;
828
}
829
830
#endif
831
832
return(sum);
833
}
834
835
#if DEBUG && FS
836
837
#define DUMP_call (1<<0)
838
#define DUMP_file (1<<1)
839
#define DUMP_fs (1<<2)
840
#define DUMP_map (1<<3)
841
#define DUMP_mount (1<<4)
842
#define DUMP_safe (1<<5)
843
#define DUMP_state (1<<6)
844
#define DUMP_view (1<<7)
845
846
/*
847
* dump Table_t
848
*/
849
850
static void
851
dumptable(char** b, char* e, Table_t* tab, const char* name)
852
{
853
register Map_t* cp;
854
register Map_t* ep;
855
register int n;
856
857
if (tab->size)
858
{
859
bprintf(b, e, "\n%s table\n\n", name);
860
for (ep = (cp = tab->table) + tab->size; cp < ep; cp++)
861
{
862
bprintf(b, e, " [%d] %-*s", cp - tab->table, cp->keysize, cp->key);
863
if ((n = 32 - cp->keysize) > 0)
864
bprintf(b, e, "%*s", n, state.null);
865
bprintf(b, e, " %-*s\n", T_VALSIZE(cp), cp->val);
866
}
867
}
868
}
869
870
/*
871
* dump internal state to option output
872
*/
873
874
static void
875
dump(const char* op, const char* oe)
876
{
877
register char* e;
878
register File_t* fp;
879
register Fs_t* fs;
880
register Mount_t* mp;
881
register int list;
882
register int n;
883
int on;
884
char* b;
885
886
if ((on = fsfd(&state.fs[FS_option])) <= 0) return;
887
if (op == (char*)state.one) list = ~DUMP_call;
888
else
889
{
890
list = 0;
891
e = state.key.next;
892
state.key.next = (char*)op;
893
for (;;)
894
{
895
switch (getkey(state.key.next, oe, ','))
896
{
897
case 0:
898
break;
899
case HASHKEY4('c','a','l','l'):
900
list |= DUMP_call;
901
continue;
902
case HASHKEY4('f','i','l','e'):
903
list |= DUMP_file;
904
continue;
905
case HASHKEY2('f','s'):
906
list |= DUMP_fs;
907
continue;
908
case HASHKEY3('m','a','p'):
909
list |= DUMP_map;
910
continue;
911
case HASHKEY5('m','o','u','n','t'):
912
list |= DUMP_mount;
913
continue;
914
case HASHKEY4('s','a','f','e'):
915
list |= DUMP_safe;
916
continue;
917
case HASHKEY5('s','t','a','t','e'):
918
list |= DUMP_state;
919
continue;
920
case HASHKEY4('v','i','e','w'):
921
list |= DUMP_view;
922
continue;
923
}
924
break;
925
}
926
state.key.next = e;
927
if (!list) return;
928
}
929
e = (b = state.path.name) + sizeof(state.path.name) - 1;
930
if (list & DUMP_state)
931
{
932
bprintf(&b, e, "\nstate %s\n\n", id + 10);
933
if (state.limit == TABSIZE) bprintf(&b, e, " %cd on\n", state.in_2d ? '2' : '3');
934
else bprintf(&b, e, " 2d %d\n", state.limit);
935
bprintf(&b, e, " boundary %s\n", state.boundary ? "on" : "off");
936
bprintf(&b, e, " cache %u\n", state.cache);
937
bprintf(&b, e, " call %u.%u", state.call.monitor, state.call.name);
938
if (state.trace.call != ~0)
939
{
940
bprintf(&b, e, " ");
941
b += msggetmask(b, e - b, state.trace.call);
942
}
943
bprintf(&b, e, "\n count %u\n", state.trace.count);
944
#if DEBUG
945
bprintf(&b, e, " debug %d\n", -error_info.trace);
946
#endif
947
bprintf(&b, e, " level %d\n", state.level);
948
#if LICENSED
949
bprintf(&b, e, " license %s\n", state.license);
950
#endif
951
bprintf(&b, e, " pid %u\n", state.pid);
952
bprintf(&b, e, " pwd %s\n", state.pwd);
953
bprintf(&b, e, " table %d\n", state.table.fd);
954
bprintf(&b, e, " test %08o\n", state.test);
955
bprintf(&b, e, " trace %u\n", state.trace.pid);
956
bprintf(&b, e, " version %u\n", TABLE_VERSION);
957
}
958
if (list & DUMP_fs)
959
{
960
bprintf(&b, e, "\nfs table\n\n");
961
for (fs = state.fs; fs < state.fs + elementsof(state.fs); fs++)
962
if (fs->flags)
963
{
964
if ((n = fs - state.fs) < 10) n += '0';
965
else n -= 10 - 'a';
966
bprintf(&b, e, " [%c] %-*s", n, sizeof(fs->special), fs->special);
967
if (fs->flags & FS_BOUND) bprintf(&b, e, " service=%-*s", fs->servicesize ? fs->servicesize : strlen(fs->service), fs->service);
968
if (fs->flags & FS_ACTIVE) bprintf(&b, e, " active");
969
if (fs->flags & FS_CLOSE) bprintf(&b, e, " close");
970
if (fs->flags & FS_ERROR) bprintf(&b, e, " error");
971
if (fs->flags & FS_FLUSH) bprintf(&b, e, " flush");
972
if (fs->flags & FS_FORK) bprintf(&b, e, " fork");
973
if (fs->flags & FS_FS) bprintf(&b, e, " fs");
974
if (fs->flags & FS_GLOBAL) bprintf(&b, e, " global");
975
if (fs->flags & FS_INIT) bprintf(&b, e, " init");
976
if (fs->flags & FS_INTERACTIVE) bprintf(&b, e, " interactive");
977
if (fs->flags & FS_INTERNAL) bprintf(&b, e, " internal");
978
#if LICENSED
979
if (fs->flags & FS_LICENSED) bprintf(&b, e, " licensed");
980
#endif
981
if (fs->flags & FS_LOAD) bprintf(&b, e, " load");
982
if (fs->flags & FS_LOCK) bprintf(&b, e, " lock");
983
if (fs->flags & FS_MAGIC) bprintf(&b, e, " magic");
984
if (fs->flags & FS_MONITOR) bprintf(&b, e, " monitor");
985
if (fs->flags & FS_NAME) bprintf(&b, e, " name");
986
if (!(fs->flags & FS_ON)) bprintf(&b, e, " off");
987
if (fs->flags & FS_OPEN) bprintf(&b, e, " open=%d", fs->fd);
988
if (fs->flags & FS_RAW) bprintf(&b, e, " raw");
989
if (fs->flags & FS_RECEIVE) bprintf(&b, e, " receive");
990
if (fs->flags & FS_REFERENCED) bprintf(&b, e, " referenced");
991
if (fs->flags & FS_REGULAR) bprintf(&b, e, " regular");
992
if (fs->flags & FS_UNIQUE) bprintf(&b, e, " unique");
993
if (fs->flags & FS_VALIDATED) bprintf(&b, e, " validated");
994
if (fs->flags & FS_WRITE) bprintf(&b, e, " write");
995
if (fs->call != ~0)
996
{
997
bprintf(&b, e, " call=");
998
b += msggetmask(b, e - b, fs->call);
999
}
1000
if (fs->ack)
1001
{
1002
bprintf(&b, e, " ack=");
1003
b += msggetmask(b, e - b, fs->ack);
1004
}
1005
if (fs->terse)
1006
{
1007
bprintf(&b, e, " terse=");
1008
b += msggetmask(b, e - b, fs->terse);
1009
}
1010
bprintf(&b, e, "%s", fs->attr);
1011
bprintf(&b, e, "\n");
1012
}
1013
}
1014
if (list & DUMP_mount)
1015
{
1016
bprintf(&b, e, "\nmount table\n\n");
1017
for (mp = state.mount; mp < state.mount + elementsof(state.mount); mp++)
1018
if (mp->fs)
1019
{
1020
if ((n = mp - state.mount) < 10) n += '0';
1021
else n -= 10 - 'a';
1022
bprintf(&b, e, " [%c] %-*s", n, sizeof(mp->fs->special), mp->fs->special);
1023
if (mp->logical) bprintf(&b, e, " logical=%-*s", mp->logicalsize ? mp->logicalsize : strlen(mp->logical), mp->logical);
1024
else if (mp->fs->flags & FS_GLOBAL) bprintf(&b, e, " global");
1025
if (mp->physical) bprintf(&b, e, " physical=%-*s", mp->physicalsize ? mp->physicalsize : strlen(mp->physical), mp->physical);
1026
if (mp->channel) bprintf(&b, e, " channel=%u", MSG_CHANNEL_SYS(mp->channel));
1027
bprintf(&b, e, "%s", mp->attr);
1028
bprintf(&b, e, "\n");
1029
}
1030
}
1031
if (list & DUMP_file)
1032
{
1033
bprintf(&b, e, "\nfile table\n\n");
1034
for (fp = state.file; fp < state.file + elementsof(state.file); fp++)
1035
if ((mp = fp->mount) || (fp->flags & (FILE_ERROR|FILE_OPEN)) || fp->reserved)
1036
{
1037
bprintf(&b, e, " [%02d]", fp - state.file);
1038
if (mp)
1039
{
1040
if ((n = mp - state.mount) < 10) n += '0';
1041
else n -= 10 - 'a';
1042
bprintf(&b, e, " mount=%s[%c]", mp->fs->special, n);
1043
}
1044
if (fp->flags & FILE_CLOEXEC) bprintf(&b, e, " cloexec");
1045
if (fp->flags & FILE_ERROR) bprintf(&b, e, " error");
1046
if (fp->flags & FILE_LOCK) bprintf(&b, e, " lock");
1047
if (fp->id.fid[0] || fp->id.fid[1]) bprintf(&b, e, " fid=%ld%s%ld", fp->id.fid[0], fp->id.fid[1] >= 0 ? "+" : state.null, fp->id.fid[1]);
1048
if (fp->flags & FILE_OPEN) bprintf(&b, e, " open");
1049
if (fp->flags & FILE_REGULAR) bprintf(&b, e, " regular");
1050
if (fp->reserved) bprintf(&b, e, " reserved");
1051
if (fp->flags & FILE_VIRTUAL) bprintf(&b, e, " virtual");
1052
if (fp->flags & FILE_WRITE) bprintf(&b, e, " write");
1053
if (n = fp->flags & ~(FILE_LOCAL - 1)) bprintf(&b, e, " local=%08o", n);
1054
bprintf(&b, e, "\n");
1055
}
1056
}
1057
if (list & DUMP_view) dumptable(&b, e, &state.vpath, "view");
1058
if (list & DUMP_map) dumptable(&b, e, &state.vmap, "map");
1059
if (list & DUMP_safe) dumptable(&b, e, &state.vsafe, "safe");
1060
if (list & DUMP_call) calldump(&b, e);
1061
bprintf(&b, e + 1, "\n");
1062
WRITE(on, state.path.name, b - state.path.name);
1063
}
1064
1065
#endif
1066
1067
static int
1068
set_option(Fs_t* fs, const char* arg, int argsize, const char* op, int opsize)
1069
{
1070
register int c;
1071
register const char* oe;
1072
register char* s;
1073
int i;
1074
int m;
1075
long n;
1076
#if FS
1077
Mount_t* mp;
1078
#endif
1079
1080
NoP(argsize);
1081
oe = op + (opsize ? opsize : strlen(op));
1082
do switch (n = getkey(op, oe, 0))
1083
{
1084
case HASHKEY2(HASHKEYN('2'),'d'):
1085
state.limit = state.key.value == state.one ? 0 : strtol(state.key.value, NiL, 0);
1086
if (state.limit > 0) state.in_2d = 0;
1087
else
1088
{
1089
if (state.limit < 0)
1090
cancel(&state.table.fd);
1091
state.limit = TABSIZE;
1092
state.in_2d = 1;
1093
}
1094
break;
1095
case HASHKEY2(HASHKEYN('3'),'d'):
1096
state.in_2d = strtol(state.key.value, NiL, 0) <= 0;
1097
state.limit = TABSIZE;
1098
break;
1099
case HASHKEY6('b','o','u','n','d','a'):
1100
state.boundary = strtol(state.key.value, NiL, 0) > 0;
1101
break;
1102
case HASHKEY4('c','a','l','l'):
1103
state.trace.call = getmsgmask(oe);
1104
if (state.trace.count)
1105
state.trace.call |= MSG_MASK(MSG_exit);
1106
break;
1107
case HASHKEY5('c','o','u','n','t'):
1108
if (state.trace.count = strtol(state.key.value, NiL, 0))
1109
{
1110
state.trace.call |= MSG_MASK(MSG_exit);
1111
if (!state.trace.pid)
1112
{
1113
state.trace.pid = 1;
1114
goto setout;
1115
}
1116
}
1117
break;
1118
1119
#if DEBUG
1120
case HASHKEY5('d','e','b','u','g'):
1121
c = error_info.trace;
1122
if (error_info.trace = -strtol(state.key.value, NiL, 0));
1123
{
1124
if (!c)
1125
{
1126
errno = 0;
1127
message((error_info.trace, "%s [%d]", state.id, state.pid));
1128
}
1129
goto setout;
1130
}
1131
break;
1132
#endif
1133
1134
#if DEBUG && FS
1135
case HASHKEY4('d','u','m','p'):
1136
dump(state.key.value, oe);
1137
break;
1138
#endif
1139
1140
#if FS
1141
case HASHKEY4('f','i','l','e'):
1142
s = state.key.value;
1143
n = -1;
1144
m = 0;
1145
while (s < oe)
1146
{
1147
long fid[2];
1148
long off;
1149
1150
if ((c = *s++) >= '0' && c < '0' + 8)
1151
{
1152
i = c - '0';
1153
while (s < oe && (c = *s++) >= '0' && c < '0' + 8)
1154
i = (i << 3) + c - '0';
1155
if (s >= oe) break;
1156
n += i;
1157
}
1158
else n++;
1159
fid[0] = 0;
1160
while (c >= 'a' && c < 'a' + 16)
1161
{
1162
fid[0] = (fid[0] << 4) + c - 'a';
1163
if (s >= oe) break;
1164
c = *s++;
1165
}
1166
fid[1] = 0;
1167
while (c >= 'A' && c < 'A' + 16)
1168
{
1169
fid[1] = (fid[1] << 4) + c - 'A';
1170
if (s >= oe) break;
1171
c = *s++;
1172
}
1173
off = 0;
1174
while (c >= 'a' && c < 'a' + 16)
1175
{
1176
off = (off << 4) + c - 'a';
1177
if (s >= oe) break;
1178
c = *s++;
1179
}
1180
i = 0;
1181
for (;;)
1182
{
1183
if (c >= 'Q' && c < 'Q' + 8)
1184
i = (i << 4) + c - 'Q';
1185
else if (c >= 'q' && c < 'q' + 8)
1186
i = (i << 4) + c - 'q' + 8;
1187
else break;
1188
if (s >= oe) break;
1189
c = *s++;
1190
}
1191
if (i) m = i;
1192
if (m >= 0 && m < elementsof(state.mount) && !fileinit(n, NiL, state.mount + m, 0))
1193
{
1194
state.file[n].id.fid[0] = fid[0];
1195
state.file[n].id.fid[1] = fid[1];
1196
}
1197
}
1198
break;
1199
#endif
1200
1201
case HASHKEY4('f','o','r','k'):
1202
if (state.trace.pid > 2)
1203
state.trace.pid = state.pid;
1204
break;
1205
case HASHKEY4('i','n','i','t'):
1206
if (!(fs->flags & FS_OPEN) && !FSTAT(2, &fs->st))
1207
{
1208
fs->flags |= FS_OPEN;
1209
fs->fd = 2;
1210
}
1211
state.trace.call = ~0;
1212
break;
1213
case HASHKEY6('l','i','c','e','n','s'):
1214
if ((char*)op >= state.table.buf && (char*)oe < state.table.buf + sizeof(state.table.buf))
1215
{
1216
if (state.key.valsize >= sizeof(state.license))
1217
state.key.valsize = sizeof(state.license) - 1;
1218
memcpy(state.license, state.key.value, state.key.valsize);
1219
state.license[state.key.valsize] = 0;
1220
}
1221
break;
1222
1223
#if DEBUG && FS
1224
case HASHKEY5('m','o','u','n','t'):
1225
if (pathreal(arg, P_PATHONLY|P_ABSOLUTE|P_NOSLASH, NiL) && (mp = getmount(state.path.name, &arg)))
1226
error(0, "getmount: %s: %s + %s", state.path.name, mp->fs->special, *arg ? arg : state.dot);
1227
break;
1228
#endif
1229
1230
case HASHKEY5('t','a','b','l','e'):
1231
if (state.table.fd == TABLE_FD && (i = strtol(state.key.value, NiL, 0)) > 0 && i != TABLE_FD)
1232
{
1233
CLOSE(state.table.fd);
1234
state.table.fd = FCNTL(i, F_DUPFD, TABLE_FD);
1235
CLOSE(i);
1236
}
1237
break;
1238
case HASHKEY4('t','e','s','t'):
1239
if (state.key.invert)
1240
{
1241
if (*state.key.invert >= '0' && *state.key.invert <= '9') state.key.value = state.key.invert;
1242
if ((n = strtol(state.key.value, NiL, 0)) <= 0) state.test = 0;
1243
else state.test &= ~n;
1244
}
1245
else state.test |= strtol(state.key.value, NiL, 0);
1246
break;
1247
1248
#if FS
1249
case HASHKEY6('t','i','m','e','o','u'):
1250
msg_info.timeout = strtol(state.key.value, NiL, 0);
1251
break;
1252
case HASHKEY6('t','i','m','e','s','t'):
1253
msg_info.timestamp = !state.key.invert;
1254
break;
1255
#endif
1256
1257
case HASHKEY5('t','r','a','c','e'):
1258
if (state.trace.pid = strtol(state.key.value, NiL, 0))
1259
{
1260
if (state.trace.pid > 2)
1261
state.trace.pid = state.pid;
1262
setout:
1263
if (state.fs[FS_option].fd == 2 && (i = FCNTL(2, F_DUPFD, RESERVED_FD)) >= 0)
1264
{
1265
state.fs[FS_option].fd = i;
1266
reserve(&state.fs[FS_option].fd);
1267
}
1268
}
1269
break;
1270
case HASHKEY6('v','e','r','s','i','o'):
1271
if ((state.table.version = strtol(state.key.value, NiL, 0)) != TABLE_VERSION)
1272
return(-1);
1273
break;
1274
} while (op = (const char*)state.key.next);
1275
return(0);
1276
}
1277
1278
static int
1279
get_pwd(register Fs_t* fs, register char* buf, const char* op, int flags)
1280
{
1281
register int n = 0;
1282
1283
NoP(flags);
1284
if (op) return(-1);
1285
if (state.pwd)
1286
{
1287
if (buf) n = sfsprintf(buf, 0, "%s /#%s ", state.pwd, fs->special);
1288
else n = state.pwdsize + fs->specialsize + 4;
1289
}
1290
return(n);
1291
}
1292
1293
/*
1294
* set state.pwd from s
1295
*/
1296
1297
static int
1298
setpwd(register const char* s)
1299
{
1300
int osiz;
1301
int olev;
1302
struct stat dot;
1303
struct stat pwd;
1304
1305
if (*s != '/' || *state.pwd == '/')
1306
return(-1);
1307
if (STAT(state.dot, &dot))
1308
{
1309
message((-1, "%s: cannot stat", state.dot));
1310
return(-1);
1311
}
1312
osiz = state.pwdsize;
1313
if ((state.pwdsize = strlen(s)) >= sizeof(state.pwdbuf))
1314
state.pwdsize = sizeof(state.pwdbuf) - 1;
1315
strncpy(state.pwd, s, state.pwdsize);
1316
state.pwd[state.pwdsize] = 0;
1317
state.pwdsize = pathcanon(state.pwd, sizeof(state.pwdbuf), 0) - state.pwd;
1318
olev = state.level;
1319
state.level = -1;
1320
state.path.linkname = 0;
1321
if ((s = pathreal(state.pwd, 0, &pwd)) && (dot.st_ino == pwd.st_ino && dot.st_dev == pwd.st_dev || state.path.linkname && !STAT(state.path.name, &pwd) && dot.st_ino == pwd.st_ino && dot.st_dev == pwd.st_dev))
1322
{
1323
state.level = state.path.level;
1324
memcpy(state.envpwd + sizeof(var_pwd) - 1, state.pwd, state.pwdsize);
1325
message((-1, "setpwd: state.pwd=%s state.level=%d state.path.level=%d", state.pwd, state.level, state.path.level));
1326
return(0);
1327
}
1328
message((-1, "%s: cannot set PWD", state.pwd));
1329
*state.pwd = '.';
1330
*(state.pwd + 1) = 0;
1331
state.pwdsize = osiz;
1332
state.level = olev;
1333
return(-1);
1334
}
1335
1336
static int
1337
set_pwd(Fs_t* fs, const char* arg, int argsize, const char* op, int opsize)
1338
{
1339
int c;
1340
int r;
1341
1342
NoP(fs);
1343
NoP(op);
1344
NoP(opsize);
1345
if (!*arg || *state.pwd == '/')
1346
return(0);
1347
if (argsize)
1348
{
1349
c = *((char*)arg + argsize);
1350
*((char*)arg + argsize) = 0;
1351
}
1352
else c = 0;
1353
if (op) message((-1, "set_pwd arg=%s op=%-*s", arg, opsize ? opsize : strlen(op), op));
1354
r = setpwd(arg);
1355
if (c) *((char*)arg + argsize) = c;
1356
return(r);
1357
}
1358
1359
static int
1360
get_view(Fs_t* fs, register char* buf, const char* op, int flags)
1361
{
1362
NoP(fs);
1363
if (op) return(-1);
1364
return(iterate(&state.vpath, mapget, buf, flags));
1365
}
1366
1367
static int
1368
set_view(Fs_t* fs, const char* arg, int argsize, const char* op, int opsize)
1369
{
1370
NoP(fs);
1371
return(mapset(&state.vpath, arg, argsize, op, opsize));
1372
}
1373
1374
/*
1375
* set state.shell from s
1376
*/
1377
1378
static int
1379
setshell(register const char* s)
1380
{
1381
if (ACCESS(s, 1))
1382
{
1383
message((-1, "%s: cannot access SHELL", s));
1384
return(-1);
1385
}
1386
strncpy(state.shell, s, PATH_MAX);
1387
return(0);
1388
}
1389
1390
/*
1391
* static data initialization
1392
*/
1393
1394
#define FSINIT(n,g,s,f,k) {FS_INTERNAL|f,0,0,sizeof(n)-1,g,s,k,0,~0,0,n}
1395
1396
State_t state =
1397
{
1398
id + 10, /* id */
1399
IDNAME, /* cmd */
1400
".", /* dot */
1401
"", /* null */
1402
"1", /* one */
1403
"/bin/sh", /* binsh */
1404
var_3d, /* env3d */
1405
var_pwd, /* envpwd */
1406
var_shell, /* envshell */
1407
var_view, /* envview */
1408
{
1409
FSINIT("null", 0, 0, FS_LICENSED,
1410
HASHKEY4('n','u','l','l')),
1411
FSINIT("option",get_option, set_option, FS_FORK|FS_LICENSED,
1412
HASHKEY6('o','p','t','i','o','n')),
1413
FSINIT("view", get_view, set_view, 0,
1414
HASHKEY4('v','i','e','w')),
1415
FSINIT("pwd", get_pwd, set_pwd, FS_LICENSED,
1416
HASHKEY3('p','w','d')),
1417
FSINIT("fs", get_fs, set_fs, 0,
1418
HASHKEY2('f','s')),
1419
FSINIT("map", get_map, set_map, 0,
1420
HASHKEY3('m','a','p')),
1421
FSINIT("safe", get_safe, set_safe, 0,
1422
HASHKEY4('s','a','f','e')),
1423
#if FS
1424
FSINIT("fd", 0, 0, FS_FS|FS_NAME,
1425
HASHKEY2('f','d')),
1426
#endif
1427
FSINIT("intercept", get_intercept, set_intercept, FS_RAW,
1428
HASHKEY6('i','n','t','e','r','c')),
1429
1430
/* NOTE: add internal mounts here */
1431
1432
#if VCS && defined(VCS_FS)
1433
VCS_FS,
1434
#endif
1435
},
1436
"default", /* default instance name*/
1437
".../...", /* opaque */
1438
TABSIZE, /* limit */
1439
};
1440
1441
/*
1442
* note external control interrupt
1443
*/
1444
1445
static void
1446
note(int sig)
1447
{
1448
state.control.note++;
1449
signal(sig, note);
1450
}
1451
1452
/*
1453
* handle external control interrupt
1454
*/
1455
1456
void
1457
control(void)
1458
{
1459
char* s;
1460
int fd;
1461
ssize_t n;
1462
char buf[PATH_MAX];
1463
1464
if (state.control.note)
1465
{
1466
message((-2, "external control interrupt"));
1467
if (s = state.control.path) n = state.control.pathsize;
1468
else
1469
{
1470
s = "/tmp/3d";
1471
n = 0;
1472
}
1473
if (!n) n = strlen(s);
1474
sfsprintf(buf, sizeof(buf), "%-*s#%d", n, s, state.pid);
1475
if ((fd = OPEN(buf, O_RDONLY, 0)) >= 0)
1476
{
1477
if ((n = READ(fd, buf, sizeof(buf) - 1)) > 0)
1478
{
1479
buf[n] = 0;
1480
mapinit(buf, 0);
1481
}
1482
CLOSE(fd);
1483
if ((fd = OPEN(buf, O_RDWR|O_TRUNC, 0)) >= 0)
1484
CLOSE(fd);
1485
}
1486
state.control.note = 0;
1487
}
1488
}
1489
1490
/*
1491
* push system call intercept
1492
*/
1493
1494
int
1495
intercept(Intercept_f call, unsigned long mask)
1496
{
1497
register int i;
1498
1499
for (i = 0;; i++)
1500
if (i >= state.trap.size)
1501
{
1502
if (i >= elementsof(state.trap.intercept))
1503
return(-1);
1504
state.trap.size++;
1505
break;
1506
}
1507
else if (state.trap.intercept[i].call == call)
1508
break;
1509
state.trap.intercept[i].call = call;
1510
state.trap.intercept[i].mask = mask;
1511
return(0);
1512
}
1513
1514
/*
1515
* 3d initialization
1516
*/
1517
1518
#define env_2d (1<<0)
1519
#define env_3d (1<<1)
1520
#define env_cmd (1<<2)
1521
#define env_path (1<<3)
1522
#define env_pwd (1<<4)
1523
#define env_shell (1<<5)
1524
#define env_view (1<<6)
1525
#define env_must (env_2d|env_3d|env_cmd|env_path|env_pwd|env_shell|env_view)
1526
#define env_home (1<<7)
1527
1528
#define var_cmd "_="
1529
#define var_disable "_3D_DISABLE_="
1530
#define var_home "HOME="
1531
#define var_path "PATH="
1532
1533
int
1534
init(int force, const char* opt, int opsize)
1535
{
1536
register char** ep = environ;
1537
register char* cp;
1538
register int i;
1539
Fs_t* fs;
1540
char* home = 0;
1541
Handler_t handler;
1542
int n;
1543
int oerrno;
1544
1545
/*
1546
* initialize the 3d state
1547
*/
1548
1549
if (!force && state.pid) return(0);
1550
oerrno = errno;
1551
#if DEBUG
1552
error_info.id = state.cmd;
1553
#endif
1554
#if defined(SIGIO) || defined(SIGPWR)
1555
#if defined(SIGIO)
1556
n = SIGIO;
1557
#else
1558
n = SIGPWR;
1559
#endif
1560
if ((handler = signal(n, note)) != SIG_DFL)
1561
signal(n, handler);
1562
#endif
1563
state.pid = getpid();
1564
state.uid = geteuid();
1565
state.gid = getegid();
1566
state.pwd = state.pwdbuf;
1567
*state.pwd = '.';
1568
state.pwdsize = 1;
1569
state.shell = state.envshell + sizeof(var_shell) - 1;
1570
callinit();
1571
state.fs[FS_safe].flags |= FS_INIT;
1572
for (fs = state.fs; fs < state.fs + elementsof(state.fs) && fs->specialsize; fs++)
1573
{
1574
fs->flags |= FS_ON;
1575
if (fs->set) (*fs->set)(fs, state.null, 0, "init", 4);
1576
}
1577
1578
/*
1579
* extract the 3d tables from table.fd or the top of the environment
1580
*/
1581
1582
cp = *(state.env = ep);
1583
i = 0;
1584
if ((n = peek(TABLE_FD, state.table.buf, sizeof(state.table.buf) - 1)) > 0 && !mapinit(state.table.buf, 1))
1585
{
1586
state.table.size = n + 1;
1587
state.table.fd = TABLE_FD;
1588
reserve(&state.table.fd);
1589
i |= env_view|env_3d;
1590
}
1591
else
1592
{
1593
state.table.version = TABLE_VERSION;
1594
if (cp && strneq(cp, state.env3d, sizeof(var_3d) - 1))
1595
{
1596
mapinit(cp + sizeof(var_3d) - 1, 1);
1597
ep++;
1598
environ++;
1599
i |= env_view|env_3d;
1600
}
1601
}
1602
if (_3d_2d) n = strlen(_3d_2d);
1603
else i |= env_2d;
1604
1605
/*
1606
* look for remaining var_* not in env_* mask i
1607
*/
1608
1609
while (cp = *ep)
1610
{
1611
if (strneq(cp, var_disable, sizeof(var_disable) - 1))
1612
{
1613
state.pid = 0;
1614
errno = oerrno;
1615
return(0);
1616
}
1617
else if (!(i & env_cmd) && strneq(cp, var_cmd, sizeof(var_cmd) - 1))
1618
{
1619
state.cmd = cp + sizeof(var_cmd) - 1;
1620
if ((i |= env_cmd) == env_must) break;
1621
}
1622
else if (!(i & env_home) && strneq(cp, var_home, sizeof(var_home) - 1))
1623
{
1624
home = cp + sizeof(var_home) - 1;
1625
if ((i |= env_home) == env_must) break;
1626
}
1627
else if (!(i & env_path) && strneq(cp, var_path, sizeof(var_path) - 1))
1628
{
1629
state.envpath = cp + sizeof(var_path) - 1;
1630
if ((i |= env_path) == env_must) break;
1631
}
1632
else if (!(i & env_pwd) && strneq(cp, state.envpwd, sizeof(var_pwd) - 1))
1633
{
1634
if (geteuid())
1635
*ep = state.envpwd;
1636
cp += sizeof(var_pwd) - 1;
1637
if (!setpwd(cp) && ((i |= env_pwd) == env_must)) break;
1638
}
1639
else if (!(i & env_shell) && strneq(cp, state.envshell, sizeof(var_shell) - 1))
1640
{
1641
*ep = state.envshell;
1642
cp += sizeof(var_shell) - 1;
1643
if (!setshell(cp) && ((i |= env_shell) == env_must)) break;
1644
}
1645
else if (!(i & env_view) && strneq(cp, state.envview, sizeof(var_view) - 1))
1646
{
1647
char* mp;
1648
char* zp;
1649
1650
cp += sizeof(var_view) - 1;
1651
if (mp = strchr(cp, ':')) do
1652
{
1653
if (!(zp = strchr(++mp, ':'))) zp = mp + strlen(mp);
1654
mapset(&state.vpath, cp, mp - cp - 1, mp, zp - mp);
1655
cp = mp;
1656
} while (*(mp = zp));
1657
if ((i |= env_view) == env_must) break;
1658
}
1659
else if (!(i & env_3d) && strneq(cp, state.env3d, sizeof(var_3d) - 1))
1660
{
1661
mapinit(cp + sizeof(var_3d) - 1, 1);
1662
if ((i |= env_3d) == env_must) break;
1663
}
1664
else if (!(i & env_2d) && strneq(cp, _3d_2d, n) && cp[n] == '=')
1665
{
1666
if ((i |= env_2d) == env_must) break;
1667
}
1668
ep++;
1669
}
1670
if (!(i & env_2d)) state.in_2d = 1;
1671
if (!(i & env_pwd) && *state.pwd != '/' && setpwd("/") && (!home || setpwd(home)))
1672
{
1673
1674
n = state.in_2d;
1675
state.in_2d = 2;
1676
if (!getcwd(state.path.name, sizeof(state.path.name)) || setpwd(state.path.name))
1677
{
1678
state.pwd = 0;
1679
if (!n)
1680
{
1681
static char msg[] = "3d: invalid PWD -- falling back to 2d\n";
1682
1683
write(2, msg, sizeof(msg) - 1);
1684
}
1685
}
1686
else state.in_2d = n;
1687
}
1688
if (!(i & env_shell)) strcpy(state.shell, state.binsh);
1689
if (state.table.fd <= 0 && mapdump(NiL, NiL, MAP_INIT) < sizeof(state.table.buf))
1690
{
1691
n = mapdump(NiL, state.table.buf, MAP_INIT);
1692
keep(state.table.buf, n, 0);
1693
}
1694
if (state.table.fd <= 0 && (state.channel.fd = open("/dev/null", O_RDONLY)) >= 0)
1695
reserve(&state.channel.fd);
1696
if (state.fs[FS_safe].flags & FS_BOUND)
1697
{
1698
state.safe = &state.fs[FS_safe];
1699
if (!state.pwd || !pathreal(state.pwd, P_PATHONLY, NiL))
1700
{
1701
#if DEBUG
1702
error(4, ". is not safe");
1703
#else
1704
static char msg[] = "3d: . is not safe\n";
1705
1706
write(2, msg, sizeof(msg) - 1);
1707
_exit(2);
1708
#endif
1709
}
1710
}
1711
state.fs[FS_safe].flags &= ~FS_INIT;
1712
errno = oerrno;
1713
return(0);
1714
}
1715
1716