optr.c revision 50476
1241600Sgonzo/*- 2241600Sgonzo * Copyright (c) 1980, 1988, 1993 3241600Sgonzo * The Regents of the University of California. All rights reserved. 4241600Sgonzo * 5241600Sgonzo * Redistribution and use in source and binary forms, with or without 6241600Sgonzo * modification, are permitted provided that the following conditions 7241600Sgonzo * are met: 8241600Sgonzo * 1. Redistributions of source code must retain the above copyright 9241600Sgonzo * notice, this list of conditions and the following disclaimer. 10241600Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11241600Sgonzo * notice, this list of conditions and the following disclaimer in the 12241600Sgonzo * documentation and/or other materials provided with the distribution. 13241600Sgonzo * 3. All advertising materials mentioning features or use of this software 14241600Sgonzo * must display the following acknowledgement: 15241600Sgonzo * This product includes software developed by the University of 16241600Sgonzo * California, Berkeley and its contributors. 17241600Sgonzo * 4. Neither the name of the University nor the names of its contributors 18241600Sgonzo * may be used to endorse or promote products derived from this software 19241600Sgonzo * without specific prior written permission. 20241600Sgonzo * 21241600Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22241600Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23241600Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24241600Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25241600Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26241600Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27241600Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28241600Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29241600Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30241600Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31241600Sgonzo * SUCH DAMAGE. 32241600Sgonzo */ 33241600Sgonzo 34241600Sgonzo#ifndef lint 35241600Sgonzo#if 0 36241600Sgonzostatic char sccsid[] = "@(#)optr.c 8.2 (Berkeley) 1/6/94"; 37241600Sgonzo#endif 38241600Sgonzostatic const char rcsid[] = 39241600Sgonzo "$FreeBSD: head/sbin/dump/optr.c 50476 1999-08-28 00:22:10Z peter $"; 40241600Sgonzo#endif /* not lint */ 41241600Sgonzo 42241600Sgonzo#include <sys/param.h> 43241600Sgonzo#include <sys/wait.h> 44241600Sgonzo#include <sys/time.h> 45241600Sgonzo 46241600Sgonzo#include <errno.h> 47241600Sgonzo#include <fstab.h> 48241600Sgonzo#include <grp.h> 49241600Sgonzo#include <stdio.h> 50241600Sgonzo#include <stdlib.h> 51241600Sgonzo#include <string.h> 52241600Sgonzo#include <stdarg.h> 53241600Sgonzo#include <unistd.h> 54241600Sgonzo#include <utmp.h> 55241600Sgonzo 56241600Sgonzo#include "dump.h" 57241600Sgonzo#include "pathnames.h" 58241600Sgonzo 59241600Sgonzovoid alarmcatch __P((/* int, int */)); 60241600Sgonzoint datesort __P((const void *, const void *)); 61241600Sgonzostatic void sendmes __P((char *, char *)); 62241600Sgonzo 63241600Sgonzo/* 64241600Sgonzo * Query the operator; This previously-fascist piece of code 65241600Sgonzo * no longer requires an exact response. 66312399Smarius * It is intended to protect dump aborting by inquisitive 67312399Smarius * people banging on the console terminal to see what is 68241600Sgonzo * happening which might cause dump to croak, destroying 69241600Sgonzo * a large number of hours of work. 70241600Sgonzo * 71241600Sgonzo * Every 2 minutes we reprint the message, alerting others 72241600Sgonzo * that dump needs attention. 73241600Sgonzo */ 74312399Smariusstatic int timeout; 75241600Sgonzostatic char *attnmessage; /* attention message */ 76241600Sgonzo 77241600Sgonzoint 78241600Sgonzoquery(question) 79241600Sgonzo char *question; 80241600Sgonzo{ 81270885Smarius char replybuffer[64]; 82241600Sgonzo int back, errcount; 83241600Sgonzo FILE *mytty; 84241600Sgonzo 85241600Sgonzo if ((mytty = fopen(_PATH_TTY, "r")) == NULL) 86276469Smarius quit("fopen on %s fails: %s\n", _PATH_TTY, strerror(errno)); 87276469Smarius attnmessage = question; 88276469Smarius timeout = 0; 89241600Sgonzo alarmcatch(); 90241600Sgonzo back = -1; 91241600Sgonzo errcount = 0; 92241600Sgonzo do { 93241600Sgonzo if (fgets(replybuffer, 63, mytty) == NULL) { 94241600Sgonzo clearerr(mytty); 95241600Sgonzo if (++errcount > 30) /* XXX ugly */ 96241600Sgonzo quit("excessive operator query failures\n"); 97241600Sgonzo } else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') { 98241600Sgonzo back = 1; 99241600Sgonzo } else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') { 100241600Sgonzo back = 0; 101241600Sgonzo } else { 102241600Sgonzo (void) fprintf(stderr, 103241600Sgonzo " DUMP: \"Yes\" or \"No\"?\n"); 104241600Sgonzo (void) fprintf(stderr, 105241600Sgonzo " DUMP: %s: (\"yes\" or \"no\") ", question); 106241600Sgonzo } 107241600Sgonzo } while (back < 0); 108289359Sadrian 109289359Sadrian /* 110312399Smarius * Turn off the alarm, and reset the signal to trap out.. 111312399Smarius */ 112312399Smarius (void) alarm(0); 113312399Smarius if (signal(SIGALRM, sig) == SIG_IGN) 114312399Smarius signal(SIGALRM, SIG_IGN); 115312399Smarius (void) fclose(mytty); 116312399Smarius return(back); 117312399Smarius} 118312399Smarius 119312399Smariuschar lastmsg[100]; 120312399Smarius 121312399Smarius/* 122312399Smarius * Alert the console operator, and enable the alarm clock to 123241600Sgonzo * sleep for 2 minutes in case nobody comes to satisfy dump 124241600Sgonzo */ 125241600Sgonzovoid 126241600Sgonzoalarmcatch() 127241600Sgonzo{ 128241600Sgonzo if (notify == 0) { 129241600Sgonzo if (timeout == 0) 130241600Sgonzo (void) fprintf(stderr, 131241600Sgonzo " DUMP: %s: (\"yes\" or \"no\") ", 132241600Sgonzo attnmessage); 133241600Sgonzo else 134241600Sgonzo msgtail("\7\7"); 135312399Smarius } else { 136312399Smarius if (timeout) { 137241600Sgonzo msgtail("\n"); 138241600Sgonzo broadcast(""); /* just print last msg */ 139270885Smarius } 140270885Smarius (void) fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ", 141270885Smarius attnmessage); 142241600Sgonzo } 143241600Sgonzo signal(SIGALRM, alarmcatch); 144241600Sgonzo (void) alarm(120); 145241600Sgonzo timeout = 1; 146241600Sgonzo} 147241600Sgonzo 148241600Sgonzo/* 149241600Sgonzo * Here if an inquisitive operator interrupts the dump program 150241600Sgonzo */ 151241600Sgonzovoid 152241600Sgonzointerrupt(signo) 153241600Sgonzo int signo; 154241600Sgonzo{ 155241600Sgonzo msg("Interrupt received.\n"); 156241600Sgonzo if (query("Do you want to abort dump?")) 157241600Sgonzo dumpabort(0); 158241600Sgonzo} 159241600Sgonzo 160241600Sgonzo/* 161241600Sgonzo * The following variables and routines manage alerting 162241600Sgonzo * operators to the status of dump. 163241600Sgonzo * This works much like wall(1) does. 164241600Sgonzo */ 165241600Sgonzostruct group *gp; 166241600Sgonzo 167241600Sgonzo/* 168241600Sgonzo * Get the names from the group entry "operator" to notify. 169241600Sgonzo */ 170241600Sgonzovoid 171241600Sgonzoset_operators() 172241600Sgonzo{ 173241600Sgonzo if (!notify) /*not going to notify*/ 174241600Sgonzo return; 175241600Sgonzo gp = getgrnam(OPGRENT); 176241600Sgonzo (void) endgrent(); 177241600Sgonzo if (gp == NULL) { 178241600Sgonzo msg("No group entry for %s.\n", OPGRENT); 179241600Sgonzo notify = 0; 180241600Sgonzo return; 181241600Sgonzo } 182241600Sgonzo} 183241600Sgonzo 184241600Sgonzostruct tm *localclock; 185241600Sgonzo 186241600Sgonzo/* 187241600Sgonzo * We fork a child to do the actual broadcasting, so 188241600Sgonzo * that the process control groups are not messed up 189241600Sgonzo */ 190241600Sgonzovoid 191241600Sgonzobroadcast(message) 192241600Sgonzo char *message; 193241600Sgonzo{ 194241600Sgonzo time_t clock; 195241600Sgonzo FILE *f_utmp; 196241600Sgonzo struct utmp utmp; 197241600Sgonzo char **np; 198241600Sgonzo int pid, s; 199241600Sgonzo 200241600Sgonzo if (!notify || gp == NULL) 201241600Sgonzo return; 202241600Sgonzo 203241600Sgonzo switch (pid = fork()) { 204241600Sgonzo case -1: 205241600Sgonzo return; 206241600Sgonzo case 0: 207241600Sgonzo break; 208241600Sgonzo default: 209241600Sgonzo while (wait(&s) != pid) 210241600Sgonzo continue; 211241600Sgonzo return; 212241600Sgonzo } 213241600Sgonzo 214241600Sgonzo clock = time((time_t *)0); 215241600Sgonzo localclock = localtime(&clock); 216241600Sgonzo 217241600Sgonzo if ((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) { 218241600Sgonzo msg("Cannot open %s: %s\n", _PATH_UTMP, strerror(errno)); 219241600Sgonzo return; 220241600Sgonzo } 221241600Sgonzo 222241600Sgonzo while (!feof(f_utmp)) { 223241600Sgonzo if (fread((char *) &utmp, sizeof (struct utmp), 1, f_utmp) != 1) 224241600Sgonzo break; 225241600Sgonzo if (utmp.ut_name[0] == 0) 226276469Smarius continue; 227241600Sgonzo for (np = gp->gr_mem; *np; np++) { 228276469Smarius if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0) 229276469Smarius continue; 230276469Smarius /* 231276469Smarius * Do not send messages to operators on dialups 232241600Sgonzo */ 233276469Smarius if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0) 234241600Sgonzo continue; 235241600Sgonzo#ifdef DEBUG 236241600Sgonzo msg("Message to %s at %s\n", *np, utmp.ut_line); 237241600Sgonzo#endif 238241600Sgonzo sendmes(utmp.ut_line, message); 239276469Smarius } 240241600Sgonzo } 241241600Sgonzo (void) fclose(f_utmp); 242276469Smarius Exit(0); /* the wait in this same routine will catch this */ 243241600Sgonzo /* NOTREACHED */ 244241600Sgonzo} 245241600Sgonzo 246241600Sgonzostatic void 247276469Smariussendmes(tty, message) 248276469Smarius char *tty, *message; 249276469Smarius{ 250276469Smarius char t[MAXPATHLEN], buf[BUFSIZ]; 251276469Smarius register char *cp; 252276469Smarius int lmsg = 1; 253276469Smarius FILE *f_tty; 254276469Smarius 255276469Smarius (void) strcpy(t, _PATH_DEV); 256276469Smarius (void) strncat(t, tty, sizeof t - strlen(_PATH_DEV) - 1); 257276469Smarius 258276469Smarius if ((f_tty = fopen(t, "w")) != NULL) { 259276469Smarius setbuf(f_tty, buf); 260276469Smarius (void) fprintf(f_tty, 261276469Smarius "\n\ 262276469Smarius\7\7\7Message from the dump program to all operators at %d:%02d ...\r\n\n\ 263241600SgonzoDUMP: NEEDS ATTENTION: ", 264241600Sgonzo localclock->tm_hour, localclock->tm_min); 265241600Sgonzo for (cp = lastmsg; ; cp++) { 266241600Sgonzo if (*cp == '\0') { 267241600Sgonzo if (lmsg) { 268241600Sgonzo cp = message; 269241600Sgonzo if (*cp == '\0') 270270885Smarius break; 271241600Sgonzo lmsg = 0; 272241600Sgonzo } else 273241600Sgonzo break; 274241600Sgonzo } 275241600Sgonzo if (*cp == '\n') 276270885Smarius (void) putc('\r', f_tty); 277241600Sgonzo (void) putc(*cp, f_tty); 278241600Sgonzo } 279241600Sgonzo (void) fclose(f_tty); 280241600Sgonzo } 281241600Sgonzo} 282241600Sgonzo 283241600Sgonzo/* 284241600Sgonzo * print out an estimate of the amount of time left to do the dump 285241600Sgonzo */ 286241600Sgonzo 287241600Sgonzotime_t tschedule = 0; 288241600Sgonzo 289241600Sgonzovoid 290241600Sgonzotimeest() 291241600Sgonzo{ 292270885Smarius time_t tnow, deltat; 293241600Sgonzo 294241600Sgonzo (void) time((time_t *) &tnow); 295241600Sgonzo if (tnow >= tschedule) { 296241600Sgonzo tschedule = tnow + 300; 297241600Sgonzo if (blockswritten < 500) 298241600Sgonzo return; 299241600Sgonzo deltat = tstart_writing - tnow + 300241600Sgonzo (1.0 * (tnow - tstart_writing)) 301241600Sgonzo / blockswritten * tapesize; 302270885Smarius msg("%3.2f%% done, finished in %d:%02d\n", 303241600Sgonzo (blockswritten * 100.0) / tapesize, 304241600Sgonzo deltat / 3600, (deltat % 3600) / 60); 305241600Sgonzo } 306241600Sgonzo} 307241600Sgonzo 308241600Sgonzovoid 309241600Sgonzo#if __STDC__ 310241600Sgonzomsg(const char *fmt, ...) 311241600Sgonzo#else 312241600Sgonzomsg(fmt, va_alist) 313241600Sgonzo char *fmt; 314241600Sgonzo va_dcl 315241600Sgonzo#endif 316241600Sgonzo{ 317241600Sgonzo va_list ap; 318241600Sgonzo 319241600Sgonzo (void) fprintf(stderr," DUMP: "); 320241600Sgonzo#ifdef TDEBUG 321241600Sgonzo (void) fprintf(stderr, "pid=%d ", getpid()); 322241600Sgonzo#endif 323241600Sgonzo#if __STDC__ 324241600Sgonzo va_start(ap, fmt); 325241600Sgonzo#else 326241600Sgonzo va_start(ap); 327241600Sgonzo#endif 328241600Sgonzo (void) vfprintf(stderr, fmt, ap); 329270885Smarius (void) fflush(stdout); 330270885Smarius (void) fflush(stderr); 331270885Smarius (void) vsprintf(lastmsg, fmt, ap); 332270885Smarius va_end(ap); 333270885Smarius} 334270885Smarius 335241600Sgonzovoid 336241600Sgonzo#if __STDC__ 337270885Smariusmsgtail(const char *fmt, ...) 338241600Sgonzo#else 339241600Sgonzomsgtail(fmt, va_alist) 340241600Sgonzo char *fmt; 341241600Sgonzo va_dcl 342241600Sgonzo#endif 343241600Sgonzo{ 344241600Sgonzo va_list ap; 345270885Smarius#if __STDC__ 346296135Sjhibbits va_start(ap, fmt); 347296135Sjhibbits#else 348241600Sgonzo va_start(ap); 349241600Sgonzo#endif 350241600Sgonzo (void) vfprintf(stderr, fmt, ap); 351241600Sgonzo va_end(ap); 352289359Sadrian} 353289359Sadrian 354241600Sgonzovoid 355241600Sgonzo#if __STDC__ 356241600Sgonzoquit(const char *fmt, ...) 357241600Sgonzo#else 358241600Sgonzoquit(fmt, va_alist) 359241600Sgonzo char *fmt; 360241600Sgonzo va_dcl 361241600Sgonzo#endif 362241600Sgonzo{ 363241600Sgonzo va_list ap; 364241600Sgonzo 365241600Sgonzo (void) fprintf(stderr," DUMP: "); 366241600Sgonzo#ifdef TDEBUG 367241600Sgonzo (void) fprintf(stderr, "pid=%d ", getpid()); 368241600Sgonzo#endif 369241600Sgonzo#if __STDC__ 370241600Sgonzo va_start(ap, fmt); 371241600Sgonzo#else 372241600Sgonzo va_start(ap); 373270885Smarius#endif 374241600Sgonzo (void) vfprintf(stderr, fmt, ap); 375241600Sgonzo va_end(ap); 376241600Sgonzo (void) fflush(stdout); 377241600Sgonzo (void) fflush(stderr); 378241600Sgonzo dumpabort(0); 379241600Sgonzo} 380241600Sgonzo 381241600Sgonzo/* 382241600Sgonzo * Tell the operator what has to be done; 383241600Sgonzo * we don't actually do it 384241600Sgonzo */ 385270885Smarius 386270885Smariusstruct fstab * 387241600Sgonzoallocfsent(fs) 388241600Sgonzo register struct fstab *fs; 389241600Sgonzo{ 390241600Sgonzo register struct fstab *new; 391241600Sgonzo 392241600Sgonzo new = (struct fstab *)malloc(sizeof (*fs)); 393270885Smarius if (new == NULL || 394241600Sgonzo (new->fs_file = strdup(fs->fs_file)) == NULL || 395276469Smarius (new->fs_type = strdup(fs->fs_type)) == NULL || 396276469Smarius (new->fs_spec = strdup(fs->fs_spec)) == NULL) 397241600Sgonzo quit("%s\n", strerror(errno)); 398241600Sgonzo new->fs_passno = fs->fs_passno; 399241600Sgonzo new->fs_freq = fs->fs_freq; 400241600Sgonzo return (new); 401276469Smarius} 402276469Smarius 403276469Smariusstruct pfstab { 404276469Smarius struct pfstab *pf_next; 405276469Smarius struct fstab *pf_fstab; 406276469Smarius}; 407276469Smarius 408276469Smariusstatic struct pfstab *table; 409276469Smarius 410276469Smariusvoid 411241600Sgonzogetfstab() 412241600Sgonzo{ 413241600Sgonzo register struct fstab *fs; 414241600Sgonzo register struct pfstab *pf; 415241600Sgonzo 416241600Sgonzo if (setfsent() == 0) { 417241600Sgonzo msg("Can't open %s for dump table information: %s\n", 418241600Sgonzo _PATH_FSTAB, strerror(errno)); 419241600Sgonzo return; 420270885Smarius } 421241600Sgonzo while ((fs = getfsent()) != NULL) { 422241600Sgonzo if (strcmp(fs->fs_type, FSTAB_RW) && 423241600Sgonzo strcmp(fs->fs_type, FSTAB_RO) && 424241600Sgonzo strcmp(fs->fs_type, FSTAB_RQ)) 425241600Sgonzo continue; 426241600Sgonzo fs = allocfsent(fs); 427241600Sgonzo if ((pf = (struct pfstab *)malloc(sizeof (*pf))) == NULL) 428299414Strasz quit("%s\n", strerror(errno)); 429241600Sgonzo pf->pf_fstab = fs; 430241600Sgonzo pf->pf_next = table; 431241600Sgonzo table = pf; 432299414Strasz } 433299414Strasz (void) endfsent(); 434299414Strasz} 435299414Strasz 436299414Strasz/* 437299414Strasz * Search in the fstab for a file name. 438241600Sgonzo * This file name can be either the special or the path file name. 439241600Sgonzo * 440241600Sgonzo * The entries in the fstab are the BLOCK special names, not the 441241600Sgonzo * character special names. 442241600Sgonzo * The caller of fstabsearch assures that the character device 443241600Sgonzo * is dumped (that is much faster) 444241600Sgonzo * 445241600Sgonzo * The file name can omit the leading '/'. 446241600Sgonzo */ 447241600Sgonzostruct fstab * 448241600Sgonzofstabsearch(key) 449241600Sgonzo char *key; 450241600Sgonzo{ 451241600Sgonzo register struct pfstab *pf; 452241600Sgonzo register struct fstab *fs; 453241600Sgonzo char *rn; 454241600Sgonzo 455241600Sgonzo for (pf = table; pf != NULL; pf = pf->pf_next) { 456241600Sgonzo fs = pf->pf_fstab; 457276469Smarius if (strcmp(fs->fs_file, key) == 0 || 458241600Sgonzo strcmp(fs->fs_spec, key) == 0) 459241600Sgonzo return (fs); 460241600Sgonzo rn = rawname(fs->fs_spec); 461241600Sgonzo if (rn != NULL && strcmp(rn, key) == 0) 462241600Sgonzo return (fs); 463241600Sgonzo if (key[0] != '/') { 464241600Sgonzo if (*fs->fs_spec == '/' && 465241600Sgonzo strcmp(fs->fs_spec + 1, key) == 0) 466312399Smarius return (fs); 467312399Smarius if (*fs->fs_file == '/' && 468312399Smarius strcmp(fs->fs_file + 1, key) == 0) 469312399Smarius return (fs); 470312399Smarius } 471241600Sgonzo } 472241600Sgonzo return (NULL); 473241600Sgonzo} 474241600Sgonzo 475241600Sgonzo/* 476241600Sgonzo * Tell the operator what to do 477241600Sgonzo */ 478241600Sgonzovoid 479241600Sgonzolastdump(arg) 480241600Sgonzo char arg; /* w ==> just what to do; W ==> most recent dumps */ 481241600Sgonzo{ 482246128Ssbz register int i; 483241600Sgonzo register struct fstab *dt; 484241600Sgonzo register struct dumpdates *dtwalk; 485241600Sgonzo char *lastname, *date; 486241600Sgonzo int dumpme; 487241600Sgonzo time_t tnow; 488241600Sgonzo struct tm *tlast; 489241600Sgonzo 490241600Sgonzo (void) time(&tnow); 491241600Sgonzo getfstab(); /* /etc/fstab input */ 492270885Smarius initdumptimes(); /* /etc/dumpdates input */ 493270885Smarius qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort); 494241600Sgonzo 495292180Sian if (arg == 'w') 496297127Sian (void) printf("Dump these file systems:\n"); 497 else 498 (void) printf("Last dump(s) done (Dump '>' file systems):\n"); 499 lastname = "??"; 500 ITITERATE(i, dtwalk) { 501 if (strncmp(lastname, dtwalk->dd_name, 502 sizeof(dtwalk->dd_name)) == 0) 503 continue; 504 date = (char *)ctime(&dtwalk->dd_ddate); 505 date[16] = '\0'; /* blast away seconds and year */ 506 lastname = dtwalk->dd_name; 507 dt = fstabsearch(dtwalk->dd_name); 508 dumpme = (dt != NULL && dt->fs_freq != 0); 509 if (dumpme) { 510 tlast = localtime(&dtwalk->dd_ddate); 511 dumpme = tnow > (dtwalk->dd_ddate - (tlast->tm_hour * 3600) 512 - (tlast->tm_min * 60) - tlast->tm_sec 513 + (dt->fs_freq * 86400)); 514 }; 515 if (arg != 'w' || dumpme) 516 (void) printf( 517 "%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 518 dumpme && (arg != 'w') ? '>' : ' ', 519 dtwalk->dd_name, 520 dt ? dt->fs_file : "", 521 dtwalk->dd_level, 522 date); 523 } 524} 525 526int 527datesort(a1, a2) 528 const void *a1, *a2; 529{ 530 struct dumpdates *d1 = *(struct dumpdates **)a1; 531 struct dumpdates *d2 = *(struct dumpdates **)a2; 532 int diff; 533 534 diff = strncmp(d1->dd_name, d2->dd_name, sizeof(d1->dd_name)); 535 if (diff == 0) 536 return (d2->dd_ddate - d1->dd_ddate); 537 return (diff); 538} 539