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