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