|
|
1.1 root 1: #include <stdio.h>
2: #include <sys/types.h>
3: #include <sys/stat.h>
4: #include <signal.h>
5: #include <ipc.h>
6: #include <errno.h>
7: #include <libc.h>
8: #include <pwd.h>
9: #include <grp.h>
10:
11: typedef struct {
12: char *address;
13: char *arg;
14: char *mpoint;
15: char *callusr;
16: int rootino;
17: dev_t rootdev;
18: char proto;
19: char stat;
20: char devnum;
21: char debug;
22: int retry;
23: } Friend;
24:
25: #define SOK 01 /* filesystem running ok */
26: #define SFOUND 02 /* found in most recent friends pass */
27:
28: #define MAXRETRY 60 /* slow down after this many retries */
29: #define LONGRETRY 20 /* after slowdown, retry after this many cycles */
30:
31: #define MAXFRIENDS 128
32: Friend friends[MAXFRIENDS]; /* should probably be dynamic */
33:
34: #define MAXMSG 5 /* largest message 5*MSGBLOCK -- known to kernel too */
35: #define MSGBLOCK 1024
36:
37: #define NBFS 4 /* our filesystem type */
38:
39: char frfile[] = "/usr/netb/friends"; /* should be an argument */
40:
41: char *estr();
42: Friend *findmpoint();
43:
44: main(argc, argv)
45: int argc;
46: char **argv;
47: {
48: Friend f;
49: int fd;
50:
51: if (argc <= 1) {
52: mkdaemon();
53: rundaemon();
54: }
55: if (argc < 6 || argc > 8) {
56: fprintf(stderr, "usage: setup netaddr arg mountpoint protocol devnum [debug userid]\n");
57: exit(1);
58: }
59: f.address = argv[1];
60: f.arg = argv[2];
61: f.mpoint = argv[3];
62: f.proto = argv[4][0];
63: f.devnum = atoi(argv[5]);
64: if (argc <= 6)
65: f.debug = 0;
66: else
67: f.debug = atoi(argv[6]);
68: if (argc <= 7)
69: f.callusr = "daemon";
70: else
71: f.callusr = argv[7];
72: if ((fd = callsys(&f)) < 0) {
73: fprintf(stderr, "%s %s %c %s: %s\n", f.address, f.arg, f.proto, f.callusr, errstr);
74: exit(1);
75: }
76: if (setup(fd, &f) < 0)
77: exit(1);
78: exit(0);
79: }
80:
81: nulltrap(s)
82: {
83: signal(s, nulltrap);
84: }
85:
86: /*
87: * prepare to be a daemon
88: */
89:
90: mkdaemon()
91: {
92: switch (fork()) {
93: case -1:
94: perror("fork");
95: exit(1);
96: default: /* parent */
97: exit(0);
98: case 0: /* child */
99: break;
100: }
101: signal(SIGINT, SIG_IGN);
102: signal(SIGQUIT, SIG_IGN);
103: signal(SIGHUP, SIG_IGN);
104: signal(SIGPIPE, SIG_IGN); /* needed? */
105: signal(SIGALRM, nulltrap); /* miscellaneous alarms */
106: }
107:
108: /*
109: * the daemon:
110: * once a minute,
111: * see if the filesystems we've already mounted are ok
112: * see if the friends file has changed, and read it if so
113: * try to mount any filesystem that isn't
114: */
115:
116: rundaemon()
117: {
118: static time_t fmtime;
119: struct stat st;
120: register Friend *fp;
121: int fd;
122:
123: for (;; sleep(60)) {
124: for (fp = friends; fp < &friends[MAXFRIENDS]; fp++) {
125: if (fp->address == NULL || (fp->stat & SOK) == 0)
126: continue;
127: alarm(60);
128: if (stat(fp->mpoint, &st) < 0) {
129: plog("stat %s: %s\n", fp->mpoint, estr());
130: fp->stat &=~ SOK;
131: } else if (st.st_dev != fp->rootdev
132: || st.st_ino != fp->rootino) {
133: plog("%s: not root: want 0x%x:%d, have 0x%x:%d\n",
134: fp->mpoint, fp->rootdev, fp->rootino,
135: st.st_dev, st.st_ino);
136: fp->stat &=~ SOK;
137: }
138: alarm(0);
139: }
140: if (stat(frfile, &st) < 0)
141: plog("stat %s: %s\n", frfile, estr());
142: else if (fmtime != st.st_mtime) {
143: fmtime = st.st_mtime;
144: newfriends();
145: }
146: for (fp = friends; fp < &friends[MAXFRIENDS]; fp++) {
147: if (fp->address == NULL || fp->stat & SOK)
148: continue;
149: if (fp->retry > MAXRETRY) {
150: if (fp->retry < MAXRETRY+LONGRETRY) {
151: fp->retry++;
152: continue; /* skip this time */
153: }
154: fp->retry = MAXRETRY; /* do this one, then skip */
155: }
156: plog("%s: calling %s %s %c %s\n",
157: fp->mpoint, fp->address, fp->arg, fp->proto, fp->callusr);
158: if ((fd = callsys(fp)) < 0) {
159: plog("%s: %s\n", fp->address, errstr);
160: fp->retry++;
161: continue;
162: }
163: if (setup(fd, fp) < 0) {
164: plog("%s: setup failed\n", fp->mpoint);
165: alarm(30);
166: close(fd);
167: alarm(0);
168: fp->retry++;
169: continue;
170: }
171: close(fd);
172: plog("%s started\n", fp->mpoint);
173: fp->stat |= SOK;
174: fp->retry = 0;
175: }
176: }
177: }
178:
179: /*
180: * reread the friends file
181: * the algorithm is quadratic,
182: * but we don't do it often
183: */
184:
185: #define ASIZE 8
186: newfriends()
187: {
188: FILE *f;
189: char line[512]; /* huge */
190: char *args[ASIZE];
191: char proto, devnum, debug;
192: char *callusr;
193: register Friend *fp;
194:
195: if ((f = fopen(frfile, "r")) == NULL) {
196: plog("can't open %s: %s\n", frfile, estr());
197: return;
198: }
199: setfields(" \t\n");
200: for (fp = friends; fp < &friends[MAXFRIENDS]; fp++)
201: fp->stat &=~ SFOUND;
202: while (fgets(line, sizeof(line), f)) {
203: if (line[0] == '#')
204: continue;
205: /*
206: * backward compatibility:
207: * login name may be omitted
208: */
209: switch (getmfields(line, args, ASIZE)) {
210: default:
211: continue;
212:
213: case 6:
214: callusr = "daemon";
215: break;
216:
217: case 7:
218: callusr = args[6];
219: break;
220: }
221: proto = args[3][0];
222: devnum = atoi(args[4]);
223: debug = atoi(args[5]);
224: fp = findmpoint(args[2]);
225: if (fp->address /* didn't return an empty */
226: && strcmp(fp->address, args[0]) == 0
227: && strcmp(fp->arg, args[1]) == 0
228: /* mount point already checked */
229: && strcmp(fp->callusr, callusr) == 0
230: && fp->proto == proto
231: && fp->devnum == devnum
232: && fp->debug == debug) {
233: fp->stat |= SFOUND;
234: fp->retry = 0;
235: continue; /* it hasn't changed */
236: }
237: if (fp->address) { /* was already there, clear it */
238: plog("changing %s\n", fp->mpoint);
239: free(fp->address);
240: free(fp->arg);
241: free(fp->mpoint);
242: free(fp->callusr);
243: }
244: fp->address = strdup(args[0]);
245: fp->arg = strdup(args[1]);
246: fp->mpoint = strdup(args[2]);
247: fp->callusr = strdup(callusr);
248: fp->proto = proto;
249: fp->devnum = devnum;
250: fp->debug = debug;
251: fp->stat = SFOUND; /* nb OK not set yet */
252: fp->retry = 0;
253: }
254: fclose(f);
255: for (fp = friends; fp < &friends[MAXFRIENDS]; fp++) {
256: if (fp->address == NULL || fp->stat & SFOUND)
257: continue;
258: plog("dropping %s\n", fp->mpoint);
259: free(fp->address);
260: free(fp->arg);
261: free(fp->mpoint);
262: fp->address = NULL;
263: }
264: }
265:
266: Friend *
267: findmpoint(mp)
268: char *mp;
269: {
270: register Friend *fp, *ep;
271: static Friend junkfriend;
272:
273: ep = NULL;
274: for (fp = friends; fp < &friends[MAXFRIENDS]; fp++) {
275: if (fp->address == NULL) {
276: if (ep == NULL)
277: ep = fp;
278: continue;
279: }
280: if (strcmp(fp->mpoint, mp) == 0)
281: return (fp);
282: }
283: if (ep)
284: return (ep);
285: plog("too many friends; no room for %s\n", mp);
286: return (&junkfriend);
287: }
288:
289: /*
290: * call a server
291: * according to network protocol
292: */
293:
294: callsys(fp)
295: register Friend *fp;
296: {
297: register int fd;
298:
299: alarm(120);
300: setlogname(fp->callusr); /* who the network thinks we are */
301: switch (fp->proto) {
302: case 'd': /* `datakit' -- general connection */
303: fd = ipcopen(ipcpath(fp->address, "dk", "fsb"), "heavy hup");
304: break;
305:
306: case 'e': /* same, but use rexec -- why bother? */
307: fd = ipcexec(ipcpath(fp->address, "dk", "exec"), "heavy hup", fp->arg);
308: break;
309:
310: case 't':
311: fd = ipcrexec(fp->address, "heavy hup", fp->arg);
312: break;
313:
314: default:
315: errstr = "unknown setup protocol";
316: fd = -1;
317: break;
318: }
319: alarm(0);
320: return (fd);
321: }
322:
323: /*
324: * initial protocol with server:
325: * client sends 16 bytes:
326: * max buffer size in 1024-byte units
327: * device number in use
328: * protocol letter
329: * debugging flag
330: * 12 unused
331: * server sends one byte: 1
332: * client sends a list of userids: maxsize bytes
333: * if list won't fit in one buffer, last username is `:'
334: * server acks with one byte 012; client sends more
335: * server sends one byte: 2
336: * client sends a list of groupids: maxsize bytes
337: * if list won't fit in one buffer, last groupname is `:'
338: * server acks with one byte 013; client sends more
339: * server sends one byte: 3
340: * then we mount it, and further messages come from the kernel
341: */
342:
343: #define M1LEN 16
344:
345: setup(fd, fp)
346: int fd;
347: register Friend *fp;
348: {
349: char m[M1LEN];
350: register int n;
351: struct stat st;
352:
353: memset(m, 0, M1LEN);
354: m[0] = MAXMSG;
355: m[1] = fp->devnum;
356: m[2] = fp->proto;
357: if (m[2] == 'e')
358: m[2] = 'd'; /* hack */
359: m[3] = fp->debug;
360: alarm(600);
361: if ((n = write(fd, m, M1LEN)) != M1LEN) {
362: plog("%s setup 1: write returned %d; %s\n", fp->mpoint, n, estr());
363: alarm(0);
364: return (-1);
365: }
366: if (getresp(fd, 1, fp->mpoint) == 0)
367: return (-1);
368: alarm(600);
369: if (senduid(fd, fp->mpoint) < 0) {
370: alarm(0);
371: return (-1);
372: }
373: alarm(600);
374: if (sendgid(fd, fp->mpoint) < 0) {
375: alarm(0);
376: return (-1);
377: }
378: alarm(60);
379: funmount(fp->mpoint); /* bad -- might unmount wrong fs */
380: if (fmount(NBFS, fd, fp->mpoint, makedev(fp->devnum, 0)) < 0) {
381: plog("%s: fmount: %s\n", fp->mpoint, estr());
382: alarm(0);
383: return (-1);
384: }
385: alarm(60);
386: if (stat(fp->mpoint, &st) < 0) {
387: plog("%s: initial root stat: %s\n", fp->mpoint, estr());
388: alarm(0);
389: return (-1);
390: }
391: alarm(0);
392: fp->rootino = st.st_ino;
393: fp->rootdev = st.st_dev;
394: return (0);
395: }
396:
397: /*
398: * get a single-byte response from server
399: * try to cope with unexpected noise,
400: * usually something like /etc/motd or `You have mail.'
401: * fortunately server responses are all characters
402: * unlikely to appear in ordinary ASCII text (viz. octal 1 2 3).
403: * it is more important to copy the junk to the logfile
404: * (so someone can get rid of it) than to survive it
405: */
406:
407: getresp(fd, id, fs)
408: int fd, id;
409: char *fs;
410: {
411: register int i, n;
412: char m[400];
413: int tries, tmo;
414:
415: tmo = 600; /* timeout */
416: for (tries = 0; tries < 5 && tmo > 0; tries++) {
417: alarm(tmo);
418: n = read(fd, m, sizeof(m)-1);
419: tmo = alarm(0); /* assume errno untouched */
420: m[n] = 0;
421: if (n <= 0) {
422: plog("%s setup %d: read returned %d: %s\n", fs, id, n, estr());
423: return (0);
424: }
425: for (i = 0; i < n; i++)
426: if (m[i] == id)
427: break;
428: if (i) {
429: m[i] = 0;
430: plog("%s setup %d: read junk: %s\n", fs, id, m);
431: }
432: if (i < n) /* found it */
433: return (1);
434: }
435: plog("%s setup %d: no response\n", fs, id);
436: return (0);
437: }
438:
439: #define SLOP 50
440:
441: senduid(fd, mpoint)
442: int fd;
443: char *mpoint;
444: {
445: char idbuf[MAXMSG*MSGBLOCK+SLOP];
446: char onebuf[SLOP];
447: register char *p;
448: register struct passwd *pw;
449: register int n, wn;
450:
451: setpwent();
452: p = idbuf;
453: while ((pw = getpwent()) != NULL) {
454: sprintf(onebuf, "%s %d\n", pw->pw_name, pw->pw_uid);
455: n = strlen(onebuf);
456: if (n > &idbuf[MAXMSG*MSGBLOCK] - p - 4) { /* room for ": 1\n" */
457: strcpy(p, ": 1\n"); /* `more coming' */
458: if ((wn = write(fd, idbuf, MAXMSG*MSGBLOCK)) != MAXMSG*MSGBLOCK) {
459: plog("%s: write uid: %d; %s\n", mpoint, wn, estr());
460: return (-1);
461: }
462: if (getresp(fd, 012, mpoint) == 0)
463: return (-1);
464: p = idbuf;
465: }
466: strcpy(p, onebuf);
467: p += n;
468: }
469: endpwent();
470: if ((wn = write(fd, idbuf, MAXMSG*MSGBLOCK)) != MAXMSG*MSGBLOCK) {
471: plog("%s: write uid: %d; %s\n", mpoint, wn, estr());
472: return (-1);
473: }
474: if (getresp(fd, 2, mpoint) == 0)
475: return (-1);
476: return (0);
477: }
478:
479: sendgid(fd, mpoint)
480: int fd;
481: char *mpoint;
482: {
483: char idbuf[MAXMSG*MSGBLOCK+SLOP];
484: char onebuf[SLOP];
485: register char *p;
486: register struct group *gr;
487: register int n, wn;
488:
489: setgrent();
490: p = idbuf;
491: while ((gr = getgrent()) != NULL) {
492: sprintf(onebuf, "%s %d\n", gr->gr_name, gr->gr_gid);
493: n = strlen(onebuf);
494: if (n > &idbuf[MAXMSG*MSGBLOCK] - p - 4) { /* room for ": 1\n" */
495: strcpy(p, ": 1\n"); /* `more coming' */
496: if ((wn = write(fd, idbuf, MAXMSG*MSGBLOCK)) != MAXMSG*MSGBLOCK) {
497: plog("%s: write gid: %d; %s\n", mpoint, wn, estr());
498: return (-1);
499: }
500: if (getresp(fd, 013, mpoint) == 0)
501: return (-1);
502: p = idbuf;
503: }
504: strcpy(p, onebuf);
505: p += n;
506: }
507: endgrent();
508: if ((wn = write(fd, idbuf, MAXMSG*MSGBLOCK)) != MAXMSG*MSGBLOCK) {
509: plog("%s: write gid: %d; %s\n", mpoint, wn, estr());
510: return (-1);
511: }
512: if (getresp(fd, 3, mpoint) == 0)
513: return (-1);
514: return (0);
515: }
516:
517: /*
518: * error logging stuff
519: * just print to stderr for now
520: */
521:
522: /* PRINTFLIKE1 */
523: plog(s, a, b, c, d, e, f)
524: char *s;
525: {
526: long now;
527:
528: time(&now);
529: fseek(stderr, 0L, 2);
530: fprintf(stderr, "%.15s ", ctime(&now)+4); /* trim day of week, year */
531: fprintf(stderr, s, a, b, c, d, e, f);
532: fflush(stderr);
533: }
534:
535: char *
536: estr()
537: {
538: static char buf[] = "Error -2147483648";
539:
540: if (errno < 0 || errno >= sys_nerr) {
541: sprintf(buf, "Error %d", errno);
542: return (buf);
543: }
544: return (sys_errlist[errno]);
545: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.