1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 1998 by Sun Microsystems, Inc. 3*0Sstevel@tonic-gate * All rights reserved. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7*0Sstevel@tonic-gate /* All Rights Reserved */ 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gate /* 10*0Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 11*0Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 12*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 13*0Sstevel@tonic-gate */ 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #include <errno.h> 18*0Sstevel@tonic-gate #include "dump.h" 19*0Sstevel@tonic-gate 20*0Sstevel@tonic-gate static unsigned int timeout; /* current timeout */ 21*0Sstevel@tonic-gate static char *attnmessage, *saveattn; /* attention message */ 22*0Sstevel@tonic-gate 23*0Sstevel@tonic-gate #ifdef __STDC__ 24*0Sstevel@tonic-gate static void alarmcatch(); 25*0Sstevel@tonic-gate static int idatesort(const void *, const void *); 26*0Sstevel@tonic-gate #else /* !__STDC__ */ 27*0Sstevel@tonic-gate static void alarmcatch(); 28*0Sstevel@tonic-gate static int idatesort(); 29*0Sstevel@tonic-gate #endif 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #ifdef DEBUG 32*0Sstevel@tonic-gate extern int xflag; 33*0Sstevel@tonic-gate #endif 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate /* 36*0Sstevel@tonic-gate * Query the operator; This fascist piece of code requires 37*0Sstevel@tonic-gate * an exact response. 38*0Sstevel@tonic-gate * It is intended to protect dump aborting by inquisitive 39*0Sstevel@tonic-gate * people banging on the console terminal to see what is 40*0Sstevel@tonic-gate * happening which might cause dump to croak, destroying 41*0Sstevel@tonic-gate * a large number of hours of work. 42*0Sstevel@tonic-gate * 43*0Sstevel@tonic-gate * Every time += 2 minutes we reprint the message, alerting others 44*0Sstevel@tonic-gate * that dump needs attention. 45*0Sstevel@tonic-gate */ 46*0Sstevel@tonic-gate int 47*0Sstevel@tonic-gate query(question) 48*0Sstevel@tonic-gate char *question; 49*0Sstevel@tonic-gate { 50*0Sstevel@tonic-gate int def = -1; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate while (def == -1) 53*0Sstevel@tonic-gate def = query_once(question, -1); 54*0Sstevel@tonic-gate return (def); 55*0Sstevel@tonic-gate } 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate static int in_query_once; 58*0Sstevel@tonic-gate static jmp_buf sjalarmbuf; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate /* real simple check-sum */ 61*0Sstevel@tonic-gate static int 62*0Sstevel@tonic-gate addem(s) 63*0Sstevel@tonic-gate char *s; 64*0Sstevel@tonic-gate { 65*0Sstevel@tonic-gate int total = 0; 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate if (s == (char *)NULL) 68*0Sstevel@tonic-gate return (total); 69*0Sstevel@tonic-gate while (*s) 70*0Sstevel@tonic-gate total += *s++; 71*0Sstevel@tonic-gate return (total); 72*0Sstevel@tonic-gate } 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate int 75*0Sstevel@tonic-gate query_once(question, def) 76*0Sstevel@tonic-gate char *question; 77*0Sstevel@tonic-gate int def; 78*0Sstevel@tonic-gate { 79*0Sstevel@tonic-gate static char *lastmsg; 80*0Sstevel@tonic-gate static int lastmsgsum; 81*0Sstevel@tonic-gate int msgsum; 82*0Sstevel@tonic-gate char replybuffer[BUFSIZ]; 83*0Sstevel@tonic-gate int back; 84*0Sstevel@tonic-gate time32_t timeclockstate; 85*0Sstevel@tonic-gate pollfd_t pollset; 86*0Sstevel@tonic-gate struct sigvec sv; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* special hook to flush timeout cache */ 89*0Sstevel@tonic-gate if (question == NULL) { 90*0Sstevel@tonic-gate lastmsg = (char *)NULL; 91*0Sstevel@tonic-gate lastmsgsum = 0; 92*0Sstevel@tonic-gate return (0); 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate attnmessage = question; 96*0Sstevel@tonic-gate /* 97*0Sstevel@tonic-gate * Only reset the state if the message changed somehow 98*0Sstevel@tonic-gate */ 99*0Sstevel@tonic-gate msgsum = addem(question); 100*0Sstevel@tonic-gate if (lastmsg != question || lastmsgsum != msgsum) { 101*0Sstevel@tonic-gate timeout = 0; 102*0Sstevel@tonic-gate if (telapsed && tstart_writing) 103*0Sstevel@tonic-gate *telapsed += time((time_t *)0) - *tstart_writing; 104*0Sstevel@tonic-gate lastmsg = question; 105*0Sstevel@tonic-gate lastmsgsum = msgsum; 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate timeclockstate = timeclock((time_t)0); 108*0Sstevel@tonic-gate if (setjmp(sjalarmbuf) != 0) { 109*0Sstevel@tonic-gate if (def != -1) { 110*0Sstevel@tonic-gate if (def) 111*0Sstevel@tonic-gate msgtail(gettext("YES\n")); 112*0Sstevel@tonic-gate else 113*0Sstevel@tonic-gate msgtail(gettext("NO\n")); 114*0Sstevel@tonic-gate } 115*0Sstevel@tonic-gate back = def; 116*0Sstevel@tonic-gate goto done; 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate alarmcatch(); 119*0Sstevel@tonic-gate in_query_once = 1; 120*0Sstevel@tonic-gate pollset.fd = -1; 121*0Sstevel@tonic-gate pollset.events = 0; 122*0Sstevel@tonic-gate pollset.revents = 0; 123*0Sstevel@tonic-gate if (isatty(fileno(stdin))) { 124*0Sstevel@tonic-gate pollset.fd = fileno(stdin); 125*0Sstevel@tonic-gate pollset.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; 126*0Sstevel@tonic-gate } else { 127*0Sstevel@tonic-gate dumpabort(); 128*0Sstevel@tonic-gate /*NOTREACHED*/ 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate for (;;) { 131*0Sstevel@tonic-gate if (poll(&pollset, 1, -1) < 0) { 132*0Sstevel@tonic-gate if (errno == EINTR) 133*0Sstevel@tonic-gate continue; 134*0Sstevel@tonic-gate perror("poll(stdin)"); 135*0Sstevel@tonic-gate dumpabort(); 136*0Sstevel@tonic-gate /*NOTREACHED*/ 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate if (pollset.revents == 0) 139*0Sstevel@tonic-gate continue; /* sanity check */ 140*0Sstevel@tonic-gate if (fgets(replybuffer, sizeof (replybuffer), stdin) == NULL) { 141*0Sstevel@tonic-gate if (ferror(stdin)) { 142*0Sstevel@tonic-gate clearerr(stdin); 143*0Sstevel@tonic-gate continue; 144*0Sstevel@tonic-gate } else { 145*0Sstevel@tonic-gate dumpabort(); 146*0Sstevel@tonic-gate /*NOTREACHED*/ 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate timeout = 0; 150*0Sstevel@tonic-gate if (strcasecmp(replybuffer, gettext("yes\n")) == 0) { 151*0Sstevel@tonic-gate back = 1; 152*0Sstevel@tonic-gate lastmsg = (char *)NULL; 153*0Sstevel@tonic-gate lastmsgsum = 0; 154*0Sstevel@tonic-gate goto done; 155*0Sstevel@tonic-gate } else if (strcasecmp(replybuffer, gettext("no\n")) == 0) { 156*0Sstevel@tonic-gate back = 0; 157*0Sstevel@tonic-gate lastmsg = (char *)NULL; 158*0Sstevel@tonic-gate lastmsgsum = 0; 159*0Sstevel@tonic-gate goto done; 160*0Sstevel@tonic-gate } else { 161*0Sstevel@tonic-gate msg(gettext("\"yes\" or \"no\"?\n")); 162*0Sstevel@tonic-gate in_query_once = 0; 163*0Sstevel@tonic-gate alarmcatch(); 164*0Sstevel@tonic-gate in_query_once = 1; 165*0Sstevel@tonic-gate } 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate done: 168*0Sstevel@tonic-gate /* 169*0Sstevel@tonic-gate * Turn off the alarm, and reset the signal to trap out.. 170*0Sstevel@tonic-gate */ 171*0Sstevel@tonic-gate (void) alarm(0); 172*0Sstevel@tonic-gate attnmessage = NULL; 173*0Sstevel@tonic-gate sv.sv_handler = sigAbort; 174*0Sstevel@tonic-gate sv.sv_flags = SA_RESTART; 175*0Sstevel@tonic-gate (void) sigemptyset(&sv.sa_mask); 176*0Sstevel@tonic-gate (void) sigvec(SIGALRM, &sv, (struct sigvec *)0); 177*0Sstevel@tonic-gate if (tstart_writing) 178*0Sstevel@tonic-gate (void) time(tstart_writing); 179*0Sstevel@tonic-gate (void) timeclock(timeclockstate); 180*0Sstevel@tonic-gate in_query_once = 0; 181*0Sstevel@tonic-gate return (back); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate /* 184*0Sstevel@tonic-gate * Alert the console operator, and enable the alarm clock to 185*0Sstevel@tonic-gate * sleep for time += 2 minutes in case nobody comes to satisfy dump 186*0Sstevel@tonic-gate * If the alarm goes off while in the query_once for loop, we just 187*0Sstevel@tonic-gate * longjmp back there and return the default answer. 188*0Sstevel@tonic-gate */ 189*0Sstevel@tonic-gate static void 190*0Sstevel@tonic-gate #ifdef __STDC__ 191*0Sstevel@tonic-gate alarmcatch(void) 192*0Sstevel@tonic-gate #else 193*0Sstevel@tonic-gate alarmcatch() 194*0Sstevel@tonic-gate #endif 195*0Sstevel@tonic-gate { 196*0Sstevel@tonic-gate struct sigvec sv; 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate if (in_query_once) { 199*0Sstevel@tonic-gate longjmp(sjalarmbuf, 1); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate if (timeout) { 202*0Sstevel@tonic-gate msgtail("\n"); 203*0Sstevel@tonic-gate } 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate timeout += 120; 206*0Sstevel@tonic-gate msg(gettext("NEEDS ATTENTION: %s"), attnmessage); 207*0Sstevel@tonic-gate sv.sv_handler = alarmcatch; 208*0Sstevel@tonic-gate sv.sv_flags = SA_RESTART; 209*0Sstevel@tonic-gate (void) sigemptyset(&sv.sa_mask); 210*0Sstevel@tonic-gate (void) sigvec(SIGALRM, &sv, (struct sigvec *)0); 211*0Sstevel@tonic-gate (void) alarm(timeout); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * Here if an inquisitive operator interrupts the dump program 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate /*ARGSUSED*/ 218*0Sstevel@tonic-gate void 219*0Sstevel@tonic-gate interrupt(sig) 220*0Sstevel@tonic-gate int sig; 221*0Sstevel@tonic-gate { 222*0Sstevel@tonic-gate if (!saveattn) { 223*0Sstevel@tonic-gate saveattn = attnmessage; 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate msg(gettext("Interrupt received.\n")); 226*0Sstevel@tonic-gate if (query(gettext( 227*0Sstevel@tonic-gate "Do you want to abort dump?: (\"yes\" or \"no\") "))) { 228*0Sstevel@tonic-gate dumpabort(); 229*0Sstevel@tonic-gate /*NOTREACHED*/ 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate if (saveattn) { 232*0Sstevel@tonic-gate attnmessage = saveattn; 233*0Sstevel@tonic-gate saveattn = NULL; 234*0Sstevel@tonic-gate alarmcatch(); 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate /* 239*0Sstevel@tonic-gate * We use wall(1) to do the actual broadcasting, so 240*0Sstevel@tonic-gate * that we don't have to worry about duplicated code 241*0Sstevel@tonic-gate * only getting fixed in one place. This also saves 242*0Sstevel@tonic-gate * us from having to worry about process groups, 243*0Sstevel@tonic-gate * controlling terminals, and the like. 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate void 246*0Sstevel@tonic-gate broadcast(message) 247*0Sstevel@tonic-gate char *message; 248*0Sstevel@tonic-gate { 249*0Sstevel@tonic-gate time_t clock; 250*0Sstevel@tonic-gate pid_t pid; 251*0Sstevel@tonic-gate int saverr; 252*0Sstevel@tonic-gate int fildes[2]; 253*0Sstevel@tonic-gate FILE *wall; 254*0Sstevel@tonic-gate struct tm *localclock; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate if (!notify) 257*0Sstevel@tonic-gate return; 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate if (pipe(fildes) < 0) { 260*0Sstevel@tonic-gate saverr = errno; 261*0Sstevel@tonic-gate msg(gettext("pipe: %s\n"), strerror(saverr)); 262*0Sstevel@tonic-gate return; 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate switch (pid = fork()) { 266*0Sstevel@tonic-gate case -1: 267*0Sstevel@tonic-gate return; 268*0Sstevel@tonic-gate case 0: 269*0Sstevel@tonic-gate close(fildes[0]); 270*0Sstevel@tonic-gate if (dup2(fildes[1], 0) < 0) { 271*0Sstevel@tonic-gate saverr = errno; 272*0Sstevel@tonic-gate msg(gettext("dup2: %s\n"), strerror(saverr)); 273*0Sstevel@tonic-gate exit(1); 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate execl("/usr/sbin/wall", "wall", "-g", OPGRENT, (char *)NULL); 276*0Sstevel@tonic-gate saverr = errno; 277*0Sstevel@tonic-gate msg(gettext("execl: %s\n"), strerror(saverr)); 278*0Sstevel@tonic-gate exit(1); 279*0Sstevel@tonic-gate default: 280*0Sstevel@tonic-gate break; /* parent */ 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate close(fildes[1]); 284*0Sstevel@tonic-gate wall = fdopen(fildes[0], "r+"); 285*0Sstevel@tonic-gate if (wall == (FILE *)NULL) { 286*0Sstevel@tonic-gate saverr = errno; 287*0Sstevel@tonic-gate msg(gettext("fdopen: %s\n"), strerror(saverr)); 288*0Sstevel@tonic-gate return; 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate clock = time((time_t *)0); 292*0Sstevel@tonic-gate localclock = localtime(&clock); 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate (void) fprintf(wall, gettext( 295*0Sstevel@tonic-gate "\n\007\007\007Message from the dump program to all operators at \ 296*0Sstevel@tonic-gate %d:%02d ...\n\n%s"), 297*0Sstevel@tonic-gate localclock->tm_hour, localclock->tm_min, message); 298*0Sstevel@tonic-gate fclose(wall); 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate while (wait((int *)0) != pid) { 301*0Sstevel@tonic-gate continue; 302*0Sstevel@tonic-gate /*LINTED [empty loop body]*/ 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate /* 307*0Sstevel@tonic-gate * print out an estimate of the amount of time left to do the dump 308*0Sstevel@tonic-gate */ 309*0Sstevel@tonic-gate #define EST_SEC 600 /* every 10 minutes */ 310*0Sstevel@tonic-gate void 311*0Sstevel@tonic-gate timeest(force, blkswritten) 312*0Sstevel@tonic-gate int force; 313*0Sstevel@tonic-gate int blkswritten; 314*0Sstevel@tonic-gate { 315*0Sstevel@tonic-gate time_t tnow, deltat; 316*0Sstevel@tonic-gate char *msgp; 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate if (tschedule == NULL) 319*0Sstevel@tonic-gate return; 320*0Sstevel@tonic-gate if (*tschedule == 0) 321*0Sstevel@tonic-gate *tschedule = time((time_t *)0) + EST_SEC; 322*0Sstevel@tonic-gate (void) time(&tnow); 323*0Sstevel@tonic-gate if ((force || tnow >= *tschedule) && blkswritten) { 324*0Sstevel@tonic-gate *tschedule = tnow + EST_SEC; 325*0Sstevel@tonic-gate if (!force && blkswritten < 50 * ntrec) 326*0Sstevel@tonic-gate return; 327*0Sstevel@tonic-gate deltat = (*telapsed + (tnow - *tstart_writing)) 328*0Sstevel@tonic-gate * ((double)esize / blkswritten - 1.0); 329*0Sstevel@tonic-gate msgp = gettext("%3.2f%% done, finished in %d:%02d\n"); 330*0Sstevel@tonic-gate msg(msgp, (blkswritten*100.0)/esize, 331*0Sstevel@tonic-gate deltat/3600, (deltat%3600)/60); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate #include <stdarg.h> 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate /* VARARGS1 */ 338*0Sstevel@tonic-gate void 339*0Sstevel@tonic-gate msg(const char *fmt, ...) 340*0Sstevel@tonic-gate { 341*0Sstevel@tonic-gate char buf[1024], *cp; 342*0Sstevel@tonic-gate size_t size; 343*0Sstevel@tonic-gate va_list args; 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate va_start(args, fmt); 346*0Sstevel@tonic-gate (void) strcpy(buf, " DUMP: "); 347*0Sstevel@tonic-gate cp = &buf[strlen(buf)]; 348*0Sstevel@tonic-gate #ifdef TDEBUG 349*0Sstevel@tonic-gate (void) sprintf(cp, "pid=%d ", getpid()); 350*0Sstevel@tonic-gate cp = &buf[strlen(buf)]; 351*0Sstevel@tonic-gate #endif 352*0Sstevel@tonic-gate /* don't need -1, vsnprintf does it right */ 353*0Sstevel@tonic-gate /* LINTED pointer arithmetic result fits in size_t */ 354*0Sstevel@tonic-gate size = ((size_t)sizeof (buf)) - (size_t)(cp - buf); 355*0Sstevel@tonic-gate (void) vsnprintf(cp, size, fmt, args); 356*0Sstevel@tonic-gate (void) fputs(buf, stderr); 357*0Sstevel@tonic-gate (void) fflush(stdout); 358*0Sstevel@tonic-gate (void) fflush(stderr); 359*0Sstevel@tonic-gate va_end(args); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* VARARGS1 */ 363*0Sstevel@tonic-gate void 364*0Sstevel@tonic-gate msgtail(const char *fmt, ...) 365*0Sstevel@tonic-gate { 366*0Sstevel@tonic-gate va_list args; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate va_start(args, fmt); 369*0Sstevel@tonic-gate (void) vfprintf(stderr, fmt, args); 370*0Sstevel@tonic-gate va_end(args); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate #define MINUTES(x) ((x) * 60) 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * Tell the operator what has to be done; 377*0Sstevel@tonic-gate * we don't actually do it 378*0Sstevel@tonic-gate */ 379*0Sstevel@tonic-gate void 380*0Sstevel@tonic-gate lastdump(arg) /* w ==> just what to do; W ==> most recent dumps */ 381*0Sstevel@tonic-gate int arg; 382*0Sstevel@tonic-gate { 383*0Sstevel@tonic-gate char *lastname; 384*0Sstevel@tonic-gate char *date; 385*0Sstevel@tonic-gate int i; 386*0Sstevel@tonic-gate time_t tnow, ddate; 387*0Sstevel@tonic-gate struct mntent *dt; 388*0Sstevel@tonic-gate int dumpme = 0; 389*0Sstevel@tonic-gate struct idates *itwalk; 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate (void) time(&tnow); 392*0Sstevel@tonic-gate mnttabread(); /* /etc/fstab input */ 393*0Sstevel@tonic-gate inititimes(); /* /etc/dumpdates input */ 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate /* Don't use msg(), this isn't a tell-the-world kind of thing */ 396*0Sstevel@tonic-gate if (arg == 'w') 397*0Sstevel@tonic-gate (void) fprintf(stdout, gettext("Dump these file systems:\n")); 398*0Sstevel@tonic-gate else 399*0Sstevel@tonic-gate (void) fprintf(stdout, gettext( 400*0Sstevel@tonic-gate "Last dump(s) done (Dump '>' file systems):\n")); 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate if (idatev != NULL) { 403*0Sstevel@tonic-gate qsort((char *)idatev, nidates, sizeof (*idatev), idatesort); 404*0Sstevel@tonic-gate lastname = "??"; 405*0Sstevel@tonic-gate ITITERATE(i, itwalk) { 406*0Sstevel@tonic-gate if (strncmp(lastname, itwalk->id_name, 407*0Sstevel@tonic-gate sizeof (itwalk->id_name)) == 0) 408*0Sstevel@tonic-gate continue; 409*0Sstevel@tonic-gate /* must be ctime(), per ufsdump(4) */ 410*0Sstevel@tonic-gate ddate = itwalk->id_ddate; 411*0Sstevel@tonic-gate date = (char *)ctime(&ddate); 412*0Sstevel@tonic-gate date[16] = '\0'; /* blow away seconds and year */ 413*0Sstevel@tonic-gate lastname = itwalk->id_name; 414*0Sstevel@tonic-gate dt = mnttabsearch(itwalk->id_name, 0); 415*0Sstevel@tonic-gate if ((time_t)(itwalk->id_ddate) < (tnow - DAY)) { 416*0Sstevel@tonic-gate dumpme = 1; 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if ((arg == 'w') && dumpme) { 420*0Sstevel@tonic-gate /* 421*0Sstevel@tonic-gate * Handle the w option: print out file systems 422*0Sstevel@tonic-gate * which haven't been backed up within a day. 423*0Sstevel@tonic-gate */ 424*0Sstevel@tonic-gate (void) printf(gettext("%8s\t(%6s)\n"), 425*0Sstevel@tonic-gate itwalk->id_name, dt ? dt->mnt_dir : ""); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate if (arg == 'W') { 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Handle the W option: print out ALL 430*0Sstevel@tonic-gate * filesystems including recent dump dates and 431*0Sstevel@tonic-gate * dump levels. Mark the backup-needing 432*0Sstevel@tonic-gate * filesystems with a >. 433*0Sstevel@tonic-gate */ 434*0Sstevel@tonic-gate (void) printf(gettext( 435*0Sstevel@tonic-gate "%c %8s\t(%6s) Last dump: Level %c, Date %s\n"), 436*0Sstevel@tonic-gate dumpme ? '>' : ' ', 437*0Sstevel@tonic-gate itwalk->id_name, 438*0Sstevel@tonic-gate dt ? dt->mnt_dir : "", 439*0Sstevel@tonic-gate (uchar_t)itwalk->id_incno, 440*0Sstevel@tonic-gate date); 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate dumpme = 0; 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate static int 448*0Sstevel@tonic-gate idatesort(v1, v2) 449*0Sstevel@tonic-gate #ifdef __STDC__ 450*0Sstevel@tonic-gate const void *v1; 451*0Sstevel@tonic-gate const void *v2; 452*0Sstevel@tonic-gate #else 453*0Sstevel@tonic-gate void *v1; 454*0Sstevel@tonic-gate void *v2; 455*0Sstevel@tonic-gate #endif 456*0Sstevel@tonic-gate { 457*0Sstevel@tonic-gate struct idates **p1 = (struct idates **)v1; 458*0Sstevel@tonic-gate struct idates **p2 = (struct idates **)v2; 459*0Sstevel@tonic-gate int diff; 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate diff = strcoll((*p1)->id_name, (*p2)->id_name); 462*0Sstevel@tonic-gate if (diff == 0) { 463*0Sstevel@tonic-gate /* 464*0Sstevel@tonic-gate * Time may eventually become unsigned, so can't 465*0Sstevel@tonic-gate * rely on subtraction to give a useful result. 466*0Sstevel@tonic-gate * Note that we are sorting dates into reverse 467*0Sstevel@tonic-gate * order, so that we will report based on the 468*0Sstevel@tonic-gate * most-recent record for a particular filesystem. 469*0Sstevel@tonic-gate */ 470*0Sstevel@tonic-gate if ((*p1)->id_ddate > (*p2)->id_ddate) 471*0Sstevel@tonic-gate diff = -1; 472*0Sstevel@tonic-gate else if ((*p1)->id_ddate < (*p2)->id_ddate) 473*0Sstevel@tonic-gate diff = 1; 474*0Sstevel@tonic-gate } 475*0Sstevel@tonic-gate return (diff); 476*0Sstevel@tonic-gate } 477