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