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