optr.c revision 1558
11558Srgrimes/*- 21558Srgrimes * Copyright (c) 1980, 1988, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 351558Srgrimesstatic char sccsid[] = "@(#)optr.c 8.2 (Berkeley) 1/6/94"; 361558Srgrimes#endif /* not lint */ 371558Srgrimes 381558Srgrimes#include <sys/param.h> 391558Srgrimes#include <sys/wait.h> 401558Srgrimes#include <sys/time.h> 411558Srgrimes 421558Srgrimes#include <errno.h> 431558Srgrimes#include <fstab.h> 441558Srgrimes#include <grp.h> 451558Srgrimes#include <signal.h> 461558Srgrimes#include <stdio.h> 471558Srgrimes#ifdef __STDC__ 481558Srgrimes#include <stdlib.h> 491558Srgrimes#include <string.h> 501558Srgrimes#include <stdarg.h> 511558Srgrimes#endif 521558Srgrimes#include <tzfile.h> 531558Srgrimes#ifdef __STDC__ 541558Srgrimes#include <unistd.h> 551558Srgrimes#endif 561558Srgrimes#include <utmp.h> 571558Srgrimes#ifndef __STDC__ 581558Srgrimes#include <varargs.h> 591558Srgrimes#endif 601558Srgrimes 611558Srgrimes#include "dump.h" 621558Srgrimes#include "pathnames.h" 631558Srgrimes 641558Srgrimesvoid alarmcatch __P((/* int, int */)); 651558Srgrimesint datesort __P((const void *, const void *)); 661558Srgrimesstatic void sendmes __P((char *, char *)); 671558Srgrimes 681558Srgrimes/* 691558Srgrimes * Query the operator; This previously-fascist piece of code 701558Srgrimes * no longer requires an exact response. 711558Srgrimes * It is intended to protect dump aborting by inquisitive 721558Srgrimes * people banging on the console terminal to see what is 731558Srgrimes * happening which might cause dump to croak, destroying 741558Srgrimes * a large number of hours of work. 751558Srgrimes * 761558Srgrimes * Every 2 minutes we reprint the message, alerting others 771558Srgrimes * that dump needs attention. 781558Srgrimes */ 791558Srgrimesstatic int timeout; 801558Srgrimesstatic char *attnmessage; /* attention message */ 811558Srgrimes 821558Srgrimesint 831558Srgrimesquery(question) 841558Srgrimes char *question; 851558Srgrimes{ 861558Srgrimes char replybuffer[64]; 871558Srgrimes int back, errcount; 881558Srgrimes FILE *mytty; 891558Srgrimes 901558Srgrimes if ((mytty = fopen(_PATH_TTY, "r")) == NULL) 911558Srgrimes quit("fopen on %s fails: %s\n", _PATH_TTY, strerror(errno)); 921558Srgrimes attnmessage = question; 931558Srgrimes timeout = 0; 941558Srgrimes alarmcatch(); 951558Srgrimes back = -1; 961558Srgrimes errcount = 0; 971558Srgrimes do { 981558Srgrimes if (fgets(replybuffer, 63, mytty) == NULL) { 991558Srgrimes clearerr(mytty); 1001558Srgrimes if (++errcount > 30) /* XXX ugly */ 1011558Srgrimes quit("excessive operator query failures\n"); 1021558Srgrimes } else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') { 1031558Srgrimes back = 1; 1041558Srgrimes } else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') { 1051558Srgrimes back = 0; 1061558Srgrimes } else { 1071558Srgrimes (void) fprintf(stderr, 1081558Srgrimes " DUMP: \"Yes\" or \"No\"?\n"); 1091558Srgrimes (void) fprintf(stderr, 1101558Srgrimes " DUMP: %s: (\"yes\" or \"no\") ", question); 1111558Srgrimes } 1121558Srgrimes } while (back < 0); 1131558Srgrimes 1141558Srgrimes /* 1151558Srgrimes * Turn off the alarm, and reset the signal to trap out.. 1161558Srgrimes */ 1171558Srgrimes (void) alarm(0); 1181558Srgrimes if (signal(SIGALRM, sig) == SIG_IGN) 1191558Srgrimes signal(SIGALRM, SIG_IGN); 1201558Srgrimes (void) fclose(mytty); 1211558Srgrimes return(back); 1221558Srgrimes} 1231558Srgrimes 1241558Srgrimeschar lastmsg[100]; 1251558Srgrimes 1261558Srgrimes/* 1271558Srgrimes * Alert the console operator, and enable the alarm clock to 1281558Srgrimes * sleep for 2 minutes in case nobody comes to satisfy dump 1291558Srgrimes */ 1301558Srgrimesvoid 1311558Srgrimesalarmcatch() 1321558Srgrimes{ 1331558Srgrimes if (notify == 0) { 1341558Srgrimes if (timeout == 0) 1351558Srgrimes (void) fprintf(stderr, 1361558Srgrimes " DUMP: %s: (\"yes\" or \"no\") ", 1371558Srgrimes attnmessage); 1381558Srgrimes else 1391558Srgrimes msgtail("\7\7"); 1401558Srgrimes } else { 1411558Srgrimes if (timeout) { 1421558Srgrimes msgtail("\n"); 1431558Srgrimes broadcast(""); /* just print last msg */ 1441558Srgrimes } 1451558Srgrimes (void) fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ", 1461558Srgrimes attnmessage); 1471558Srgrimes } 1481558Srgrimes signal(SIGALRM, alarmcatch); 1491558Srgrimes (void) alarm(120); 1501558Srgrimes timeout = 1; 1511558Srgrimes} 1521558Srgrimes 1531558Srgrimes/* 1541558Srgrimes * Here if an inquisitive operator interrupts the dump program 1551558Srgrimes */ 1561558Srgrimesvoid 1571558Srgrimesinterrupt(signo) 1581558Srgrimes int signo; 1591558Srgrimes{ 1601558Srgrimes msg("Interrupt received.\n"); 1611558Srgrimes if (query("Do you want to abort dump?")) 1621558Srgrimes dumpabort(0); 1631558Srgrimes} 1641558Srgrimes 1651558Srgrimes/* 1661558Srgrimes * The following variables and routines manage alerting 1671558Srgrimes * operators to the status of dump. 1681558Srgrimes * This works much like wall(1) does. 1691558Srgrimes */ 1701558Srgrimesstruct group *gp; 1711558Srgrimes 1721558Srgrimes/* 1731558Srgrimes * Get the names from the group entry "operator" to notify. 1741558Srgrimes */ 1751558Srgrimesvoid 1761558Srgrimesset_operators() 1771558Srgrimes{ 1781558Srgrimes if (!notify) /*not going to notify*/ 1791558Srgrimes return; 1801558Srgrimes gp = getgrnam(OPGRENT); 1811558Srgrimes (void) endgrent(); 1821558Srgrimes if (gp == NULL) { 1831558Srgrimes msg("No group entry for %s.\n", OPGRENT); 1841558Srgrimes notify = 0; 1851558Srgrimes return; 1861558Srgrimes } 1871558Srgrimes} 1881558Srgrimes 1891558Srgrimesstruct tm *localclock; 1901558Srgrimes 1911558Srgrimes/* 1921558Srgrimes * We fork a child to do the actual broadcasting, so 1931558Srgrimes * that the process control groups are not messed up 1941558Srgrimes */ 1951558Srgrimesvoid 1961558Srgrimesbroadcast(message) 1971558Srgrimes char *message; 1981558Srgrimes{ 1991558Srgrimes time_t clock; 2001558Srgrimes FILE *f_utmp; 2011558Srgrimes struct utmp utmp; 2021558Srgrimes char **np; 2031558Srgrimes int pid, s; 2041558Srgrimes 2051558Srgrimes if (!notify || gp == NULL) 2061558Srgrimes return; 2071558Srgrimes 2081558Srgrimes switch (pid = fork()) { 2091558Srgrimes case -1: 2101558Srgrimes return; 2111558Srgrimes case 0: 2121558Srgrimes break; 2131558Srgrimes default: 2141558Srgrimes while (wait(&s) != pid) 2151558Srgrimes continue; 2161558Srgrimes return; 2171558Srgrimes } 2181558Srgrimes 2191558Srgrimes clock = time((time_t *)0); 2201558Srgrimes localclock = localtime(&clock); 2211558Srgrimes 2221558Srgrimes if ((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) { 2231558Srgrimes msg("Cannot open %s: %s\n", _PATH_UTMP, strerror(errno)); 2241558Srgrimes return; 2251558Srgrimes } 2261558Srgrimes 2271558Srgrimes while (!feof(f_utmp)) { 2281558Srgrimes if (fread((char *) &utmp, sizeof (struct utmp), 1, f_utmp) != 1) 2291558Srgrimes break; 2301558Srgrimes if (utmp.ut_name[0] == 0) 2311558Srgrimes continue; 2321558Srgrimes for (np = gp->gr_mem; *np; np++) { 2331558Srgrimes if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0) 2341558Srgrimes continue; 2351558Srgrimes /* 2361558Srgrimes * Do not send messages to operators on dialups 2371558Srgrimes */ 2381558Srgrimes if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0) 2391558Srgrimes continue; 2401558Srgrimes#ifdef DEBUG 2411558Srgrimes msg("Message to %s at %s\n", *np, utmp.ut_line); 2421558Srgrimes#endif 2431558Srgrimes sendmes(utmp.ut_line, message); 2441558Srgrimes } 2451558Srgrimes } 2461558Srgrimes (void) fclose(f_utmp); 2471558Srgrimes Exit(0); /* the wait in this same routine will catch this */ 2481558Srgrimes /* NOTREACHED */ 2491558Srgrimes} 2501558Srgrimes 2511558Srgrimesstatic void 2521558Srgrimessendmes(tty, message) 2531558Srgrimes char *tty, *message; 2541558Srgrimes{ 2551558Srgrimes char t[50], buf[BUFSIZ]; 2561558Srgrimes register char *cp; 2571558Srgrimes int lmsg = 1; 2581558Srgrimes FILE *f_tty; 2591558Srgrimes 2601558Srgrimes (void) strcpy(t, _PATH_DEV); 2611558Srgrimes (void) strcat(t, tty); 2621558Srgrimes 2631558Srgrimes if ((f_tty = fopen(t, "w")) != NULL) { 2641558Srgrimes setbuf(f_tty, buf); 2651558Srgrimes (void) fprintf(f_tty, 2661558Srgrimes "\n\ 2671558Srgrimes\7\7\7Message from the dump program to all operators at %d:%02d ...\r\n\n\ 2681558SrgrimesDUMP: NEEDS ATTENTION: ", 2691558Srgrimes localclock->tm_hour, localclock->tm_min); 2701558Srgrimes for (cp = lastmsg; ; cp++) { 2711558Srgrimes if (*cp == '\0') { 2721558Srgrimes if (lmsg) { 2731558Srgrimes cp = message; 2741558Srgrimes if (*cp == '\0') 2751558Srgrimes break; 2761558Srgrimes lmsg = 0; 2771558Srgrimes } else 2781558Srgrimes break; 2791558Srgrimes } 2801558Srgrimes if (*cp == '\n') 2811558Srgrimes (void) putc('\r', f_tty); 2821558Srgrimes (void) putc(*cp, f_tty); 2831558Srgrimes } 2841558Srgrimes (void) fclose(f_tty); 2851558Srgrimes } 2861558Srgrimes} 2871558Srgrimes 2881558Srgrimes/* 2891558Srgrimes * print out an estimate of the amount of time left to do the dump 2901558Srgrimes */ 2911558Srgrimes 2921558Srgrimestime_t tschedule = 0; 2931558Srgrimes 2941558Srgrimesvoid 2951558Srgrimestimeest() 2961558Srgrimes{ 2971558Srgrimes time_t tnow, deltat; 2981558Srgrimes 2991558Srgrimes (void) time((time_t *) &tnow); 3001558Srgrimes if (tnow >= tschedule) { 3011558Srgrimes tschedule = tnow + 300; 3021558Srgrimes if (blockswritten < 500) 3031558Srgrimes return; 3041558Srgrimes deltat = tstart_writing - tnow + 3051558Srgrimes (1.0 * (tnow - tstart_writing)) 3061558Srgrimes / blockswritten * tapesize; 3071558Srgrimes msg("%3.2f%% done, finished in %d:%02d\n", 3081558Srgrimes (blockswritten * 100.0) / tapesize, 3091558Srgrimes deltat / 3600, (deltat % 3600) / 60); 3101558Srgrimes } 3111558Srgrimes} 3121558Srgrimes 3131558Srgrimesvoid 3141558Srgrimes#if __STDC__ 3151558Srgrimesmsg(const char *fmt, ...) 3161558Srgrimes#else 3171558Srgrimesmsg(fmt, va_alist) 3181558Srgrimes char *fmt; 3191558Srgrimes va_dcl 3201558Srgrimes#endif 3211558Srgrimes{ 3221558Srgrimes va_list ap; 3231558Srgrimes 3241558Srgrimes (void) fprintf(stderr," DUMP: "); 3251558Srgrimes#ifdef TDEBUG 3261558Srgrimes (void) fprintf(stderr, "pid=%d ", getpid()); 3271558Srgrimes#endif 3281558Srgrimes#if __STDC__ 3291558Srgrimes va_start(ap, fmt); 3301558Srgrimes#else 3311558Srgrimes va_start(ap); 3321558Srgrimes#endif 3331558Srgrimes (void) vfprintf(stderr, fmt, ap); 3341558Srgrimes (void) fflush(stdout); 3351558Srgrimes (void) fflush(stderr); 3361558Srgrimes (void) vsprintf(lastmsg, fmt, ap); 3371558Srgrimes va_end(ap); 3381558Srgrimes} 3391558Srgrimes 3401558Srgrimesvoid 3411558Srgrimes#if __STDC__ 3421558Srgrimesmsgtail(const char *fmt, ...) 3431558Srgrimes#else 3441558Srgrimesmsgtail(fmt, va_alist) 3451558Srgrimes char *fmt; 3461558Srgrimes va_dcl 3471558Srgrimes#endif 3481558Srgrimes{ 3491558Srgrimes va_list ap; 3501558Srgrimes#if __STDC__ 3511558Srgrimes va_start(ap, fmt); 3521558Srgrimes#else 3531558Srgrimes va_start(ap); 3541558Srgrimes#endif 3551558Srgrimes (void) vfprintf(stderr, fmt, ap); 3561558Srgrimes va_end(ap); 3571558Srgrimes} 3581558Srgrimes 3591558Srgrimesvoid 3601558Srgrimes#if __STDC__ 3611558Srgrimesquit(const char *fmt, ...) 3621558Srgrimes#else 3631558Srgrimesquit(fmt, va_alist) 3641558Srgrimes char *fmt; 3651558Srgrimes va_dcl 3661558Srgrimes#endif 3671558Srgrimes{ 3681558Srgrimes va_list ap; 3691558Srgrimes 3701558Srgrimes (void) fprintf(stderr," DUMP: "); 3711558Srgrimes#ifdef TDEBUG 3721558Srgrimes (void) fprintf(stderr, "pid=%d ", getpid()); 3731558Srgrimes#endif 3741558Srgrimes#if __STDC__ 3751558Srgrimes va_start(ap, fmt); 3761558Srgrimes#else 3771558Srgrimes va_start(ap); 3781558Srgrimes#endif 3791558Srgrimes (void) vfprintf(stderr, fmt, ap); 3801558Srgrimes va_end(ap); 3811558Srgrimes (void) fflush(stdout); 3821558Srgrimes (void) fflush(stderr); 3831558Srgrimes dumpabort(0); 3841558Srgrimes} 3851558Srgrimes 3861558Srgrimes/* 3871558Srgrimes * Tell the operator what has to be done; 3881558Srgrimes * we don't actually do it 3891558Srgrimes */ 3901558Srgrimes 3911558Srgrimesstruct fstab * 3921558Srgrimesallocfsent(fs) 3931558Srgrimes register struct fstab *fs; 3941558Srgrimes{ 3951558Srgrimes register struct fstab *new; 3961558Srgrimes 3971558Srgrimes new = (struct fstab *)malloc(sizeof (*fs)); 3981558Srgrimes if (new == NULL || 3991558Srgrimes (new->fs_file = strdup(fs->fs_file)) == NULL || 4001558Srgrimes (new->fs_type = strdup(fs->fs_type)) == NULL || 4011558Srgrimes (new->fs_spec = strdup(fs->fs_spec)) == NULL) 4021558Srgrimes quit("%s\n", strerror(errno)); 4031558Srgrimes new->fs_passno = fs->fs_passno; 4041558Srgrimes new->fs_freq = fs->fs_freq; 4051558Srgrimes return (new); 4061558Srgrimes} 4071558Srgrimes 4081558Srgrimesstruct pfstab { 4091558Srgrimes struct pfstab *pf_next; 4101558Srgrimes struct fstab *pf_fstab; 4111558Srgrimes}; 4121558Srgrimes 4131558Srgrimesstatic struct pfstab *table; 4141558Srgrimes 4151558Srgrimesvoid 4161558Srgrimesgetfstab() 4171558Srgrimes{ 4181558Srgrimes register struct fstab *fs; 4191558Srgrimes register struct pfstab *pf; 4201558Srgrimes 4211558Srgrimes if (setfsent() == 0) { 4221558Srgrimes msg("Can't open %s for dump table information: %s\n", 4231558Srgrimes _PATH_FSTAB, strerror(errno)); 4241558Srgrimes return; 4251558Srgrimes } 4261558Srgrimes while ((fs = getfsent()) != NULL) { 4271558Srgrimes if (strcmp(fs->fs_type, FSTAB_RW) && 4281558Srgrimes strcmp(fs->fs_type, FSTAB_RO) && 4291558Srgrimes strcmp(fs->fs_type, FSTAB_RQ)) 4301558Srgrimes continue; 4311558Srgrimes fs = allocfsent(fs); 4321558Srgrimes if ((pf = (struct pfstab *)malloc(sizeof (*pf))) == NULL) 4331558Srgrimes quit("%s\n", strerror(errno)); 4341558Srgrimes pf->pf_fstab = fs; 4351558Srgrimes pf->pf_next = table; 4361558Srgrimes table = pf; 4371558Srgrimes } 4381558Srgrimes (void) endfsent(); 4391558Srgrimes} 4401558Srgrimes 4411558Srgrimes/* 4421558Srgrimes * Search in the fstab for a file name. 4431558Srgrimes * This file name can be either the special or the path file name. 4441558Srgrimes * 4451558Srgrimes * The entries in the fstab are the BLOCK special names, not the 4461558Srgrimes * character special names. 4471558Srgrimes * The caller of fstabsearch assures that the character device 4481558Srgrimes * is dumped (that is much faster) 4491558Srgrimes * 4501558Srgrimes * The file name can omit the leading '/'. 4511558Srgrimes */ 4521558Srgrimesstruct fstab * 4531558Srgrimesfstabsearch(key) 4541558Srgrimes char *key; 4551558Srgrimes{ 4561558Srgrimes register struct pfstab *pf; 4571558Srgrimes register struct fstab *fs; 4581558Srgrimes char *rn; 4591558Srgrimes 4601558Srgrimes for (pf = table; pf != NULL; pf = pf->pf_next) { 4611558Srgrimes fs = pf->pf_fstab; 4621558Srgrimes if (strcmp(fs->fs_file, key) == 0 || 4631558Srgrimes strcmp(fs->fs_spec, key) == 0) 4641558Srgrimes return (fs); 4651558Srgrimes rn = rawname(fs->fs_spec); 4661558Srgrimes if (rn != NULL && strcmp(rn, key) == 0) 4671558Srgrimes return (fs); 4681558Srgrimes if (key[0] != '/') { 4691558Srgrimes if (*fs->fs_spec == '/' && 4701558Srgrimes strcmp(fs->fs_spec + 1, key) == 0) 4711558Srgrimes return (fs); 4721558Srgrimes if (*fs->fs_file == '/' && 4731558Srgrimes strcmp(fs->fs_file + 1, key) == 0) 4741558Srgrimes return (fs); 4751558Srgrimes } 4761558Srgrimes } 4771558Srgrimes return (NULL); 4781558Srgrimes} 4791558Srgrimes 4801558Srgrimes/* 4811558Srgrimes * Tell the operator what to do 4821558Srgrimes */ 4831558Srgrimesvoid 4841558Srgrimeslastdump(arg) 4851558Srgrimes char arg; /* w ==> just what to do; W ==> most recent dumps */ 4861558Srgrimes{ 4871558Srgrimes register int i; 4881558Srgrimes register struct fstab *dt; 4891558Srgrimes register struct dumpdates *dtwalk; 4901558Srgrimes char *lastname, *date; 4911558Srgrimes int dumpme; 4921558Srgrimes time_t tnow; 4931558Srgrimes 4941558Srgrimes (void) time(&tnow); 4951558Srgrimes getfstab(); /* /etc/fstab input */ 4961558Srgrimes initdumptimes(); /* /etc/dumpdates input */ 4971558Srgrimes qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort); 4981558Srgrimes 4991558Srgrimes if (arg == 'w') 5001558Srgrimes (void) printf("Dump these file systems:\n"); 5011558Srgrimes else 5021558Srgrimes (void) printf("Last dump(s) done (Dump '>' file systems):\n"); 5031558Srgrimes lastname = "??"; 5041558Srgrimes ITITERATE(i, dtwalk) { 5051558Srgrimes if (strncmp(lastname, dtwalk->dd_name, 5061558Srgrimes sizeof(dtwalk->dd_name)) == 0) 5071558Srgrimes continue; 5081558Srgrimes date = (char *)ctime(&dtwalk->dd_ddate); 5091558Srgrimes date[16] = '\0'; /* blast away seconds and year */ 5101558Srgrimes lastname = dtwalk->dd_name; 5111558Srgrimes dt = fstabsearch(dtwalk->dd_name); 5121558Srgrimes dumpme = (dt != NULL && 5131558Srgrimes dt->fs_freq != 0 && 5141558Srgrimes dtwalk->dd_ddate < tnow - (dt->fs_freq * SECSPERDAY)); 5151558Srgrimes if (arg != 'w' || dumpme) 5161558Srgrimes (void) printf( 5171558Srgrimes "%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 5181558Srgrimes dumpme && (arg != 'w') ? '>' : ' ', 5191558Srgrimes dtwalk->dd_name, 5201558Srgrimes dt ? dt->fs_file : "", 5211558Srgrimes dtwalk->dd_level, 5221558Srgrimes date); 5231558Srgrimes } 5241558Srgrimes} 5251558Srgrimes 5261558Srgrimesint 5271558Srgrimesdatesort(a1, a2) 5281558Srgrimes const void *a1, *a2; 5291558Srgrimes{ 5301558Srgrimes struct dumpdates *d1 = *(struct dumpdates **)a1; 5311558Srgrimes struct dumpdates *d2 = *(struct dumpdates **)a2; 5321558Srgrimes int diff; 5331558Srgrimes 5341558Srgrimes diff = strncmp(d1->dd_name, d2->dd_name, sizeof(d1->dd_name)); 5351558Srgrimes if (diff == 0) 5361558Srgrimes return (d2->dd_ddate - d1->dd_ddate); 5371558Srgrimes return (diff); 5381558Srgrimes} 539