home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / dump / optr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-16  |  11.9 KB  |  542 lines

  1. /*-
  2.  * Copyright (c) 1980, 1988 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)optr.c    5.14 (Berkeley) 7/16/92";
  36. #endif /* not lint */
  37.  
  38. #ifdef sunos
  39. #include <stdio.h>
  40. #include <ctype.h>
  41. #include <sys/param.h>
  42. #include <sys/wait.h>
  43. #include <sys/stat.h>
  44. #include <sys/time.h>
  45. #else
  46. #include <sys/param.h>
  47. #include <sys/wait.h>
  48. #include <stdio.h>
  49. #endif
  50. #include <signal.h>
  51. #include <time.h>
  52. #include <fstab.h>
  53. #include <grp.h>
  54. #include <utmp.h>
  55. #include <tzfile.h>
  56. #include <errno.h>
  57. #ifdef __STDC__
  58. #include <unistd.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <stdarg.h>
  62. #else
  63. #include <varargs.h>
  64. #endif
  65. #include "dump.h"
  66. #include "pathnames.h"
  67.  
  68. static void alarmcatch();
  69. static void sendmes();
  70.  
  71. /*
  72.  *    Query the operator; This previously-fascist piece of code
  73.  *    no longer requires an exact response.
  74.  *    It is intended to protect dump aborting by inquisitive
  75.  *    people banging on the console terminal to see what is
  76.  *    happening which might cause dump to croak, destroying
  77.  *    a large number of hours of work.
  78.  *
  79.  *    Every 2 minutes we reprint the message, alerting others
  80.  *    that dump needs attention.
  81.  */
  82. int    timeout;
  83. char    *attnmessage;        /* attention message */
  84.  
  85. int
  86. query(question)
  87.     char    *question;
  88. {
  89.     char    replybuffer[64];
  90.     int    back, errcount;
  91.     FILE    *mytty;
  92.  
  93.     if ((mytty = fopen(_PATH_TTY, "r")) == NULL)
  94.         quit("fopen on %s fails: %s\n", _PATH_TTY, strerror(errno));
  95.     attnmessage = question;
  96.     timeout = 0;
  97.     alarmcatch();
  98.     back = -1;
  99.     errcount = 0;
  100.     do {
  101.         if (fgets(replybuffer, 63, mytty) == NULL) {
  102.             clearerr(mytty);
  103.             if (++errcount > 30)    /* XXX    ugly */
  104.                 quit("excessive operator query failures\n");
  105.         } else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') {
  106.             back = 1;
  107.         } else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') {
  108.             back = 0;
  109.         } else {
  110.             (void) fprintf(stderr,
  111.                 "  DUMP: \"Yes\" or \"No\"?\n");
  112.             (void) fprintf(stderr,
  113.                 "  DUMP: %s: (\"yes\" or \"no\") ", question);
  114.         }
  115.     } while (back < 0);
  116.  
  117.     /*
  118.      *    Turn off the alarm, and reset the signal to trap out..
  119.      */
  120.     (void) alarm(0);
  121.     if (signal(SIGALRM, sig) == SIG_IGN)
  122.         signal(SIGALRM, SIG_IGN);
  123.     (void) fclose(mytty);
  124.     return(back);
  125. }
  126.  
  127. char lastmsg[100];
  128.  
  129. /*
  130.  *    Alert the console operator, and enable the alarm clock to
  131.  *    sleep for 2 minutes in case nobody comes to satisfy dump
  132.  */
  133. static void
  134. alarmcatch()
  135. {
  136.     if (notify == 0) {
  137.         if (timeout == 0)
  138.             (void) fprintf(stderr,
  139.                 "  DUMP: %s: (\"yes\" or \"no\") ",
  140.                 attnmessage);
  141.         else
  142.             msgtail("\7\7");
  143.     } else {
  144.         if (timeout) {
  145.             msgtail("\n");
  146.             broadcast("");        /* just print last msg */
  147.         }
  148.         (void) fprintf(stderr,"  DUMP: %s: (\"yes\" or \"no\") ",
  149.             attnmessage);
  150.     }
  151.     signal(SIGALRM, alarmcatch);
  152.     (void) alarm(120);
  153.     timeout = 1;
  154. }
  155.  
  156. /*
  157.  *    Here if an inquisitive operator interrupts the dump program
  158.  */
  159. void
  160. interrupt(signo)
  161.     int signo;
  162. {
  163.     msg("Interrupt received.\n");
  164.     if (query("Do you want to abort dump?"))
  165.         dumpabort(0);
  166. }
  167.  
  168. /*
  169.  *    The following variables and routines manage alerting
  170.  *    operators to the status of dump.
  171.  *    This works much like wall(1) does.
  172.  */
  173. struct    group *gp;
  174.  
  175. /*
  176.  *    Get the names from the group entry "operator" to notify.
  177.  */    
  178. void
  179. set_operators()
  180. {
  181.     if (!notify)        /*not going to notify*/
  182.         return;
  183.     gp = getgrnam(OPGRENT);
  184.     (void) endgrent();
  185.     if (gp == NULL) {
  186.         msg("No group entry for %s.\n", OPGRENT);
  187.         notify = 0;
  188.         return;
  189.     }
  190. }
  191.  
  192. struct tm *localtime();
  193. struct tm *localclock;
  194.  
  195. /*
  196.  *    We fork a child to do the actual broadcasting, so
  197.  *    that the process control groups are not messed up
  198.  */
  199. void
  200. broadcast(message)
  201.     char    *message;
  202. {
  203.     time_t        clock;
  204.     FILE    *f_utmp;
  205.     struct    utmp    utmp;
  206.     char    **np;
  207.     int    pid, s;
  208.  
  209.     if (!notify || gp == NULL)
  210.         return;
  211.  
  212.     switch (pid = fork()) {
  213.     case -1:
  214.         return;
  215.     case 0:
  216.         break;
  217.     default:
  218.         while (wait(&s) != pid)
  219.             continue;
  220.         return;
  221.     }
  222.  
  223.     clock = time((time_t *)0);
  224.     localclock = localtime(&clock);
  225.  
  226.     if ((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) {
  227.         msg("Cannot open %s: %s\n", _PATH_UTMP, strerror(errno));
  228.         return;
  229.     }
  230.  
  231.     while (!feof(f_utmp)) {
  232.         if (fread((char *) &utmp, sizeof (struct utmp), 1, f_utmp) != 1)
  233.             break;
  234.         if (utmp.ut_name[0] == 0)
  235.             continue;
  236.         for (np = gp->gr_mem; *np; np++) {
  237.             if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0)
  238.                 continue;
  239.             /*
  240.              *    Do not send messages to operators on dialups
  241.              */
  242.             if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0)
  243.                 continue;
  244. #ifdef DEBUG
  245.             msg("Message to %s at %s\n", *np, utmp.ut_line);
  246. #endif
  247.             sendmes(utmp.ut_line, message);
  248.         }
  249.     }
  250.     (void) fclose(f_utmp);
  251.     Exit(0);    /* the wait in this same routine will catch this */
  252.     /* NOTREACHED */
  253. }
  254.  
  255. static void
  256. sendmes(tty, message)
  257.     char *tty, *message;
  258. {
  259.     char t[50], buf[BUFSIZ];
  260.     register char *cp;
  261.     int lmsg = 1;
  262.     FILE *f_tty;
  263.  
  264.     (void) strcpy(t, _PATH_DEV);
  265.     (void) strcat(t, tty);
  266.  
  267.     if ((f_tty = fopen(t, "w")) != NULL) {
  268.         setbuf(f_tty, buf);
  269.         (void) fprintf(f_tty,
  270.             "\n\
  271. \7\7\7Message from the dump program to all operators at %d:%02d ...\r\n\n\
  272. DUMP: NEEDS ATTENTION: ",
  273.             localclock->tm_hour, localclock->tm_min);
  274.         for (cp = lastmsg; ; cp++) {
  275.             if (*cp == '\0') {
  276.                 if (lmsg) {
  277.                     cp = message;
  278.                     if (*cp == '\0')
  279.                         break;
  280.                     lmsg = 0;
  281.                 } else
  282.                     break;
  283.             }
  284.             if (*cp == '\n')
  285.                 (void) putc('\r', f_tty);
  286.             (void) putc(*cp, f_tty);
  287.         }
  288.         (void) fclose(f_tty);
  289.     }
  290. }
  291.  
  292. /*
  293.  *    print out an estimate of the amount of time left to do the dump
  294.  */
  295.  
  296. time_t    tschedule = 0;
  297.  
  298. void
  299. timeest()
  300. {
  301.     time_t    tnow, deltat;
  302.  
  303.     (void) time((time_t *) &tnow);
  304.     if (tnow >= tschedule) {
  305.         tschedule = tnow + 300;
  306.         if (blockswritten < 500)
  307.             return;    
  308.         deltat = tstart_writing - tnow +
  309.             (1.0 * (tnow - tstart_writing))
  310.             / blockswritten * tapesize;
  311.         msg("%3.2f%% done, finished in %d:%02d\n",
  312.             (blockswritten * 100.0) / tapesize,
  313.             deltat / 3600, (deltat % 3600) / 60);
  314.     }
  315. }
  316.  
  317. void
  318. #if __STDC__
  319. msg(const char *fmt, ...)
  320. #else
  321. msg(fmt, va_alist)
  322.     char *fmt;
  323.     va_dcl
  324. #endif
  325. {
  326.     va_list ap;
  327.  
  328.     (void) fprintf(stderr,"  DUMP: ");
  329. #ifdef TDEBUG
  330.     (void) fprintf(stderr, "pid=%d ", getpid());
  331. #endif
  332. #if __STDC__
  333.     va_start(ap, fmt);
  334. #else
  335.     va_start(ap);
  336. #endif
  337.     (void) vfprintf(stderr, fmt, ap);
  338.     (void) fflush(stdout);
  339.     (void) fflush(stderr);
  340.     (void) vsprintf(lastmsg, fmt, ap);
  341.     va_end(ap);
  342. }
  343.  
  344. void
  345. #if __STDC__
  346. msgtail(const char *fmt, ...)
  347. #else
  348. msgtail(fmt, va_alist)
  349.     char *fmt;
  350.     va_dcl
  351. #endif
  352. {
  353.     va_list ap;
  354. #if __STDC__
  355.     va_start(ap, fmt);
  356. #else
  357.     va_start(ap);
  358. #endif
  359.     (void) vfprintf(stderr, fmt, ap);
  360.     va_end(ap);
  361. }
  362.  
  363. void
  364. #if __STDC__
  365. quit(const char *fmt, ...)
  366. #else
  367. quit(fmt, va_alist)
  368.     char *fmt;
  369.     va_dcl
  370. #endif
  371. {
  372.     va_list ap;
  373.  
  374.     (void) fprintf(stderr,"  DUMP: ");
  375. #ifdef TDEBUG
  376.     (void) fprintf(stderr, "pid=%d ", getpid());
  377. #endif
  378. #if __STDC__
  379.     va_start(ap, fmt);
  380. #else
  381.     va_start(ap);
  382. #endif
  383.     (void) vfprintf(stderr, fmt, ap);
  384.     va_end(ap);
  385.     (void) fflush(stdout);
  386.     (void) fflush(stderr);
  387.     dumpabort(0);
  388. }
  389.  
  390. /*
  391.  *    Tell the operator what has to be done;
  392.  *    we don't actually do it
  393.  */
  394.  
  395. struct fstab *
  396. allocfsent(fs)
  397.     register struct fstab *fs;
  398. {
  399.     register struct fstab *new;
  400.  
  401.     new = (struct fstab *)malloc(sizeof (*fs));
  402.     if (new == NULL ||
  403.         (new->fs_file = strdup(fs->fs_file)) == NULL ||
  404.         (new->fs_type = strdup(fs->fs_type)) == NULL ||
  405.         (new->fs_spec = strdup(fs->fs_spec)) == NULL)
  406.         quit("%s\n", strerror(errno));
  407.     new->fs_passno = fs->fs_passno;
  408.     new->fs_freq = fs->fs_freq;
  409.     return (new);
  410. }
  411.  
  412. struct    pfstab {
  413.     struct    pfstab *pf_next;
  414.     struct    fstab *pf_fstab;
  415. };
  416.  
  417. static    struct pfstab *table;
  418.  
  419. void
  420. getfstab()
  421. {
  422.     register struct fstab *fs;
  423.     register struct pfstab *pf;
  424.  
  425.     if (setfsent() == 0) {
  426.         msg("Can't open %s for dump table information: %s\n",
  427.             _PATH_FSTAB, strerror(errno));
  428.         return;
  429.     }
  430.     while (fs = getfsent()) {
  431.         if (strcmp(fs->fs_type, FSTAB_RW) &&
  432.             strcmp(fs->fs_type, FSTAB_RO) &&
  433.             strcmp(fs->fs_type, FSTAB_RQ))
  434.             continue;
  435.         fs = allocfsent(fs);
  436.         if ((pf = (struct pfstab *)malloc(sizeof (*pf))) == NULL)
  437.             quit("%s\n", strerror(errno));
  438.         pf->pf_fstab = fs;
  439.         pf->pf_next = table;
  440.         table = pf;
  441.     }
  442.     (void) endfsent();
  443. }
  444.  
  445. /*
  446.  * Search in the fstab for a file name.
  447.  * This file name can be either the special or the path file name.
  448.  *
  449.  * The entries in the fstab are the BLOCK special names, not the
  450.  * character special names.
  451.  * The caller of fstabsearch assures that the character device
  452.  * is dumped (that is much faster)
  453.  *
  454.  * The file name can omit the leading '/'.
  455.  */
  456. struct fstab *
  457. fstabsearch(key)
  458.     char *key;
  459. {
  460.     register struct pfstab *pf;
  461.     register struct fstab *fs;
  462.     char *rawname();
  463.  
  464.     for (pf = table; pf != NULL; pf = pf->pf_next) {
  465.         fs = pf->pf_fstab;
  466.         if (strcmp(fs->fs_file, key) == 0 ||
  467.             strcmp(fs->fs_spec, key) == 0 ||
  468.             strcmp(rawname(fs->fs_spec), key) == 0)
  469.             return (fs);
  470.         if (key[0] != '/') {
  471.             if (*fs->fs_spec == '/' &&
  472.                 strcmp(fs->fs_spec + 1, key) == 0)
  473.                 return (fs);
  474.             if (*fs->fs_file == '/' &&
  475.                 strcmp(fs->fs_file + 1, key) == 0)
  476.                 return (fs);
  477.         }
  478.     }
  479.     return (NULL);
  480. }
  481.  
  482. /*
  483.  *    Tell the operator what to do
  484.  */
  485. void
  486. lastdump(arg)
  487.     char    arg;    /* w ==> just what to do; W ==> most recent dumps */
  488. {
  489.     register int i;
  490.     register struct fstab *dt;
  491.     register struct dumpdates *dtwalk;
  492.     char *lastname, *date;
  493.     int dumpme, datesort();
  494.     time_t tnow;
  495.  
  496.     (void) time(&tnow);
  497.     getfstab();        /* /etc/fstab input */
  498.     initdumptimes();    /* /etc/dumpdates input */
  499.     qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort);
  500.  
  501.     if (arg == 'w')
  502.         (void) printf("Dump these file systems:\n");
  503.     else
  504.         (void) printf("Last dump(s) done (Dump '>' file systems):\n");
  505.     lastname = "??";
  506.     ITITERATE(i, dtwalk) {
  507.         if (strncmp(lastname, dtwalk->dd_name,
  508.             sizeof(dtwalk->dd_name)) == 0)
  509.             continue;
  510.         date = (char *)ctime(&dtwalk->dd_ddate);
  511.         date[16] = '\0';    /* blast away seconds and year */
  512.         lastname = dtwalk->dd_name;
  513.         dt = fstabsearch(dtwalk->dd_name);
  514.         dumpme = (dt != NULL &&
  515.             dt->fs_freq != 0 &&
  516.             dtwalk->dd_ddate < tnow - (dt->fs_freq * SECSPERDAY));
  517.         if (arg != 'w' || dumpme)
  518.             (void) printf(
  519.                 "%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
  520.                 dumpme && (arg != 'w') ? '>' : ' ',
  521.                 dtwalk->dd_name,
  522.                 dt ? dt->fs_file : "",
  523.                 dtwalk->dd_level,
  524.                 date);
  525.     }
  526. }
  527.  
  528. int
  529. datesort(a1, a2)
  530.     void *a1, *a2;
  531. {
  532.     struct dumpdates *d1 = *(struct dumpdates **)a1;
  533.     struct dumpdates *d2 = *(struct dumpdates **)a2;
  534.     int diff;
  535.  
  536.     diff = strncmp(d1->dd_name, d2->dd_name, sizeof(d1->dd_name));
  537.     if (diff == 0)
  538.         return (d2->dd_ddate - d1->dd_ddate);
  539.     return (diff);
  540. }
  541.  
  542.