LUNA-II (68040 based LUNA) support
[unix-history] / usr / src / sbin / dump / optr.c
CommitLineData
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 9static 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
38void alarmcatch __P((/* int, int */));
39int datesort __P((const void *, const void *));
40static 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
53static int timeout;
54static char *attnmessage; /* attention message */
e6ee6826
CT
55
56int
f3869107
BJ
57query(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
98char 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 104void
f3869107
BJ
105alarmcatch()
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 130void
71b2d5ef
KB
131interrupt(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 144struct group *gp;
f3869107
BJ
145
146/*
147 * Get the names from the group entry "operator" to notify.
148 */
e6ee6826 149void
f3869107
BJ
150set_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
163struct 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 169void
f3869107
BJ
170broadcast(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 225static void
f3869107 226sendmes(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\
242DUMP: 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
266time_t tschedule = 0;
267
e6ee6826 268void
f3869107
BJ
269timeest()
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 287void
226b33ce 288#if __STDC__
92f1f317 289msg(const char *fmt, ...)
226b33ce 290#else
92f1f317
KB
291msg(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
314void
315#if __STDC__
316msgtail(const char *fmt, ...)
317#else
318msgtail(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
333void
334#if __STDC__
335quit(const char *fmt, ...)
336#else
337quit(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
365struct fstab *
366allocfsent(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
382struct pfstab {
383 struct pfstab *pf_next;
384 struct fstab *pf_fstab;
385};
386
e6ee6826 387static struct pfstab *table;
2bfbb1f9 388
e6ee6826 389void
f3869107
BJ
390getfstab()
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
426struct fstab *
427fstabsearch(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 454void
77db894d 455lastdump(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
497int
498datesort(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}