|
|
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.