2 * Copyright (c) 1998 by Sun Microsystems, Inc.
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
20 static unsigned int timeout
; /* current timeout */
21 static char *attnmessage
, *saveattn
; /* attention message */
24 static void alarmcatch();
25 static int idatesort(const void *, const void *);
27 static void alarmcatch();
28 static int idatesort();
36 * Query the operator; This fascist piece of code requires
38 * It is intended to protect dump aborting by inquisitive
39 * people banging on the console terminal to see what is
40 * happening which might cause dump to croak, destroying
41 * a large number of hours of work.
43 * Every time += 2 minutes we reprint the message, alerting others
44 * that dump needs attention.
53 def
= query_once(question
, -1);
57 static int in_query_once
;
58 static jmp_buf sjalarmbuf
;
60 /* real simple check-sum */
67 if (s
== (char *)NULL
)
75 query_once(question
, def
)
80 static int lastmsgsum
;
82 char replybuffer
[BUFSIZ
];
84 time32_t timeclockstate
;
88 /* special hook to flush timeout cache */
89 if (question
== NULL
) {
90 lastmsg
= (char *)NULL
;
95 attnmessage
= question
;
97 * Only reset the state if the message changed somehow
99 msgsum
= addem(question
);
100 if (lastmsg
!= question
|| lastmsgsum
!= msgsum
) {
102 if (telapsed
&& tstart_writing
)
103 *telapsed
+= time((time_t *)0) - *tstart_writing
;
107 timeclockstate
= timeclock((time_t)0);
108 if (setjmp(sjalarmbuf
) != 0) {
111 msgtail(gettext("YES\n"));
113 msgtail(gettext("NO\n"));
123 if (isatty(fileno(stdin
))) {
124 pollset
.fd
= fileno(stdin
);
125 pollset
.events
= POLLIN
| POLLPRI
| POLLRDNORM
| POLLRDBAND
;
131 if (poll(&pollset
, 1, -1) < 0) {
134 perror("poll(stdin)");
138 if (pollset
.revents
== 0)
139 continue; /* sanity check */
140 if (fgets(replybuffer
, sizeof (replybuffer
), stdin
) == NULL
) {
150 if (strcasecmp(replybuffer
, gettext("yes\n")) == 0) {
152 lastmsg
= (char *)NULL
;
155 } else if (strcasecmp(replybuffer
, gettext("no\n")) == 0) {
157 lastmsg
= (char *)NULL
;
161 msg(gettext("\"yes\" or \"no\"?\n"));
169 * Turn off the alarm, and reset the signal to trap out..
173 sv
.sv_handler
= sigAbort
;
174 sv
.sv_flags
= SA_RESTART
;
175 (void) sigemptyset(&sv
.sa_mask
);
176 (void) sigvec(SIGALRM
, &sv
, (struct sigvec
*)0);
178 (void) time(tstart_writing
);
179 (void) timeclock(timeclockstate
);
184 * Alert the console operator, and enable the alarm clock to
185 * sleep for time += 2 minutes in case nobody comes to satisfy dump
186 * If the alarm goes off while in the query_once for loop, we just
187 * longjmp back there and return the default answer.
199 longjmp(sjalarmbuf
, 1);
206 msg(gettext("NEEDS ATTENTION: %s"), attnmessage
);
207 sv
.sv_handler
= alarmcatch
;
208 sv
.sv_flags
= SA_RESTART
;
209 (void) sigemptyset(&sv
.sa_mask
);
210 (void) sigvec(SIGALRM
, &sv
, (struct sigvec
*)0);
211 (void) alarm(timeout
);
215 * Here if an inquisitive operator interrupts the dump program
223 saveattn
= attnmessage
;
225 msg(gettext("Interrupt received.\n"));
227 "Do you want to abort dump?: (\"yes\" or \"no\") "))) {
232 attnmessage
= saveattn
;
239 * We use wall(1) to do the actual broadcasting, so
240 * that we don't have to worry about duplicated code
241 * only getting fixed in one place. This also saves
242 * us from having to worry about process groups,
243 * controlling terminals, and the like.
254 struct tm
*localclock
;
259 if (pipe(fildes
) < 0) {
261 msg(gettext("pipe: %s\n"), strerror(saverr
));
265 switch (pid
= fork()) {
270 if (dup2(fildes
[1], 0) < 0) {
272 msg(gettext("dup2: %s\n"), strerror(saverr
));
275 execl("/usr/sbin/wall", "wall", "-g", OPGRENT
, (char *)NULL
);
277 msg(gettext("execl: %s\n"), strerror(saverr
));
284 wall
= fdopen(fildes
[0], "r+");
285 if (wall
== (FILE *)NULL
) {
287 msg(gettext("fdopen: %s\n"), strerror(saverr
));
291 clock
= time((time_t *)0);
292 localclock
= localtime(&clock
);
294 (void) fprintf(wall
, gettext(
295 "\n\007\007\007Message from the dump program to all operators at \
297 localclock
->tm_hour
, localclock
->tm_min
, message
);
300 while (wait((int *)0) != pid
) {
302 /*LINTED [empty loop body]*/
307 * print out an estimate of the amount of time left to do the dump
309 #define EST_SEC 600 /* every 10 minutes */
311 timeest(force
, blkswritten
)
318 if (tschedule
== NULL
)
321 *tschedule
= time((time_t *)0) + EST_SEC
;
323 if ((force
|| tnow
>= *tschedule
) && blkswritten
) {
324 *tschedule
= tnow
+ EST_SEC
;
325 if (!force
&& blkswritten
< 50 * ntrec
)
327 deltat
= (*telapsed
+ (tnow
- *tstart_writing
))
328 * ((double)esize
/ blkswritten
- 1.0);
329 msgp
= gettext("%3.2f%% done, finished in %d:%02d\n");
330 msg(msgp
, (blkswritten
*100.0)/esize
,
331 deltat
/3600, (deltat
%3600)/60);
339 msg(const char *fmt
, ...)
346 (void) strcpy(buf
, " DUMP: ");
347 cp
= &buf
[strlen(buf
)];
349 (void) sprintf(cp
, "pid=%d ", getpid());
350 cp
= &buf
[strlen(buf
)];
352 /* don't need -1, vsnprintf does it right */
353 /* LINTED pointer arithmetic result fits in size_t */
354 size
= ((size_t)sizeof (buf
)) - (size_t)(cp
- buf
);
355 (void) vsnprintf(cp
, size
, fmt
, args
);
356 (void) fputs(buf
, stderr
);
357 (void) fflush(stdout
);
358 (void) fflush(stderr
);
364 msgtail(const char *fmt
, ...)
369 (void) vfprintf(stderr
, fmt
, args
);
373 #define MINUTES(x) ((x) * 60)
376 * Tell the operator what has to be done;
377 * we don't actually do it
380 lastdump(arg
) /* w ==> just what to do; W ==> most recent dumps */
389 struct idates
*itwalk
;
392 mnttabread(); /* /etc/fstab input */
393 inititimes(); /* /etc/dumpdates input */
395 /* Don't use msg(), this isn't a tell-the-world kind of thing */
397 (void) fprintf(stdout
, gettext("Dump these file systems:\n"));
399 (void) fprintf(stdout
, gettext(
400 "Last dump(s) done (Dump '>' file systems):\n"));
402 if (idatev
!= NULL
) {
403 qsort((char *)idatev
, nidates
, sizeof (*idatev
), idatesort
);
405 ITITERATE(i
, itwalk
) {
406 if (strncmp(lastname
, itwalk
->id_name
,
407 sizeof (itwalk
->id_name
)) == 0)
409 /* must be ctime(), per ufsdump(4) */
410 ddate
= itwalk
->id_ddate
;
411 date
= (char *)ctime(&ddate
);
412 date
[16] = '\0'; /* blow away seconds and year */
413 lastname
= itwalk
->id_name
;
414 dt
= mnttabsearch(itwalk
->id_name
, 0);
415 if ((time_t)(itwalk
->id_ddate
) < (tnow
- DAY
)) {
419 if ((arg
== 'w') && dumpme
) {
421 * Handle the w option: print out file systems
422 * which haven't been backed up within a day.
424 (void) printf(gettext("%8s\t(%6s)\n"),
425 itwalk
->id_name
, dt
? dt
->mnt_dir
: "");
429 * Handle the W option: print out ALL
430 * filesystems including recent dump dates and
431 * dump levels. Mark the backup-needing
432 * filesystems with a >.
434 (void) printf(gettext(
435 "%c %8s\t(%6s) Last dump: Level %c, Date %s\n"),
438 dt
? dt
->mnt_dir
: "",
439 (uchar_t
)itwalk
->id_incno
,
457 struct idates
**p1
= (struct idates
**)v1
;
458 struct idates
**p2
= (struct idates
**)v2
;
461 diff
= strcoll((*p1
)->id_name
, (*p2
)->id_name
);
464 * Time may eventually become unsigned, so can't
465 * rely on subtraction to give a useful result.
466 * Note that we are sorting dates into reverse
467 * order, so that we will report based on the
468 * most-recent record for a particular filesystem.
470 if ((*p1
)->id_ddate
> (*p2
)->id_ddate
)
472 else if ((*p1
)->id_ddate
< (*p2
)->id_ddate
)