add rps and minfree arguments
[unix-history] / usr / src / sbin / dump / optr.c
CommitLineData
1ddebffe 1static char *sccsid = "@(#)optr.c 1.6 (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
282getfstab()
283{
284 register struct fstab *dt;
9ba0a26f 285 struct fstab *fsp;
f3869107
BJ
286
287 nfstab = 0;
9ba0a26f 288 if (setfsent() == 0) {
f3869107
BJ
289 msg("Can't open %s for dump table information.\n", FSTAB);
290 } else {
291 for (nfstab = 0, dt = fstab; nfstab < MAXFSTAB;){
9ba0a26f 292 if ( (fsp = getfsent()) == 0)
f3869107 293 break;
9ba0a26f
BJ
294 if ( (strcmp(fsp->fs_type, FSTAB_RW) == 0)
295 || (strcmp(fsp->fs_type, FSTAB_RO) == 0) ){
296 *dt = *fsp;
297 nfstab++;
298 dt++;
299 }
f3869107 300 }
9ba0a26f 301 endfsent();
f3869107
BJ
302 }
303}
304
305/*
306 * Search in the fstab for a file name.
307 * This file name can be either the special or the path file name.
308 *
309 * The entries in the fstab are the BLOCK special names, not the
310 * character special names.
311 * The caller of fstabsearch assures that the character device
312 * is dumped (that is much faster)
313 *
314 * The file name can omit the leading '/'.
315 */
316struct fstab *fstabsearch(key)
317 char *key;
318{
319 register struct fstab *dt;
320 int i;
321 int keylength;
322 char *rawname();
323
324 keylength = min(strlen(key), sizeof (dt->fs_file));
325 for (i = 0, dt = fstab; i < nfstab; i++, dt++){
326 if (strncmp(dt->fs_file, key, keylength) == 0)
327 return(dt);
328 if (strncmp(dt->fs_spec, key, keylength) == 0)
329 return(dt);
330 if (strncmp(rawname(dt->fs_spec), key, keylength) == 0)
331 return(dt);
332
333 if (key[0] != '/'){
334 if ( (dt->fs_spec[0] == '/')
335 && (strncmp(dt->fs_spec+1, key, keylength) == 0))
336 return(dt);
337 if ( (dt->fs_file[0] == '/')
338 && (strncmp(dt->fs_file+1, key, keylength) == 0))
339 return(dt);
340 }
341 }
342 return(0);
343}
344
345/*
346 * Tell the operator what to do
347 */
77db894d
BJ
348lastdump(arg)
349 char arg; /* w ==> just what to do; W ==> most recent dumps */
f3869107
BJ
350{
351 char *lastname;
352 char *date;
353 register int i;
354 time_t tnow;
355 register struct fstab *dt;
356 int dumpme;
357 register struct idates *itwalk;
358
359 int idatesort();
360
361 time(&tnow);
362 getfstab(); /* /etc/fstab input */
363 inititimes(); /* /etc/dumpdates input */
364 qsort(idatev, nidates, sizeof(struct idates *), idatesort);
365
77db894d
BJ
366 if (arg == 'w')
367 fprintf(stdout, "Dump these file systems:\n");
368 else
369 fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n");
f3869107
BJ
370 lastname = "??";
371 ITITERATE(i, itwalk){
372 if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0)
373 continue;
374 date = (char *)ctime(&itwalk->id_ddate);
375 date[16] = '\0'; /* blast away seconds and year */
376 lastname = itwalk->id_name;
377 dt = fstabsearch(itwalk->id_name);
378 dumpme = ( (dt != 0)
379 && (dt->fs_freq != 0)
380 && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY)));
77db894d
BJ
381 if ( (arg != 'w') || dumpme)
382 fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
383 dumpme && (arg != 'w') ? '>' : ' ',
f3869107 384 itwalk->id_name,
1ddebffe 385 dt ? dt->fs_file : "",
f3869107
BJ
386 itwalk->id_incno,
387 date
388 );
389 }
390}
391
392int idatesort(p1, p2)
393 struct idates **p1, **p2;
394{
395 int diff;
396
397 diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name));
398 if (diff == 0)
399 return ((*p2)->id_ddate - (*p1)->id_ddate);
400 else
401 return (diff);
402}
403
404int max(a,b)
661913e7 405 int a, b;
f3869107
BJ
406{
407 return(a>b?a:b);
408}
409int min(a,b)
661913e7 410 int a, b;
f3869107
BJ
411{
412 return(a<b?a:b);
413}