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 <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Eduardo Krell <ekrell@adexus.cl> *
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
fschannel(register Mount_t * mp)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
fsphony(register Mount_t * mp,register File_t * fp,int fd)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*
fsreal(register Mount_t * mp,long call,const char * up)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
fscall(register Mount_t * mp,long call,int ret,...)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
fsinit(register Fs_t * fs,int fd)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
fsdrop(register Fs_t * fs,int clear)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