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