Mercurial > illumos > onarm
diff usr/src/cmd/backup/dump/dumpoptr.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/backup/dump/dumpoptr.c Tue Jun 02 18:56:50 2009 +0900 @@ -0,0 +1,476 @@ +/* + * Copyright (c) 1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#pragma ident "@(#)dumpoptr.c 1.66 05/03/08 SMI" + +#include <errno.h> +#include "dump.h" + +static unsigned int timeout; /* current timeout */ +static char *attnmessage, *saveattn; /* attention message */ + +#ifdef __STDC__ +static void alarmcatch(); +static int idatesort(const void *, const void *); +#else /* !__STDC__ */ +static void alarmcatch(); +static int idatesort(); +#endif + +#ifdef DEBUG +extern int xflag; +#endif + +/* + * Query the operator; This fascist piece of code requires + * an exact response. + * It is intended to protect dump aborting by inquisitive + * people banging on the console terminal to see what is + * happening which might cause dump to croak, destroying + * a large number of hours of work. + * + * Every time += 2 minutes we reprint the message, alerting others + * that dump needs attention. + */ +int +query(question) + char *question; +{ + int def = -1; + + while (def == -1) + def = query_once(question, -1); + return (def); +} + +static int in_query_once; +static jmp_buf sjalarmbuf; + +/* real simple check-sum */ +static int +addem(s) + char *s; +{ + int total = 0; + + if (s == (char *)NULL) + return (total); + while (*s) + total += *s++; + return (total); +} + +int +query_once(question, def) + char *question; + int def; +{ + static char *lastmsg; + static int lastmsgsum; + int msgsum; + char replybuffer[BUFSIZ]; + int back; + time32_t timeclockstate; + pollfd_t pollset; + struct sigvec sv; + + /* special hook to flush timeout cache */ + if (question == NULL) { + lastmsg = (char *)NULL; + lastmsgsum = 0; + return (0); + } + + attnmessage = question; + /* + * Only reset the state if the message changed somehow + */ + msgsum = addem(question); + if (lastmsg != question || lastmsgsum != msgsum) { + timeout = 0; + if (telapsed && tstart_writing) + *telapsed += time((time_t *)0) - *tstart_writing; + lastmsg = question; + lastmsgsum = msgsum; + } + timeclockstate = timeclock((time_t)0); + if (setjmp(sjalarmbuf) != 0) { + if (def != -1) { + if (def) + msgtail(gettext("YES\n")); + else + msgtail(gettext("NO\n")); + } + back = def; + goto done; + } + alarmcatch(); + in_query_once = 1; + pollset.fd = -1; + pollset.events = 0; + pollset.revents = 0; + if (isatty(fileno(stdin))) { + pollset.fd = fileno(stdin); + pollset.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; + } else { + dumpabort(); + /*NOTREACHED*/ + } + for (;;) { + if (poll(&pollset, 1, -1) < 0) { + if (errno == EINTR) + continue; + perror("poll(stdin)"); + dumpabort(); + /*NOTREACHED*/ + } + if (pollset.revents == 0) + continue; /* sanity check */ + if (fgets(replybuffer, sizeof (replybuffer), stdin) == NULL) { + if (ferror(stdin)) { + clearerr(stdin); + continue; + } else { + dumpabort(); + /*NOTREACHED*/ + } + } + timeout = 0; + if (strcasecmp(replybuffer, gettext("yes\n")) == 0) { + back = 1; + lastmsg = (char *)NULL; + lastmsgsum = 0; + goto done; + } else if (strcasecmp(replybuffer, gettext("no\n")) == 0) { + back = 0; + lastmsg = (char *)NULL; + lastmsgsum = 0; + goto done; + } else { + msg(gettext("\"yes\" or \"no\"?\n")); + in_query_once = 0; + alarmcatch(); + in_query_once = 1; + } + } +done: + /* + * Turn off the alarm, and reset the signal to trap out.. + */ + (void) alarm(0); + attnmessage = NULL; + sv.sv_handler = sigAbort; + sv.sv_flags = SA_RESTART; + (void) sigemptyset(&sv.sa_mask); + (void) sigvec(SIGALRM, &sv, (struct sigvec *)0); + if (tstart_writing) + (void) time(tstart_writing); + (void) timeclock(timeclockstate); + in_query_once = 0; + return (back); +} +/* + * Alert the console operator, and enable the alarm clock to + * sleep for time += 2 minutes in case nobody comes to satisfy dump + * If the alarm goes off while in the query_once for loop, we just + * longjmp back there and return the default answer. + */ +static void +#ifdef __STDC__ +alarmcatch(void) +#else +alarmcatch() +#endif +{ + struct sigvec sv; + + if (in_query_once) { + longjmp(sjalarmbuf, 1); + } + if (timeout) { + msgtail("\n"); + } + + timeout += 120; + msg(gettext("NEEDS ATTENTION: %s"), attnmessage); + sv.sv_handler = alarmcatch; + sv.sv_flags = SA_RESTART; + (void) sigemptyset(&sv.sa_mask); + (void) sigvec(SIGALRM, &sv, (struct sigvec *)0); + (void) alarm(timeout); +} + +/* + * Here if an inquisitive operator interrupts the dump program + */ +/*ARGSUSED*/ +void +interrupt(sig) + int sig; +{ + if (!saveattn) { + saveattn = attnmessage; + } + msg(gettext("Interrupt received.\n")); + if (query(gettext( + "Do you want to abort dump?: (\"yes\" or \"no\") "))) { + dumpabort(); + /*NOTREACHED*/ + } + if (saveattn) { + attnmessage = saveattn; + saveattn = NULL; + alarmcatch(); + } +} + +/* + * We use wall(1) to do the actual broadcasting, so + * that we don't have to worry about duplicated code + * only getting fixed in one place. This also saves + * us from having to worry about process groups, + * controlling terminals, and the like. + */ +void +broadcast(message) + char *message; +{ + time_t clock; + pid_t pid; + int saverr; + int fildes[2]; + FILE *wall; + struct tm *localclock; + + if (!notify) + return; + + if (pipe(fildes) < 0) { + saverr = errno; + msg(gettext("pipe: %s\n"), strerror(saverr)); + return; + } + + switch (pid = fork()) { + case -1: + return; + case 0: + close(fildes[0]); + if (dup2(fildes[1], 0) < 0) { + saverr = errno; + msg(gettext("dup2: %s\n"), strerror(saverr)); + exit(1); + } + execl("/usr/sbin/wall", "wall", "-g", OPGRENT, (char *)NULL); + saverr = errno; + msg(gettext("execl: %s\n"), strerror(saverr)); + exit(1); + default: + break; /* parent */ + } + + close(fildes[1]); + wall = fdopen(fildes[0], "r+"); + if (wall == (FILE *)NULL) { + saverr = errno; + msg(gettext("fdopen: %s\n"), strerror(saverr)); + return; + } + + clock = time((time_t *)0); + localclock = localtime(&clock); + + (void) fprintf(wall, gettext( +"\n\007\007\007Message from the dump program to all operators at \ +%d:%02d ...\n\n%s"), + localclock->tm_hour, localclock->tm_min, message); + fclose(wall); + + while (wait((int *)0) != pid) { + continue; + /*LINTED [empty loop body]*/ + } +} + +/* + * print out an estimate of the amount of time left to do the dump + */ +#define EST_SEC 600 /* every 10 minutes */ +void +timeest(force, blkswritten) + int force; + int blkswritten; +{ + time_t tnow, deltat; + char *msgp; + + if (tschedule == NULL) + return; + if (*tschedule == 0) + *tschedule = time((time_t *)0) + EST_SEC; + (void) time(&tnow); + if ((force || tnow >= *tschedule) && blkswritten) { + *tschedule = tnow + EST_SEC; + if (!force && blkswritten < 50 * ntrec) + return; + deltat = (*telapsed + (tnow - *tstart_writing)) + * ((double)esize / blkswritten - 1.0); + msgp = gettext("%3.2f%% done, finished in %d:%02d\n"); + msg(msgp, (blkswritten*100.0)/esize, + deltat/3600, (deltat%3600)/60); + } +} + +#include <stdarg.h> + +/* VARARGS1 */ +void +msg(const char *fmt, ...) +{ + char buf[1024], *cp; + size_t size; + va_list args; + + va_start(args, fmt); + (void) strcpy(buf, " DUMP: "); + cp = &buf[strlen(buf)]; +#ifdef TDEBUG + (void) sprintf(cp, "pid=%d ", getpid()); + cp = &buf[strlen(buf)]; +#endif + /* don't need -1, vsnprintf does it right */ + /* LINTED pointer arithmetic result fits in size_t */ + size = ((size_t)sizeof (buf)) - (size_t)(cp - buf); + (void) vsnprintf(cp, size, fmt, args); + (void) fputs(buf, stderr); + (void) fflush(stdout); + (void) fflush(stderr); + va_end(args); +} + +/* VARARGS1 */ +void +msgtail(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + (void) vfprintf(stderr, fmt, args); + va_end(args); +} + +#define MINUTES(x) ((x) * 60) + +/* + * Tell the operator what has to be done; + * we don't actually do it + */ +void +lastdump(arg) /* w ==> just what to do; W ==> most recent dumps */ + int arg; +{ + char *lastname; + char *date; + int i; + time_t tnow, ddate; + struct mntent *dt; + int dumpme = 0; + struct idates *itwalk; + + (void) time(&tnow); + mnttabread(); /* /etc/fstab input */ + inititimes(); /* /etc/dumpdates input */ + + /* Don't use msg(), this isn't a tell-the-world kind of thing */ + if (arg == 'w') + (void) fprintf(stdout, gettext("Dump these file systems:\n")); + else + (void) fprintf(stdout, gettext( + "Last dump(s) done (Dump '>' file systems):\n")); + + if (idatev != NULL) { + qsort((char *)idatev, nidates, sizeof (*idatev), idatesort); + lastname = "??"; + ITITERATE(i, itwalk) { + if (strncmp(lastname, itwalk->id_name, + sizeof (itwalk->id_name)) == 0) + continue; + /* must be ctime(), per ufsdump(4) */ + ddate = itwalk->id_ddate; + date = (char *)ctime(&ddate); + date[16] = '\0'; /* blow away seconds and year */ + lastname = itwalk->id_name; + dt = mnttabsearch(itwalk->id_name, 0); + if ((time_t)(itwalk->id_ddate) < (tnow - DAY)) { + dumpme = 1; + } + + if ((arg == 'w') && dumpme) { + /* + * Handle the w option: print out file systems + * which haven't been backed up within a day. + */ + (void) printf(gettext("%8s\t(%6s)\n"), + itwalk->id_name, dt ? dt->mnt_dir : ""); + } + if (arg == 'W') { + /* + * Handle the W option: print out ALL + * filesystems including recent dump dates and + * dump levels. Mark the backup-needing + * filesystems with a >. + */ + (void) printf(gettext( + "%c %8s\t(%6s) Last dump: Level %c, Date %s\n"), + dumpme ? '>' : ' ', + itwalk->id_name, + dt ? dt->mnt_dir : "", + (uchar_t)itwalk->id_incno, + date); + } + dumpme = 0; + } + } +} + +static int +idatesort(v1, v2) +#ifdef __STDC__ + const void *v1; + const void *v2; +#else + void *v1; + void *v2; +#endif +{ + struct idates **p1 = (struct idates **)v1; + struct idates **p2 = (struct idates **)v2; + int diff; + + diff = strcoll((*p1)->id_name, (*p2)->id_name); + if (diff == 0) { + /* + * Time may eventually become unsigned, so can't + * rely on subtraction to give a useful result. + * Note that we are sorting dates into reverse + * order, so that we will report based on the + * most-recent record for a particular filesystem. + */ + if ((*p1)->id_ddate > (*p2)->id_ddate) + diff = -1; + else if ((*p1)->id_ddate < (*p2)->id_ddate) + diff = 1; + } + return (diff); +}