|
|
1.1 root 1: /*
2: * Copyright (c) 1980, 1988 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)dumpoptr.c 5.3 (Berkeley) 2/15/90";
9: #endif not lint
10:
11: #include "dump.h"
12: #include <sys/time.h>
13: #include "pathnames.h"
14:
15: /*
16: * This is from /usr/include/grp.h
17: * That defined struct group, which conflicts
18: * with the struct group defined in param.h
19: */
20: struct Group { /* see getgrent(3) */
21: char *gr_name;
22: char *gr_passwd;
23: int gr_gid;
24: char **gr_mem;
25: };
26: struct Group *getgrnam();
27: /*
28: * Query the operator; This previously-fascist piece of code
29: * no longer requires an exact response.
30: * It is intended to protect dump aborting by inquisitive
31: * people banging on the console terminal to see what is
32: * happening which might cause dump to croak, destroying
33: * a large number of hours of work.
34: *
35: * Every 2 minutes we reprint the message, alerting others
36: * that dump needs attention.
37: */
38: int timeout;
39: char *attnmessage; /* attention message */
40: query(question)
41: char *question;
42: {
43: char replybuffer[64];
44: int back;
45: FILE *mytty;
46:
47: if ( (mytty = fopen(_PATH_TTY, "r")) == NULL){
48: msg("fopen on %s fails\n", _PATH_TTY);
49: abort();
50: }
51: attnmessage = question;
52: timeout = 0;
53: alarmcatch();
54: for(;;){
55: if ( fgets(replybuffer, 63, mytty) == NULL){
56: if (ferror(mytty)){
57: clearerr(mytty);
58: continue;
59: }
60: } else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') {
61: back = 1;
62: goto done;
63: } else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') {
64: back = 0;
65: goto done;
66: } else {
67: fprintf(stderr, " DUMP: \"Yes\" or \"No\"?\n");
68: fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ",
69: question);
70: }
71: }
72: done:
73: /*
74: * Turn off the alarm, and reset the signal to trap out..
75: */
76: alarm(0);
77: if (signal(SIGALRM, sigalrm) == SIG_IGN)
78: signal(SIGALRM, SIG_IGN);
79: fclose(mytty);
80: return(back);
81: }
82:
83: char lastmsg[100];
84:
85: /*
86: * Alert the console operator, and enable the alarm clock to
87: * sleep for 2 minutes in case nobody comes to satisfy dump
88: */
89: alarmcatch()
90: {
91: if (notify == 0) {
92: if (timeout == 0)
93: fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ",
94: attnmessage);
95: else
96: msgtail("\7\7");
97: } else {
98: if (timeout) {
99: msgtail("\n");
100: broadcast(""); /* just print last msg */
101: }
102: fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ",
103: attnmessage);
104: }
105: signal(SIGALRM, alarmcatch);
106: alarm(120);
107: timeout = 1;
108: }
109: /*
110: * Here if an inquisitive operator interrupts the dump program
111: */
112: interrupt()
113: {
114: msg("Interrupt received.\n");
115: if (query("Do you want to abort dump?"))
116: dumpabort();
117: }
118:
119: /*
120: * The following variables and routines manage alerting
121: * operators to the status of dump.
122: * This works much like wall(1) does.
123: */
124: struct Group *gp;
125:
126: /*
127: * Get the names from the group entry "operator" to notify.
128: */
129: set_operators()
130: {
131: if (!notify) /*not going to notify*/
132: return;
133: gp = getgrnam(OPGRENT);
134: endgrent();
135: if (gp == (struct Group *)0){
136: msg("No group entry for %s.\n",
137: OPGRENT);
138: notify = 0;
139: return;
140: }
141: }
142:
143: struct tm *localtime();
144: struct tm *localclock;
145:
146: /*
147: * We fork a child to do the actual broadcasting, so
148: * that the process control groups are not messed up
149: */
150: broadcast(message)
151: char *message;
152: {
153: time_t clock;
154: FILE *f_utmp;
155: struct utmp utmp;
156: int nusers;
157: char **np;
158: int pid, s;
159:
160: switch (pid = fork()) {
161: case -1:
162: return;
163: case 0:
164: break;
165: default:
166: while (wait(&s) != pid)
167: continue;
168: return;
169: }
170:
171: if (!notify || gp == 0)
172: exit(0);
173: clock = time(0);
174: localclock = localtime(&clock);
175:
176: if((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) {
177: msg("Cannot open %s\n", _PATH_UTMP);
178: return;
179: }
180:
181: nusers = 0;
182: while (!feof(f_utmp)){
183: if (fread(&utmp, sizeof (struct utmp), 1, f_utmp) != 1)
184: break;
185: if (utmp.ut_name[0] == 0)
186: continue;
187: nusers++;
188: for (np = gp->gr_mem; *np; np++){
189: if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0)
190: continue;
191: /*
192: * Do not send messages to operators on dialups
193: */
194: if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0)
195: continue;
196: #ifdef DEBUG
197: msg("Message to %s at %s\n",
198: utmp.ut_name, utmp.ut_line);
199: #endif DEBUG
200: sendmes(utmp.ut_line, message);
201: }
202: }
203: fclose(f_utmp);
204: Exit(0); /* the wait in this same routine will catch this */
205: /* NOTREACHED */
206: }
207:
208: sendmes(tty, message)
209: char *tty, *message;
210: {
211: char t[50], buf[BUFSIZ];
212: register char *cp;
213: int lmsg = 1;
214: FILE *f_tty;
215:
216: strcpy(t, _PATH_DEV);
217: strcat(t, tty);
218:
219: if((f_tty = fopen(t, "w")) != NULL) {
220: setbuf(f_tty, buf);
221: fprintf(f_tty, "\n\07\07\07Message from the dump program to all operators at %d:%02d ...\r\n\n DUMP: NEEDS ATTENTION: "
222: ,localclock->tm_hour
223: ,localclock->tm_min);
224: for (cp = lastmsg; ; cp++) {
225: if (*cp == '\0') {
226: if (lmsg) {
227: cp = message;
228: if (*cp == '\0')
229: break;
230: lmsg = 0;
231: } else
232: break;
233: }
234: if (*cp == '\n')
235: putc('\r', f_tty);
236: putc(*cp, f_tty);
237: }
238: fclose(f_tty);
239: }
240: }
241:
242: /*
243: * print out an estimate of the amount of time left to do the dump
244: */
245:
246: time_t tschedule = 0;
247:
248: timeest()
249: {
250: time_t tnow, deltat;
251:
252: time (&tnow);
253: if (tnow >= tschedule){
254: tschedule = tnow + 300;
255: if (blockswritten < 500)
256: return;
257: deltat = tstart_writing - tnow +
258: (((1.0*(tnow - tstart_writing))/blockswritten) * esize);
259: msg("%3.2f%% done, finished in %d:%02d\n",
260: (blockswritten*100.0)/esize,
261: deltat/3600, (deltat%3600)/60);
262: }
263: }
264:
265: int blocksontape()
266: {
267: /*
268: * esize: total number of blocks estimated over all reels
269: * blockswritten: blocks actually written, over all reels
270: * etapes: estimated number of tapes to write
271: *
272: * tsize: blocks can write on this reel
273: * asize: blocks written on this reel
274: * tapeno: number of tapes written so far
275: */
276: if (tapeno == etapes)
277: return(esize - (etapes - 1)*tsize);
278: return(tsize);
279: }
280:
281: /* VARARGS1 */
282: /* ARGSUSED */
283: msg(fmt, a1, a2, a3, a4, a5)
284: char *fmt;
285: int a1, a2, a3, a4, a5;
286: {
287: fprintf(stderr," DUMP: ");
288: #ifdef TDEBUG
289: fprintf(stderr,"pid=%d ", getpid());
290: #endif
291: fprintf(stderr, fmt, a1, a2, a3, a4, a5);
292: fflush(stdout);
293: fflush(stderr);
294: sprintf(lastmsg, fmt, a1, a2, a3, a4, a5);
295: }
296:
297: /* VARARGS1 */
298: /* ARGSUSED */
299: msgtail(fmt, a1, a2, a3, a4, a5)
300: char *fmt;
301: int a1, a2, a3, a4, a5;
302: {
303: fprintf(stderr, fmt, a1, a2, a3, a4, a5);
304: }
305: /*
306: * Tell the operator what has to be done;
307: * we don't actually do it
308: */
309:
310: struct fstab *
311: allocfsent(fs)
312: register struct fstab *fs;
313: {
314: register struct fstab *new;
315: register char *cp;
316: char *malloc();
317:
318: new = (struct fstab *)malloc(sizeof (*fs));
319: cp = malloc(strlen(fs->fs_file) + 1);
320: strcpy(cp, fs->fs_file);
321: new->fs_file = cp;
322: cp = malloc(strlen(fs->fs_type) + 1);
323: strcpy(cp, fs->fs_type);
324: new->fs_type = cp;
325: cp = malloc(strlen(fs->fs_spec) + 1);
326: strcpy(cp, fs->fs_spec);
327: new->fs_spec = cp;
328: new->fs_passno = fs->fs_passno;
329: new->fs_freq = fs->fs_freq;
330: return (new);
331: }
332:
333: struct pfstab {
334: struct pfstab *pf_next;
335: struct fstab *pf_fstab;
336: };
337:
338: static struct pfstab *table = NULL;
339:
340: getfstab()
341: {
342: register struct fstab *fs;
343: register struct pfstab *pf;
344:
345: if (setfsent() == 0) {
346: msg("Can't open %s for dump table information.\n", _PATH_FSTAB);
347: return;
348: }
349: while (fs = getfsent()) {
350: if (strcmp(fs->fs_type, FSTAB_RW) &&
351: strcmp(fs->fs_type, FSTAB_RO) &&
352: strcmp(fs->fs_type, FSTAB_RQ))
353: continue;
354: fs = allocfsent(fs);
355: pf = (struct pfstab *)malloc(sizeof (*pf));
356: pf->pf_fstab = fs;
357: pf->pf_next = table;
358: table = pf;
359: }
360: endfsent();
361: }
362:
363: /*
364: * Search in the fstab for a file name.
365: * This file name can be either the special or the path file name.
366: *
367: * The entries in the fstab are the BLOCK special names, not the
368: * character special names.
369: * The caller of fstabsearch assures that the character device
370: * is dumped (that is much faster)
371: *
372: * The file name can omit the leading '/'.
373: */
374: struct fstab *
375: fstabsearch(key)
376: char *key;
377: {
378: register struct pfstab *pf;
379: register struct fstab *fs;
380: char *rawname();
381:
382: if (table == NULL)
383: return ((struct fstab *)0);
384: for (pf = table; pf; pf = pf->pf_next) {
385: fs = pf->pf_fstab;
386: if (strcmp(fs->fs_file, key) == 0)
387: return (fs);
388: if (strcmp(fs->fs_spec, key) == 0)
389: return (fs);
390: if (strcmp(rawname(fs->fs_spec), key) == 0)
391: return (fs);
392: if (key[0] != '/'){
393: if (*fs->fs_spec == '/' &&
394: strcmp(fs->fs_spec + 1, key) == 0)
395: return (fs);
396: if (*fs->fs_file == '/' &&
397: strcmp(fs->fs_file + 1, key) == 0)
398: return (fs);
399: }
400: }
401: return (0);
402: }
403:
404: /*
405: * Tell the operator what to do
406: */
407: lastdump(arg)
408: char arg; /* w ==> just what to do; W ==> most recent dumps */
409: {
410: char *lastname;
411: char *date;
412: register int i;
413: time_t tnow;
414: register struct fstab *dt;
415: int dumpme;
416: register struct idates *itwalk;
417:
418: int idatesort();
419:
420: time(&tnow);
421: getfstab(); /* /etc/fstab input */
422: inititimes(); /* /etc/dumpdates input */
423: qsort(idatev, nidates, sizeof(struct idates *), idatesort);
424:
425: if (arg == 'w')
426: fprintf(stdout, "Dump these file systems:\n");
427: else
428: fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n");
429: lastname = "??";
430: ITITERATE(i, itwalk){
431: if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0)
432: continue;
433: date = (char *)ctime(&itwalk->id_ddate);
434: date[16] = '\0'; /* blast away seconds and year */
435: lastname = itwalk->id_name;
436: dt = fstabsearch(itwalk->id_name);
437: dumpme = ( (dt != 0)
438: && (dt->fs_freq != 0)
439: && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY)));
440: if ( (arg != 'w') || dumpme)
441: fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
442: dumpme && (arg != 'w') ? '>' : ' ',
443: itwalk->id_name,
444: dt ? dt->fs_file : "",
445: itwalk->id_incno,
446: date
447: );
448: }
449: }
450:
451: int idatesort(p1, p2)
452: struct idates **p1, **p2;
453: {
454: int diff;
455:
456: diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name));
457: if (diff == 0)
458: return ((*p2)->id_ddate - (*p1)->id_ddate);
459: else
460: return (diff);
461: }
462:
463: int max(a,b)
464: int a, b;
465: {
466: return(a>b?a:b);
467: }
468: int min(a,b)
469: int a, b;
470: {
471: return(a<b?a:b);
472: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.