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