|
|
1.1 root 1: static char *sccsid = "@(#)dumpoptr.c 1.4 (Berkeley) 12/17/80";
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: getfstab()
280: {
281: register struct fstab *dt;
282: struct fstab *fsp;
283:
284: nfstab = 0;
285: if (setfsent() == 0) {
286: msg("Can't open %s for dump table information.\n", FSTAB);
287: } else {
288: for (nfstab = 0, dt = fstab; nfstab < MAXFSTAB;){
289: if ( (fsp = getfsent()) == 0)
290: break;
291: if ( (strcmp(fsp->fs_type, FSTAB_RW) == 0)
292: || (strcmp(fsp->fs_type, FSTAB_RO) == 0) ){
293: *dt = *fsp;
294: nfstab++;
295: dt++;
296: }
297: }
298: endfsent();
299: }
300: }
301:
302: /*
303: * Search in the fstab for a file name.
304: * This file name can be either the special or the path file name.
305: *
306: * The entries in the fstab are the BLOCK special names, not the
307: * character special names.
308: * The caller of fstabsearch assures that the character device
309: * is dumped (that is much faster)
310: *
311: * The file name can omit the leading '/'.
312: */
313: struct fstab *fstabsearch(key)
314: char *key;
315: {
316: register struct fstab *dt;
317: int i;
318: int keylength;
319: char *rawname();
320:
321: keylength = min(strlen(key), sizeof (dt->fs_file));
322: for (i = 0, dt = fstab; i < nfstab; i++, dt++){
323: if (strncmp(dt->fs_file, key, keylength) == 0)
324: return(dt);
325: if (strncmp(dt->fs_spec, key, keylength) == 0)
326: return(dt);
327: if (strncmp(rawname(dt->fs_spec), key, keylength) == 0)
328: return(dt);
329:
330: if (key[0] != '/'){
331: if ( (dt->fs_spec[0] == '/')
332: && (strncmp(dt->fs_spec+1, key, keylength) == 0))
333: return(dt);
334: if ( (dt->fs_file[0] == '/')
335: && (strncmp(dt->fs_file+1, key, keylength) == 0))
336: return(dt);
337: }
338: }
339: return(0);
340: }
341:
342: /*
343: * Tell the operator what to do
344: */
345: lastdump(arg)
346: char arg; /* w ==> just what to do; W ==> most recent dumps */
347: {
348: char *lastname;
349: char *date;
350: register int i;
351: time_t tnow;
352: register struct fstab *dt;
353: int dumpme;
354: register struct idates *itwalk;
355:
356: int idatesort();
357:
358: time(&tnow);
359: getfstab(); /* /etc/fstab input */
360: inititimes(); /* /etc/dumpdates input */
361: qsort(idatev, nidates, sizeof(struct idates *), idatesort);
362:
363: if (arg == 'w')
364: fprintf(stdout, "Dump these file systems:\n");
365: else
366: fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n");
367: lastname = "??";
368: ITITERATE(i, itwalk){
369: if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0)
370: continue;
371: date = (char *)ctime(&itwalk->id_ddate);
372: date[16] = '\0'; /* blast away seconds and year */
373: lastname = itwalk->id_name;
374: dt = fstabsearch(itwalk->id_name);
375: dumpme = ( (dt != 0)
376: && (dt->fs_freq != 0)
377: && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY)));
378: if ( (arg != 'w') || dumpme)
379: fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
380: dumpme && (arg != 'w') ? '>' : ' ',
381: itwalk->id_name,
382: dt ? dt->fs_file : 0,
383: itwalk->id_incno,
384: date
385: );
386: }
387: }
388:
389: int idatesort(p1, p2)
390: struct idates **p1, **p2;
391: {
392: int diff;
393:
394: diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name));
395: if (diff == 0)
396: return ((*p2)->id_ddate - (*p1)->id_ddate);
397: else
398: return (diff);
399: }
400:
401: int max(a,b)
402: {
403: return(a>b?a:b);
404: }
405: int min(a,b)
406: {
407: return(a<b?a:b);
408: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.