|
|
1.1 ! root 1: #include <errno.h> ! 2: #include <sys/param.h> ! 3: #include "parms.h" ! 4: #include "structs.h" ! 5: #include <signal.h> /* signal processing */ ! 6: #include <ctype.h> ! 7: #ifdef SIGCHLD ! 8: #include <sys/wait.h> /* for child status */ ! 9: #endif SIGCHLD ! 10: ! 11: #ifdef RCSIDENT ! 12: static char rcsid[] = "$Header: misc.c,v 1.7.0.5 85/10/06 01:41:01 notes Rel $"; ! 13: #endif RCSIDENT ! 14: ! 15: #define LOCKTRY 10 /* number of shots at grabbing */ ! 16: #define FORKTRY 10 /* tries at forking */ ! 17: ! 18: /* ! 19: * dounix(charstring, flag) will execute that character string as a shell command ! 20: * stolen from shell, though this one catches more signals. ! 21: * ! 22: * Depending on the RUNSUID flag the routine sets things back to ! 23: * the users group or uid. Early versions were setuid and newer ! 24: * versions only run setgid. Don't get confused by the "hisuid" ! 25: * argument: it really means "reset to his permissions". ! 26: * R. Kolstad -- 11/2/80 ! 27: * modified: R. Essick January 1982, to clean up some signal processing ! 28: * ! 29: */ ! 30: ! 31: #if defined(SIGCHLD) ! 32: static int kidpid; /* passed by kidwatch() */ ! 33: static union wait kidstatus; ! 34: #endif defined(SIGCHLD) ! 35: ! 36: ! 37: #ifndef FASTFORK ! 38: dounix (linebuf, hisuid, ttymode) ! 39: char linebuf[]; ! 40: #else ! 41: dounix (hisuid, ttymode, arg0, arg1, arg2, arg3, arg4) ! 42: char *arg0, ! 43: *arg1, ! 44: *arg2, ! 45: *arg3, ! 46: *arg4; ! 47: #endif ! 48: { ! 49: register pid, ! 50: forktry, ! 51: rpid; ! 52: int (*p) (), ! 53: (*q) (), ! 54: (*r) (); ! 55: #if defined(SIGTSTP) ! 56: int (*s) (); ! 57: #endif defined(SIGTSTP) ! 58: #if defined(SIGCHLD) ! 59: int (*t) (); ! 60: extern int watchkid (); /* catch stopped kids */ ! 61: #endif defined(SIGCHLD) ! 62: int retcode; ! 63: ! 64: ! 65: if (ttymode) ! 66: ttystop (); /* give back to normal mode */ ! 67: pid = 0; /* satisfy init conditions */ ! 68: forktry = 0; /* init the counter */ ! 69: while (pid <= 0 && ++forktry < FORKTRY) ! 70: { ! 71: if ((pid = fork ()) == 0) ! 72: { ! 73: uncatchem (); /* reset this process signals */ ! 74: /* if user can get his hands on it */ ! 75: if (hisuid) /* only set uid if giving shell */ ! 76: #ifdef RUNSUID ! 77: setuid (globuid); /* give him his uid */ ! 78: #else ! 79: setgid (getgid ()); /* his group */ ! 80: #endif RUNSUID ! 81: for (rpid = 3; rpid < NOFILE; rpid++) /* close extra files */ ! 82: close (rpid); ! 83: ! 84: #ifndef FASTFORK ! 85: if (linebuf == 0) ! 86: execl (hisshell, hisshell, 0); ! 87: else ! 88: execl (DFLTSH, "sh", "-c", linebuf, 0); ! 89: printf ("Rats -- Couldn't load %s\n", DFLTSH); ! 90: #else ! 91: if (arg0 == 0) ! 92: execlp (hisshell, hisshell, 0); ! 93: else ! 94: execlp (arg0, arg0, arg1, arg2, arg3, arg4); ! 95: printf ("Rats - Couldn't load %s\n", arg0); ! 96: #endif ! 97: ! 98: _exit (BAD); /* if exec fails .. */ ! 99: } ! 100: if (pid <= 0) /* if fork failed */ ! 101: sleep (2); /* wait a bit */ ! 102: } ! 103: if (pid > 0) /* only if have son */ ! 104: { ! 105: p = signal (SIGHUP, SIG_IGN); ! 106: q = signal (SIGINT, SIG_IGN); ! 107: r = signal (SIGQUIT, SIG_IGN); ! 108: #if defined(SIGTSTP) ! 109: s = signal (SIGTSTP, SIG_DFL); ! 110: #endif defined(SIGTSTP) ! 111: #if defined(SIGCHLD) ! 112: t = signal (SIGCHLD, watchkid); /* if he signals */ ! 113: #endif defined(SIGCHLD) ! 114: while ((rpid = wait (&retcode)) != pid && rpid != -1); ! 115: if (rpid == -1) ! 116: { ! 117: #if defined(SIGCHLD) ! 118: /* ! 119: * watchkid() might have sucked down the status of the terminated ! 120: * child, so we load whatever value it left for us in kidstatus ! 121: * (provided that kidpid was ok) ! 122: */ ! 123: if (pid == kidpid) /* the one we wanted */ ! 124: retcode = kidstatus.w_status; /* from watchkid() */ ! 125: else ! 126: retcode = 1 << 8; /* make an error */ ! 127: #else ! 128: /* ! 129: * normal case, if the wait() failed for some reason we say that it ! 130: * is an error. ! 131: */ ! 132: retcode = 1 << 8; /* indicates error */ ! 133: #endif defined(SIGCHLD) ! 134: } ! 135: signal (SIGHUP, p); ! 136: signal (SIGINT, q); ! 137: signal (SIGQUIT, r); ! 138: #if defined(SIGTSTP) ! 139: signal (SIGTSTP, s); ! 140: #endif defined(SIGTSTP) ! 141: #if defined(SIGCHLD) ! 142: signal (SIGCHLD, t); ! 143: #endif defined(SIGCHLD) ! 144: } ! 145: else ! 146: retcode = -1; /* some sort of error */ ! 147: if (ttymode) ! 148: ttystrt (); /* back into raw mode */ ! 149: return retcode >> 8; /* hand him the completion code */ ! 150: } ! 151: ! 152: #if defined(SIGCHLD) ! 153: /* ! 154: * watchkid() ! 155: * ! 156: * called when we receive a SIGCHLD signal, indicating that a child's ! 157: * status has changed. This routine looks via wait3() to see if ! 158: * the children have merely been suspended. If so, it stops itself ! 159: * so that it's parent can decide what to do. ! 160: * ! 161: * This catches problems with programs like vi which run in raw mode ! 162: * and catch ^z as a character. They later try to signal the entire ! 163: * process group but are unable to signal the notes process since it ! 164: * has a different effective uid. By watching the SIGCHLD signal, we ! 165: * get notification when the vi process has stopped and we can stop ! 166: * ourselves. ! 167: * Ray Essick, Augst 22, 1984 ! 168: */ ! 169: static int watchkid (sig) ! 170: int sig; ! 171: { ! 172: ! 173: kidpid = wait3 (&kidstatus, WUNTRACED | WNOHANG, 0);/* get status */ ! 174: if (kidpid == 0) /* nothing to report */ ! 175: return 0; /* get out */ ! 176: if (kidpid == (-1)) /* no children at all */ ! 177: return 0; /* get out */ ! 178: if (WIFSTOPPED (kidstatus)) /* stopped himself */ ! 179: { ! 180: kill (getpid (), SIGTSTP); /* stop myself */ ! 181: } ! 182: } ! 183: #endif defined(SIGCHLD) ! 184: ! 185: /* ! 186: * If the condition is TRUE (non-zero) abort the program. ! 187: * ! 188: * Print the supplied message and halt. ! 189: * Leave an optional core dump for debugging later. ! 190: * ! 191: * Ray Essick 10/23/80 ! 192: */ ! 193: ! 194: x (cond, p) char *p; ! 195: { ! 196: if (cond == 0) ! 197: return; /* didnt fail */ ! 198: ! 199: perror ("notes"); ! 200: fprintf (stderr, "Fatal Internal Notesfile Error: %s\n", p); ! 201: ttystop (); /* back to normal */ ! 202: ! 203: ! 204: #ifdef DUMPCORE ! 205: if (chdir (Mstdir) < 0) /* go to known place */ ! 206: exit (BAD); /* drop out */ ! 207: if (chdir (UTILITY) < 0) ! 208: exit (BAD); /* drop out */ ! 209: if (chdir (DUMPCORE) < 0) /* writeable to all */ ! 210: exit (BAD); /* drop out */ ! 211: #ifdef RUNSUID ! 212: setuid (globuid); /* won't dump if euid != uid */ ! 213: #else ! 214: setgid (getgid ()); /* no gift groups */ ! 215: #endif RUNSUID ! 216: #endif DUMPCORE ! 217: ! 218: #ifdef NFMAINT ! 219: /* ! 220: * This code is kind of risky. If the NFMAINT notesfile ever ! 221: * gets trashed and starts calling this routine, look out because ! 222: * it will recursively fail. This is the unfortunate byproduct ! 223: * of the fact that the "x" routine doesn't know what the ! 224: * current notesfile is. ! 225: */ ! 226: { ! 227: char pbuf[512]; /* hold message */ ! 228: char pbuf2[128]; /* and title */ ! 229: char pbuf3[256]; /* core image */ ! 230: char *tail; /* end of invocation */ ! 231: ! 232: sprintf (pbuf2, "%s: aborted", Invokedas); ! 233: sprintf (pbuf, "Program:\t%s\nMessage:\t%s\n\nerrno:\t\t%d (%s)\n", ! 234: Invokedas, p, errno, ! 235: errno >= sys_nerr ? "Unknown error code" : sys_errlist[errno]); ! 236: #ifdef DUMPCORE ! 237: if ((tail = rindex (Invokedas, '/')) == NULL) /* pathname? */ ! 238: tail = Invokedas; /* simple invocation */ ! 239: else ! 240: tail++; /* strip the slash */ ! 241: sprintf (pbuf3, "%s/%s/%s/%s", Mstdir, UTILITY, DUMPCORE, tail); ! 242: nfabort (NFMAINT, pbuf, pbuf2, pbuf3, BAD); /* log & abort */ ! 243: #else ! DUMPCORE ! 244: nfcomment (NFMAINT, pbuf, pbuf2, 0, 0); /* actual insertion */ ! 245: #endif DUMPCORE ! 246: } ! 247: #endif NFMAINT ! 248: ! 249: /* ! 250: * Handle the exit if NFMAINT is undefined. ! 251: */ ! 252: ! 253: #ifdef DUMPCORE ! 254: abort (); /* dump in "core" */ ! 255: #else ! 256: exit (BAD); /* for production */ ! 257: #endif DUMPCORE ! 258: } ! 259: ! 260: /* ! 261: * lock creates a lock file, or waits until it can create the lock. ! 262: * lock files are of the form lock# where # is a character passed ! 263: * to the routine. ! 264: * ! 265: * Rob Kolstad 10/20/80 ! 266: * modified: rbe December 1981 to add full path name for lock file ! 267: */ ! 268: ! 269: locknf (io, c) ! 270: struct io_f *io; ! 271: char c; ! 272: { ! 273: register int i, ! 274: holderr, ! 275: trys; ! 276: char p[WDLEN]; ! 277: ! 278: sprintf (p, "%s/%s/%c%s", Mstdir, LOCKS, c, io -> nf); ! 279: /* generate file name */ ! 280: trys = LOCKTRY; /* set him up */ ! 281: while ((i = creat (p, 0)) < 0) ! 282: { ! 283: if (trys-- == 0) ! 284: { ! 285: holderr = errno; /* before it's abused */ ! 286: fprintf (stderr, "lock %c (%s) permanently locked - consult a guru\n", ! 287: c, io -> nf); ! 288: #ifdef NFMAINT ! 289: if (strcmp (NFMAINT, io -> nf)) /* avoid loops */ ! 290: { ! 291: char pbuf[256]; /* for error logging */ ! 292: char tbuf[256]; /* title */ ! 293: sprintf (pbuf, ! 294: "lock %c failed for %s,\nerrno = %d (%s)\nProgram = %s\n", ! 295: c, io -> fullname, holderr, sys_errlist[holderr], ! 296: Invokedas); ! 297: sprintf (tbuf, "%s: locked (%c)", io -> nf, c); ! 298: nfcomment (NFMAINT, pbuf, tbuf, 0, 0); ! 299: } ! 300: #endif NFMAINT ! 301: ttystop (); ! 302: exit (BAD); ! 303: } ! 304: sleep (2); /* guarantee at least 1 */ ! 305: } ! 306: ignoresigs++; /* critical section */ ! 307: /* ! 308: * could be above getting the lock, but wanted to be able to suspend ! 309: * while getting the lock. The interuptable window is very small ! 310: */ ! 311: close (i); ! 312: } ! 313: ! 314: /* ! 315: * unlock takes the same arguements as the lock routine, and it ! 316: * will remove the corresponding lock file ! 317: * ! 318: * Rob Kolstad 10/20/80 ! 319: * modified: rbe December 1981 to add full path name for lock name ! 320: */ ! 321: ! 322: unlocknf (io, c) ! 323: struct io_f *io; ! 324: char c; ! 325: { ! 326: char p[WDLEN]; ! 327: ! 328: sprintf (p, "%s/%s/%c%s", Mstdir, LOCKS, c, io -> nf); ! 329: /* generate file name */ ! 330: x (unlink (p) < 0, "unlock: unlink lock"); ! 331: ignoresigs--; /* no longer critical */ ! 332: } ! 333: ! 334: /* ! 335: * glock creates a lock file, or waits until it can create the lock. ! 336: * lock files are of the form lock# where # is a character passed ! 337: * to the routine. ! 338: * This lock file is a GLOBAL lock - across all notefiles ! 339: * ! 340: * taken from lock routine above by R. Essick December 1981 ! 341: */ ! 342: ! 343: glocknf (io, c) ! 344: struct io_f *io; /* unused in this routine */ ! 345: char c; ! 346: { ! 347: register int i, ! 348: holderr, ! 349: trys; ! 350: char p[WDLEN]; ! 351: ! 352: sprintf (p, "%s/%s/%c", Mstdir, LOCKS, c); /* generate file name */ ! 353: trys = LOCKTRY; ! 354: while ((i = creat (p, 0)) < 0) ! 355: { ! 356: if (trys-- == 0) ! 357: { ! 358: holderr = errno; /* before it's abused */ ! 359: fprintf (stderr, "lock%c combo lost - consult your local guru\n", c); ! 360: #ifdef NFMAINT ! 361: if (strcmp (NFMAINT, io -> nf)) /* don't loop on self */ ! 362: { ! 363: char pbuf[256]; /* for error logging */ ! 364: char pbuf2[256]; ! 365: sprintf (pbuf, ! 366: "glock %c failed for %s, errno = %d (%s)\nProgram = %s\n", ! 367: c, io -> fullname, holderr, sys_errlist[holderr], ! 368: Invokedas); ! 369: sprintf (pbuf2, "Frozen Global Lock (%c)", c); ! 370: nfcomment (NFMAINT, pbuf, pbuf2, 0, 0); ! 371: } ! 372: #endif NFMAINT ! 373: ttystop (); ! 374: exit (BAD); ! 375: } ! 376: sleep (2); /* is there a smaller time interval */ ! 377: } ! 378: close (i); ! 379: } ! 380: ! 381: /* ! 382: * gunlock takes the same arguements as the lock routine, and it ! 383: * will remove the corresponding lock file ! 384: * This is GLOBAL locking - across all notefiles ! 385: * ! 386: * copy of code from unlock, with minor changes ! 387: * Ray Essick December 1981 ! 388: */ ! 389: ! 390: gunlocknf (io, c) ! 391: struct io_f *io; /* not used by this routine */ ! 392: char c; ! 393: { ! 394: char p[WDLEN]; ! 395: ! 396: sprintf (p, "%s/%s/%c", Mstdir, LOCKS, c); /* make the file name */ ! 397: x (unlink (p) < 0, "gunlock: unlink lock"); ! 398: } ! 399: ! 400: /* ! 401: * length tells us max(length of string, 1) ! 402: */ ! 403: len (p, n) char *p; ! 404: { ! 405: int i; ! 406: i = n; ! 407: p += n; ! 408: while (*--p == ' ' && --i) ! 409: if (i == 0) ! 410: i = 1; ! 411: return i; ! 412: } ! 413: ! 414: /* ! 415: * shell - give the user a shell ! 416: * this includes: ! 417: * 1) changing to the directory where he came in from ! 418: * 2) giving him a shell ! 419: * 3) return to the notefile directory ! 420: * ! 421: * original author: Ray Essick may 29, 1981 ! 422: * ! 423: */ ! 424: ! 425: gshell () ! 426: { ! 427: printf ("\n"); ! 428: #ifndef FASTFORK ! 429: dounix (0, 1, 1); /* give him his shell */ ! 430: #else ! 431: dounix (1, 1, 0, 0, 0, 0, 0); ! 432: #endif ! 433: return 0; ! 434: } ! 435: ! 436: /* copydate merely moves a when_f structure from 'from' to 'to' */ ! 437: /* ray essick - 20-nov-1981 */ ! 438: ! 439: copydate (from, to) ! 440: struct when_f *from, ! 441: *to; ! 442: { ! 443: *to = *from; /* use block move */ ! 444: } ! 445: ! 446: /* strmove - copy a null terminated string to another */ ! 447: /* returns the count of characters moved, this count includes the */ ! 448: /* null terminator.. */ ! 449: /* r. essick 20-nov-81 */ ! 450: ! 451: strmove (p, q) ! 452: char *p, ! 453: *q; /* from p to q */ ! 454: { ! 455: int count; ! 456: register char *pp, ! 457: *qq; ! 458: ! 459: count = 0; /* start with no characters moved */ ! 460: pp = p; ! 461: qq = q; /* use registers for speed */ ! 462: while (*qq++ = *pp++) ! 463: count++; ! 464: return count; /* return count of characters moved */ ! 465: /* don't include the terminator */ ! 466: } ! 467: ! 468: /* copyauth(from, to) struct auth_f *from,*auth ! 469: * copys author from from to to ! 470: * Ray Essick December 1981 ! 471: * ! 472: * SHOULD USE STRUCTURE ASSIGNMENT IN ALL PLACES THAT CALL THIS ! 473: */ ! 474: copyauth (from, to) ! 475: struct auth_f *from, ! 476: *to; ! 477: { ! 478: ! 479: strncpy (to -> aname, from -> aname, NAMESZ); /* author name */ ! 480: strncpy (to -> asystem, from -> asystem, HOMESYSSZ);/* home machine */ ! 481: to -> aid = from -> aid; /* and user id */ ! 482: } ! 483: ! 484: /* listget, listconv - parse a list of numbers. ! 485: * this is all taken ( sort of ) from Rob Kolstad's getpg ! 486: * program ! 487: */ ! 488: ! 489: listget (buf, ptr, start, finish) ! 490: char buf[]; ! 491: int *ptr, ! 492: *start, ! 493: *finish; ! 494: { ! 495: if ((buf[*ptr] < '0' || buf[*ptr] > '9') && buf[*ptr] != ' ') ! 496: { ! 497: return 0; /* end of this list */ ! 498: } ! 499: *start = listconv (buf, ptr); /* get the first */ ! 500: *finish = *start; /* default to single */ ! 501: if (buf[*ptr] == '-') ! 502: { ! 503: ++(*ptr); /* trash that separator */ ! 504: *finish = listconv (buf, ptr); /* grab second */ ! 505: ++(*ptr); /* bump past delimiter */ ! 506: return 2; /* parsed 2 arguements */ ! 507: } ! 508: else ! 509: { ! 510: if (buf[*ptr] != '\0') ! 511: ++(*ptr); /* dump delimiter */ ! 512: return 1; ! 513: } ! 514: } ! 515: ! 516: listconv (buf, ptr) ! 517: char buf[]; ! 518: int *ptr; ! 519: { ! 520: int i; ! 521: i = 0; ! 522: while (buf[*ptr] == ' ') ! 523: ++(*ptr); ! 524: while (buf[*ptr] >= '0' && buf[*ptr] <= '9') ! 525: { ! 526: i = 10 * i + buf[*ptr] - '0'; ! 527: ++(*ptr); /* bump him */ ! 528: } ! 529: return (i); ! 530: } ! 531: ! 532: /* tolcase - check to see if upper case, and convert to lcase */ ! 533: /* R. Essick Feb 1982 */ ! 534: tolcase (c) ! 535: char c; ! 536: { ! 537: if (isascii (c) && isupper (c)) ! 538: return (tolower (c)); /* to lower case */ ! 539: return (c); /* leave as is */ ! 540: } ! 541: ! 542: /* ! 543: * Date printing stuff. ! 544: * ! 545: * CHANGE TO CTIME(III) FORMAT EVENTUALLY ! 546: */ ! 547: ! 548: char *mnames[13] = /* so indexes work right */ ! 549: { ! 550: "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", ! 551: "Sep", "Oct", "Nov", "Dec" ! 552: }; ! 553: ! 554: sprdate (w, str) struct when_f *w; ! 555: char *str; ! 556: { ! 557: char *m; ! 558: int h, ! 559: i, ! 560: j; /* temps to print 0's or funny strings */ ! 561: m = "am"; ! 562: h = w -> w_hours; ! 563: if (h >= 12) ! 564: m = "pm"; ! 565: if (h == 0) ! 566: h = 12; ! 567: if (h > 12) ! 568: h -= 12; ! 569: i = w -> w_mins / 10; ! 570: j = w -> w_mins % 10; /* get those leading zeroes */ ! 571: sprintf (str, "%2d:%d%d %2s %3s %2d, %4d", h, i, j, m, mnames[w -> w_month], w -> w_day, w -> w_year); ! 572: /* sprintf puts it into a string */ ! 573: } ! 574: ! 575: prdate (zdate) struct when_f *zdate; ! 576: { ! 577: char line[DATELEN]; ! 578: ! 579: sprdate (zdate, line); /* format it */ ! 580: printf ("%s", line); /* and print it */ ! 581: } ! 582: ! 583: /* ! 584: * Saves a string with malloc() and returns a pointer ! 585: * to where it wound up. Useful for building lists of ! 586: * stuff. ! 587: * ! 588: * Courtesy of Lou Salkind & Rick Spickelmier. ! 589: */ ! 590: ! 591: ! 592: char *strsave (s) ! 593: char *s; ! 594: { ! 595: char *p; ! 596: extern char *malloc (); ! 597: ! 598: p = malloc (strlen (s) + 1); ! 599: strcpy (p, s); ! 600: return (p); ! 601: } ! 602: ! 603: /* ! 604: * substr(a,b) see if A is a substring of B ! 605: * ! 606: * uses: strlen. ! 607: */ ! 608: ! 609: substr (a, b) ! 610: char *a; ! 611: char *b; ! 612: { ! 613: register char first; ! 614: register int length; /* length of a */ ! 615: register int count; /* max checks */ ! 616: ! 617: first = *a; /* get first */ ! 618: length = strlen (a); /* for strncmp */ ! 619: count = strlen (b) - length + 1; /* max checks */ ! 620: while (count-- > 0) /* can try */ ! 621: { ! 622: if (*b == first && !strncmp (a, b, length)) ! 623: return (1); /* is a substring */ ! 624: b++; /* on to next */ ! 625: } ! 626: return (0); /* not a substring */ ! 627: } ! 628: ! 629: /* ! 630: * routine to process a string and remove any ! 631: * nasties like control characters and escape codes. ! 632: */ ! 633: ! 634: int strclean (p) ! 635: char *p; ! 636: { ! 637: if (p == (char *) NULL) ! 638: return 0; ! 639: if (*p == '\0') ! 640: return 0; ! 641: do ! 642: { ! 643: if (!isascii (*p) || iscntrl (*p)) ! 644: *p = '_'; /* kill controls */ ! 645: } while (*++p != '\0'); ! 646: return (0); ! 647: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.