Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/3d/fs.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-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
* David Korn <[email protected]> *
19
* Eduardo Krell <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
24
/*
25
* 3d mounted fs support
26
*
27
* NOTE: be vewwwy careful with errno
28
*/
29
30
#include "3d.h"
31
32
#if FS
33
34
#include <cs.h>
35
36
#define DEVFD "/dev/fd"
37
#define MNTFD "path\n"
38
#define MNTNAM "/dev/tcp/*"
39
40
/*
41
* initialize mount channel and return fs fd for mp
42
*/
43
44
int
45
fschannel(register Mount_t* mp)
46
{
47
register Fs_t* fs;
48
register int fd;
49
50
if (mp->channel == -1)
51
return -1;
52
fs = mp->fs;
53
if (mp->channel && fs->fd)
54
return fs->fd;
55
if ((fd = fsfd(fs)) <= 0)
56
return -1;
57
if (mp->channel)
58
return fs->fd;
59
mp->channel = 1;
60
mp->flags |= MOUNT_PRIMARY;
61
return fd;
62
}
63
64
/*
65
* generate phony monitor open for fd inherited from parent
66
*/
67
68
static void
69
fsphony(register Mount_t* mp, register File_t* fp, int fd)
70
{
71
register ssize_t n;
72
int nd;
73
Mount_t* np;
74
char buf[64];
75
76
state.kernel++;
77
fp->flags |= FILE_LOCK;
78
*buf = 0;
79
if (!(np = getmount(MNTNAM, NiL)) || (nd = fsfd(np->fs)) < 0)
80
sfsprintf(buf, sizeof(buf), "%s/%d", DEVFD, fd);
81
else if (!(np->fs->flags & FS_LOCK) && WRITE(nd, MNTFD, sizeof(MNTFD) - 1) == sizeof(MNTFD) - 1)
82
{
83
np->fs->flags |= FS_LOCK;
84
if (!cssend(&cs, nd, &fd, 1) && (n = READ(nd, buf, sizeof(buf))) > 1)
85
buf[n - 1] = 0;
86
np->fs->flags &= ~FS_LOCK;
87
}
88
state.kernel--;
89
if (*buf)
90
{
91
fp->open |= (1<<(mp-state.mount));
92
message((-3, "fs: phony: %s", buf));
93
fscall(mp, MSG_open, fd, buf, fp->oflag, 0, 0);
94
}
95
fp->flags &= ~FILE_LOCK;
96
}
97
98
/*
99
* return real fd for up under mount mp to be accessed by call
100
* return value stuck in tail portion of state.path.name
101
*/
102
103
char*
104
fsreal(register Mount_t* mp, long call, const char* up)
105
{
106
char dev[2 * PATH_MAX + 3];
107
register char* s = dev;
108
register Fs_t* fs = mp->fs;
109
register int n;
110
register int fd;
111
int lz;
112
int pz;
113
114
if (!(lz = mp->logicalsize))
115
lz = strlen(mp->logical);
116
if (!(pz = mp->physicalsize) && mp->physical)
117
pz = strlen(mp->physical);
118
n = sfsprintf(s, sizeof(dev) - 1, "%s %-*s %s%s%-*s pwd=%s%s%s", msgname(call), lz, mp->logical, up, pz ? " physical=" : "", pz, mp->physical ? mp->physical : "", state.pwd, mp->fs->attr, mp->attr);
119
s[n] = 0;
120
message((-2, "fs: %s: real: service=%-*s request=\"%s\"", fs->special, fs->servicesize, fs->service, s));
121
s[n++] = '\n';
122
if ((fd = fsfd(fs)) <= 0)
123
return 0;
124
s = state.path.name + PATH_MAX;
125
if (write(fd, dev, n) != n || (n = csread(&cs, fd, s, PATH_MAX, CS_LINE)) <= 0)
126
{
127
fsdrop(fs, 0);
128
return 0;
129
}
130
if (n <= 1)
131
return 0;
132
s[n - 1] = 0;
133
if (s[0] >= 'A' && s[0] <= 'Z' && s[1] == ' ')
134
{
135
message((-2, "fs: %s: real: %s", fs->special, s + 2));
136
return 0;
137
}
138
message((-2, "fs: %s: real: path=%s", fs->special, s));
139
return s;
140
}
141
142
/*
143
* do fs call
144
* -1 returned if not mounted
145
* 0 returned if mounted with state.ret call return value
146
* state.path.monitor set if monitor or name service mount
147
*/
148
149
int
150
fscall(register Mount_t* mp, long call, int ret, ...)
151
{
152
register Fs_t* fs;
153
register int retry;
154
register int tries;
155
const char* up;
156
const char* sp;
157
int cd;
158
int fd;
159
int oerrno;
160
int m;
161
long n;
162
File_t* fp;
163
Handler_t handler;
164
Msg_return_t* rp;
165
Msg_return_t rv;
166
void** xp;
167
void* xv[2];
168
int* ip;
169
Msg_file_t iv[2];
170
va_list ap;
171
172
oerrno = errno;
173
initialize();
174
state.ret = -1;
175
if (state.in_2d)
176
return -1;
177
up = 0;
178
/* proto workaround */
179
va_start(ap, ret); va_end(ap);
180
if (!mp)
181
{
182
state.path.monitor = 0;
183
state.path.mount = 0;
184
sp = 0;
185
va_start(ap, ret);
186
switch (MSG_ARG(call, 1))
187
{
188
case MSG_ARG_file:
189
fd = va_arg(ap, int);
190
if (fd < 0 || fd >= elementsof(state.file))
191
goto nope;
192
if (!state.kernel && (mp = state.global) && !((fp = &state.file[fd])->flags & FILE_LOCK)) do
193
{
194
if (fssys(mp, MSG_open) && ((fp->flags & FILE_OPEN) || !fileinit(fd, NiL, NiL, 0)))
195
{
196
fs = mp->fs;
197
if ((!(fs->flags & FS_REGULAR) || (fp->flags & FILE_REGULAR)) && (!(fs->flags & FS_WRITE) || (fp->flags & FILE_WRITE)) && ((mp->flags & MOUNT_PRIMARY) || fd > 2) && !(fp->open & (1<<(mp-state.mount))))
198
fsphony(mp, fp, fd);
199
}
200
} while (mp = mp->global);
201
mp = fgetmount(fd);
202
n = FS_ERROR|FS_INIT|FS_LOCK|FS_NAME|FS_ON;
203
break;
204
case MSG_ARG_string:
205
sp = va_arg(ap, const char*);
206
if (sp != state.path.name)
207
sp = pathreal(sp, P_PATHONLY|P_ABSOLUTE, NiL);
208
if (sp) mp = getmount(sp, &up);
209
n = FS_ERROR|FS_INIT|FS_LOCK|FS_ON;
210
break;
211
}
212
va_end(ap);
213
if (!mp || ((fs = mp->fs)->flags & n) != FS_ON)
214
goto nope;
215
if (fs->flags & FS_MONITOR)
216
{
217
if (!state.kernel && (fs->call & MSG_MASK(call)))
218
{
219
if (sp && fs->match)
220
{
221
if (fs->matchsize)
222
{
223
cd = fs->match[fs->matchsize];
224
fs->match[fs->matchsize] = 0;
225
}
226
if (strmatch(sp, fs->match))
227
state.path.monitor = mp;
228
if (fs->matchsize)
229
fs->match[fs->matchsize] = cd;
230
}
231
else state.path.monitor = mp;
232
}
233
goto nope;
234
}
235
}
236
else if (((fs = mp->fs)->flags & (FS_ERROR|FS_INIT|FS_LOCK|FS_ON)) != FS_ON)
237
goto nope;
238
if (!(fs->call & MSG_MASK(call)))
239
goto nope;
240
if (fs->flags & FS_MONITOR)
241
{
242
if (state.kernel)
243
goto nope;
244
if (MSG_ARG(call, 1) == MSG_ARG_file)
245
{
246
va_start(ap, ret);
247
fd = va_arg(ap, int);
248
va_end(ap);
249
if (fd < 0 || fd >= elementsof(state.file))
250
goto nope;
251
fp = &state.file[fd];
252
if (fp->flags & FILE_LOCK)
253
goto nope;
254
if (!(fp->flags & FILE_OPEN) && fileinit(fd, NiL, NiL, 0))
255
goto nope;
256
if ((fs->flags & FS_REGULAR) && !(fp->flags & FILE_REGULAR) || (fs->flags & FS_WRITE) && !(fp->flags & FILE_WRITE))
257
goto nope;
258
if (fssys(mp, MSG_open) && ((mp->flags & MOUNT_PRIMARY) || fd > 2) && !(fp->open & (1<<(mp-state.mount))))
259
fsphony(mp, fp, fd);
260
}
261
else if (call == MSG_open)
262
{
263
if (fsmount(mp) < 0)
264
goto nope;
265
if (fs->flags & FS_WRITE)
266
{
267
va_start(ap, ret);
268
va_arg(ap, const char*);
269
n = va_arg(ap, int);
270
va_end(ap);
271
if ((n & O_ACCMODE) == O_RDONLY)
272
goto nope;
273
}
274
}
275
if (MSG_ARG(call, 0) == MSG_ARG_file)
276
{
277
fp = &state.file[ret];
278
fp->open |= (1<<(mp-state.mount));
279
rv.file = fp->id;
280
}
281
else rv.number = ret;
282
rp = &rv;
283
}
284
else if (call == MSG_open)
285
{
286
int oflag;
287
int mode;
288
int level;
289
290
fs->flags |= FS_LOCK;
291
va_start(ap, ret);
292
sp = va_arg(ap, const char*);
293
oflag = va_arg(ap, int);
294
mode = va_arg(ap, int);
295
level = va_arg(ap, int);
296
va_end(ap);
297
message((-3, "fs: %s: open: path=%s", fs->special, sp));
298
if (fs == &state.fs[FS_fd])
299
{
300
const char* ep;
301
302
if ((fd = OPEN(sp, oflag, mode)) >= 0)
303
{
304
state.ret = fd;
305
goto unlock;
306
}
307
fd = strtol(up, (char**)&ep, 0);
308
if (*ep)
309
{
310
oerrno = ENOENT;
311
goto unlock;
312
}
313
if ((n = FCNTL(fd, F_GETFL, 0)) < 0)
314
{
315
oerrno = errno;
316
goto unlock;
317
}
318
n &= O_ACCMODE;
319
oflag &= O_ACCMODE;
320
if (n == O_RDONLY && oflag == O_WRONLY || n == O_WRONLY && oflag == O_RDONLY)
321
{
322
oerrno = EPERM;
323
goto unlock;
324
}
325
if ((state.ret = FCNTL(fd, F_DUPFD, 0)) < 0)
326
oerrno = errno;
327
}
328
else if ((sp = (const char*)fsreal(mp, MSG_open, up)) && (fd = fsfd(mp->fs)) > 0)
329
{
330
/*
331
* /#<id>/[#]<path> for active fd's
332
* /#<id>\n written back to initialize
333
*/
334
335
if (sp[0] == '/' && sp[1] == '#')
336
{
337
up = sp;
338
if (!(sp = strchr(sp + 2, '/')))
339
{
340
sp = up;
341
up = 0;
342
}
343
else
344
{
345
m = sp - up;
346
if (sp[1] == '#')
347
sp += 2;
348
}
349
}
350
else up = 0;
351
if (streq(sp, DEVFD))
352
{
353
cd = -1;
354
while (csrecv(&cs, fd, NiL, &cd, 1) != 1 && errno == EINTR);
355
fd = cd;
356
}
357
else if ((fd = fs3d_open(sp, oflag, mode)) == -1)
358
oerrno = errno;
359
if (fd >= 0 && up)
360
{
361
*((char*)up + m++) = '\n';
362
if (write(fd, up, m) != m)
363
fd = -1;
364
else
365
{
366
if (fd > state.cache)
367
state.cache = fd;
368
fp = &state.file[fd];
369
fp->open = ~0;
370
fp->flags = FILE_OPEN;
371
fp->mount = mp;
372
}
373
}
374
state.ret = fd;
375
}
376
goto unlock;
377
}
378
else
379
rp = 0;
380
if (fs->flags & FS_NAME)
381
{
382
if (up && fs != &state.fs[FS_fd])
383
{
384
state.path.monitor = mp;
385
state.path.mount = (char*)up;
386
}
387
goto nope;
388
}
389
if (MSG_MASK(call) & (MSG_MASK(MSG_close)|MSG_MASK(MSG_dup)))
390
goto nope;
391
message((-3, "fs: %s: %s: call", fs->special, msgname(call)));
392
fs->flags |= FS_LOCK;
393
if (fs->terse & MSG_MASK(call))
394
{
395
tries = MSG_ARG_CALL;
396
for (;;)
397
{
398
tries += MSG_ARG_TYPE;
399
switch ((call >> tries) & ((1 << MSG_ARG_TYPE) - 1))
400
{
401
case 0:
402
break;
403
case MSG_ARG_output:
404
if (!(fs->flags & FS_MONITOR)) break;
405
/*FALLTHROUGH*/
406
case MSG_ARG_input:
407
case MSG_ARG_vector:
408
call = (call & ~(((1 << MSG_ARG_TYPE) - 1) << tries)) | (MSG_ARG_number << tries);
409
continue;
410
default:
411
continue;
412
}
413
break;
414
}
415
}
416
if (fs->flags & FS_ACTIVE)
417
{
418
if (!(fs->flags & FS_MONITOR))
419
call |= MSG_RETURN;
420
else if (fs->ack & MSG_MASK(call))
421
call |= (fs->flags & FS_INTERACTIVE) ? MSG_RETURN : MSG_ACK;
422
retry = fs->retry;
423
}
424
else retry = 0;
425
if ((fs->flags & FS_FLUSH) && (call |= MSG_FLUSH) || retry)
426
handler = signal(SIGPIPE, SIG_IGN);
427
tries = 1;
428
for (;;)
429
{
430
if ((cd = fsmount(mp)) < 0)
431
{
432
message((-2, "fs: %s: %s: connect error on try %d", fs->special, msgname(call), tries));
433
goto unlock;
434
}
435
va_start(ap, ret);
436
xp = xv;
437
switch (MSG_ARG(call, 1))
438
{
439
case MSG_ARG_file:
440
fd = va_arg(ap, int);
441
if (!(fs->flags & FS_MONITOR))
442
cd = fd;
443
*xp++ = (void*)&state.file[fd].id;
444
break;
445
case MSG_ARG_string:
446
sp = va_arg(ap, const char*);
447
if (MSG_VAR(call) == MSG_VAR_FILE)
448
{
449
if (!(fs->flags & FS_MONITOR))
450
sp = up;
451
else if (sp != state.path.name && !(sp = (const char*)pathreal(sp, P_PATHONLY|P_ABSOLUTE, NiL)))
452
goto unlock;
453
}
454
*xp++ = (void*)sp;
455
break;
456
case MSG_ARG_output:
457
if (call == MSG_pipe)
458
{
459
ip = va_arg(ap, int*);
460
for (n = 0; n < 2; n++)
461
{
462
fp = &state.file[ip[n]];
463
if (!(fp->flags & FILE_OPEN))
464
fileinit(ip[n], NiL, NiL, 0);
465
fp->open |= (1<<(mp-state.mount));
466
iv[n] = fp->id;
467
*xp++ = (void*)iv;
468
}
469
}
470
break;
471
default:
472
xp = 0;
473
break;
474
}
475
if (xp)
476
{
477
*xp = 0;
478
xp = xv;
479
}
480
n = msgvcall(cd, MSG_CHANNEL(state.pid, mp->channel), call, rp, xp, ap);
481
va_end(ap);
482
if (n != -1)
483
break;
484
if (errno != EMSGIO)
485
{
486
if (!(fs->flags & FS_MONITOR))
487
oerrno = errno;
488
break;
489
}
490
message((-2, "fs: %s: %s: error on try %d", fs->special, msgname(call), tries));
491
if (tries++ > retry)
492
break;
493
fsdrop(fs, 0);
494
}
495
if ((fs->flags & FS_FLUSH) || retry)
496
signal(SIGPIPE, handler);
497
if (fs->flags & FS_ACTIVE)
498
{
499
if ((state.ret = n) > 0 && (fs->flags & (FS_ACTIVE|FS_INTERACTIVE|FS_MONITOR)) == (FS_ACTIVE|FS_INTERACTIVE|FS_MONITOR) && (fs->ack & MSG_MASK(call)))
500
{
501
char buf[TABLE_MAX];
502
503
if ((n = READ(cd, buf, sizeof(buf))) > 1)
504
{
505
buf[n - 1] = 0;
506
mapinit(buf, 0);
507
}
508
else message((-3, "fs: %s: %s: interactive ack failed", fs->special, msgname(call)));
509
}
510
}
511
else if (!(fs->flags & FS_MONITOR))
512
{
513
oerrno = errno = ENODEV;
514
message((-3, "fs: %s: %s: return: passive fs", fs->special, msgname(call)));
515
}
516
else if (fs->ack & MSG_MASK(call))
517
{
518
oerrno = errno = ENODEV;
519
message((-3, "fs: %s: %s: ack: passive fs", fs->special, msgname(call)));
520
}
521
else state.ret = 0;
522
unlock:
523
fs->flags &= ~FS_LOCK;
524
errno = oerrno;
525
return 0;
526
nope:
527
errno = oerrno;
528
return -1;
529
}
530
531
#endif
532
533
/*
534
* initialize mounted fs and return device service fd
535
*/
536
537
int
538
fsinit(register Fs_t* fs, int fd)
539
{
540
int n;
541
int oerrno;
542
543
if (fd < 0 && (fs->flags & (FS_BOUND|FS_ERROR|FS_INIT|FS_ON)) != (FS_BOUND|FS_ON) || state.kernel && (fs->flags & FS_GLOBAL))
544
return -1;
545
oerrno = errno;
546
fs->flags |= FS_INIT;
547
if ((fs->flags & (FS_ON|FS_OPEN)) != (FS_ON|FS_OPEN))
548
{
549
state.kernel++;
550
if ((fs->fd = fd) < 0)
551
{
552
char* svc;
553
char buf[PATH_MAX];
554
555
if (n = fs->servicesize)
556
{
557
if (n >= sizeof(buf)) n = sizeof(buf) - 1;
558
svc = (char*)memcpy(buf, fs->service, n);
559
svc[n] = 0;
560
}
561
else svc = fs->service;
562
message((-3, "fs: %s: init#1: service=%s", fs->special, svc));
563
#if FS
564
fs->fd = cslocal(&cs, svc);
565
message((-3, "fs: %s: init#2: service=%s cslocal=%d", fs->special, svc, fs->fd));
566
if (fs->fd >= 0)
567
{
568
if (fs->flags & FS_RECEIVE)
569
{
570
n = csrecv(&cs, fs->fd, NiL, &fd, 1);
571
CLOSE(fs->fd);
572
fs->fd = n == 1 ? fd : -1;
573
}
574
}
575
else if (errno == ENOENT)
576
#endif
577
fs->fd = fs3d_open(svc, O_CREAT|O_RDWR|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
578
}
579
if (fs->fd < 0 || FSTAT(fs->fd, &fs->st))
580
{
581
fs->fd = -1;
582
fs->flags |= FS_ERROR;
583
}
584
else
585
{
586
if (fs->flags & FS_CLOSE)
587
FCNTL(fs->fd, F_SETFD, FD_CLOEXEC);
588
if (S_ISREG(fs->st.st_mode))
589
fs->flags &= ~FS_ACTIVE;
590
fs->flags |= FS_ON|FS_OPEN;
591
reserve(&fs->fd);
592
if (fd < 0)
593
message((-3, "fs: %s: init#3: service=%-*s fd=%d cache=%d", fs->special, fs->servicesize ? fs->servicesize : strlen(fs->service), fs->service, fs->fd, state.cache));
594
}
595
state.kernel--;
596
}
597
fs->flags &= ~FS_INIT;
598
errno = oerrno;
599
return fs->fd;
600
}
601
602
/*
603
* drop internal 3d mount
604
* if clear!=0 then path binding also cleared
605
*/
606
607
void
608
fsdrop(register Fs_t* fs, int clear)
609
{
610
int oerrno;
611
612
state.kernel++;
613
oerrno = errno;
614
message((-3, "fs: %s: drop:%s", fs->special, clear ? " clear" : state.null));
615
if (fs->flags & FS_OPEN)
616
{
617
fs->flags &= ~FS_OPEN;
618
cancel(&fs->fd);
619
}
620
fs->flags &= ~FS_ERROR;
621
if (clear)
622
{
623
#if FS
624
if (fs->flags & FS_FS)
625
{
626
register int n;
627
register int m;
628
register Mount_t* mp;
629
630
for (n = 0; n <= state.cache; n++)
631
if ((mp = state.file[n].mount) && mp->fs == fs)
632
state.file[n].mount = 0;
633
for (n = m = 0; n < state.vmount.size; n++)
634
{
635
if (((Mount_t*)state.vmount.table[n].val)->fs != fs)
636
{
637
if (n != m)
638
state.vmount.table[m] = state.vmount.table[n];
639
m++;
640
}
641
else if (state.vmount.table[n].valsize & T_ALLOCATE)
642
free(state.vmount.table[n].key);
643
}
644
state.vmount.size = m;
645
for (n = 0; n < elementsof(state.mount); n++)
646
if (state.mount[n].fs == fs)
647
{
648
state.mount[n].fs = 0;
649
if (state.mount[n].physical && !state.mount[n].physicalsize)
650
{
651
free(state.mount[n].physical);
652
state.mount[n].physical = 0;
653
}
654
}
655
}
656
#endif
657
if (fs->flags & FS_INTERNAL) fs->flags &= ~(FS_BOUND|FS_ON);
658
else
659
{
660
fs->flags = 0;
661
if (fs->service && !fs->servicesize)
662
{
663
free(fs->service);
664
fs->service = 0;
665
}
666
}
667
}
668
errno = oerrno;
669
state.kernel--;
670
}
671
672