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