1 /* 2 * Copyright (c) 1980, 1988 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)optr.c 5.2 (Berkeley) 09/12/89"; 9 #endif not lint 10 11 #include "dump.h" 12 #include "pathnames.h" 13 14 /* 15 * This is from /usr/include/grp.h 16 * That defined struct group, which conflicts 17 * with the struct group defined in param.h 18 */ 19 struct Group { /* see getgrent(3) */ 20 char *gr_name; 21 char *gr_passwd; 22 int gr_gid; 23 char **gr_mem; 24 }; 25 struct Group *getgrnam(); 26 /* 27 * Query the operator; This previously-fascist piece of code 28 * no longer requires an exact response. 29 * It is intended to protect dump aborting by inquisitive 30 * people banging on the console terminal to see what is 31 * happening which might cause dump to croak, destroying 32 * a large number of hours of work. 33 * 34 * Every 2 minutes we reprint the message, alerting others 35 * that dump needs attention. 36 */ 37 int timeout; 38 char *attnmessage; /* attention message */ 39 query(question) 40 char *question; 41 { 42 char replybuffer[64]; 43 int back; 44 FILE *mytty; 45 46 if ( (mytty = fopen(_PATH_TTY, "r")) == NULL){ 47 msg("fopen on %s fails\n", _PATH_TTY); 48 abort(); 49 } 50 attnmessage = question; 51 timeout = 0; 52 alarmcatch(); 53 for(;;){ 54 if ( fgets(replybuffer, 63, mytty) == NULL){ 55 if (ferror(mytty)){ 56 clearerr(mytty); 57 continue; 58 } 59 } else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') { 60 back = 1; 61 goto done; 62 } else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') { 63 back = 0; 64 goto done; 65 } else { 66 fprintf(stderr, " DUMP: \"Yes\" or \"No\"?\n"); 67 fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ", 68 question); 69 } 70 } 71 done: 72 /* 73 * Turn off the alarm, and reset the signal to trap out.. 74 */ 75 alarm(0); 76 if (signal(SIGALRM, sigalrm) == SIG_IGN) 77 signal(SIGALRM, SIG_IGN); 78 fclose(mytty); 79 return(back); 80 } 81 82 char lastmsg[100]; 83 84 /* 85 * Alert the console operator, and enable the alarm clock to 86 * sleep for 2 minutes in case nobody comes to satisfy dump 87 */ 88 alarmcatch() 89 { 90 if (notify == 0) { 91 if (timeout == 0) 92 fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ", 93 attnmessage); 94 else 95 msgtail("\7\7"); 96 } else { 97 if (timeout) { 98 msgtail("\n"); 99 broadcast(""); /* just print last msg */ 100 } 101 fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ", 102 attnmessage); 103 } 104 signal(SIGALRM, alarmcatch); 105 alarm(120); 106 timeout = 1; 107 } 108 /* 109 * Here if an inquisitive operator interrupts the dump program 110 */ 111 interrupt() 112 { 113 msg("Interrupt received.\n"); 114 if (query("Do you want to abort dump?")) 115 dumpabort(); 116 } 117 118 /* 119 * The following variables and routines manage alerting 120 * operators to the status of dump. 121 * This works much like wall(1) does. 122 */ 123 struct Group *gp; 124 125 /* 126 * Get the names from the group entry "operator" to notify. 127 */ 128 set_operators() 129 { 130 if (!notify) /*not going to notify*/ 131 return; 132 gp = getgrnam(OPGRENT); 133 endgrent(); 134 if (gp == (struct Group *)0){ 135 msg("No group entry for %s.\n", 136 OPGRENT); 137 notify = 0; 138 return; 139 } 140 } 141 142 struct tm *localtime(); 143 struct tm *localclock; 144 145 /* 146 * We fork a child to do the actual broadcasting, so 147 * that the process control groups are not messed up 148 */ 149 broadcast(message) 150 char *message; 151 { 152 time_t clock; 153 FILE *f_utmp; 154 struct utmp utmp; 155 int nusers; 156 char **np; 157 int pid, s; 158 159 switch (pid = fork()) { 160 case -1: 161 return; 162 case 0: 163 break; 164 default: 165 while (wait(&s) != pid) 166 continue; 167 return; 168 } 169 170 if (!notify || gp == 0) 171 exit(0); 172 clock = time(0); 173 localclock = localtime(&clock); 174 175 if((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) { 176 msg("Cannot open %s\n", _PATH_UTMP); 177 return; 178 } 179 180 nusers = 0; 181 while (!feof(f_utmp)){ 182 if (fread(&utmp, sizeof (struct utmp), 1, f_utmp) != 1) 183 break; 184 if (utmp.ut_name[0] == 0) 185 continue; 186 nusers++; 187 for (np = gp->gr_mem; *np; np++){ 188 if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0) 189 continue; 190 /* 191 * Do not send messages to operators on dialups 192 */ 193 if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0) 194 continue; 195 #ifdef DEBUG 196 msg("Message to %s at %s\n", 197 utmp.ut_name, utmp.ut_line); 198 #endif DEBUG 199 sendmes(utmp.ut_line, message); 200 } 201 } 202 fclose(f_utmp); 203 Exit(0); /* the wait in this same routine will catch this */ 204 /* NOTREACHED */ 205 } 206 207 sendmes(tty, message) 208 char *tty, *message; 209 { 210 char t[50], buf[BUFSIZ]; 211 register char *cp; 212 int lmsg = 1; 213 FILE *f_tty; 214 215 strcpy(t, _PATH_DEV); 216 strcat(t, tty); 217 218 if((f_tty = fopen(t, "w")) != NULL) { 219 setbuf(f_tty, buf); 220 fprintf(f_tty, "\n\07\07\07Message from the dump program to all operators at %d:%02d ...\r\n\n DUMP: NEEDS ATTENTION: " 221 ,localclock->tm_hour 222 ,localclock->tm_min); 223 for (cp = lastmsg; ; cp++) { 224 if (*cp == '\0') { 225 if (lmsg) { 226 cp = message; 227 if (*cp == '\0') 228 break; 229 lmsg = 0; 230 } else 231 break; 232 } 233 if (*cp == '\n') 234 putc('\r', f_tty); 235 putc(*cp, f_tty); 236 } 237 fclose(f_tty); 238 } 239 } 240 241 /* 242 * print out an estimate of the amount of time left to do the dump 243 */ 244 245 time_t tschedule = 0; 246 247 timeest() 248 { 249 time_t tnow, deltat; 250 251 time (&tnow); 252 if (tnow >= tschedule){ 253 tschedule = tnow + 300; 254 if (blockswritten < 500) 255 return; 256 deltat = tstart_writing - tnow + 257 (((1.0*(tnow - tstart_writing))/blockswritten) * esize); 258 msg("%3.2f%% done, finished in %d:%02d\n", 259 (blockswritten*100.0)/esize, 260 deltat/3600, (deltat%3600)/60); 261 } 262 } 263 264 int blocksontape() 265 { 266 /* 267 * esize: total number of blocks estimated over all reels 268 * blockswritten: blocks actually written, over all reels 269 * etapes: estimated number of tapes to write 270 * 271 * tsize: blocks can write on this reel 272 * asize: blocks written on this reel 273 * tapeno: number of tapes written so far 274 */ 275 if (tapeno == etapes) 276 return(esize - (etapes - 1)*tsize); 277 return(tsize); 278 } 279 280 /* VARARGS1 */ 281 /* ARGSUSED */ 282 msg(fmt, a1, a2, a3, a4, a5) 283 char *fmt; 284 int a1, a2, a3, a4, a5; 285 { 286 fprintf(stderr," DUMP: "); 287 #ifdef TDEBUG 288 fprintf(stderr,"pid=%d ", getpid()); 289 #endif 290 fprintf(stderr, fmt, a1, a2, a3, a4, a5); 291 fflush(stdout); 292 fflush(stderr); 293 sprintf(lastmsg, fmt, a1, a2, a3, a4, a5); 294 } 295 296 /* VARARGS1 */ 297 /* ARGSUSED */ 298 msgtail(fmt, a1, a2, a3, a4, a5) 299 char *fmt; 300 int a1, a2, a3, a4, a5; 301 { 302 fprintf(stderr, fmt, a1, a2, a3, a4, a5); 303 } 304 /* 305 * Tell the operator what has to be done; 306 * we don't actually do it 307 */ 308 309 struct fstab * 310 allocfsent(fs) 311 register struct fstab *fs; 312 { 313 register struct fstab *new; 314 register char *cp; 315 char *malloc(); 316 317 new = (struct fstab *)malloc(sizeof (*fs)); 318 cp = malloc(strlen(fs->fs_file) + 1); 319 strcpy(cp, fs->fs_file); 320 new->fs_file = cp; 321 cp = malloc(strlen(fs->fs_type) + 1); 322 strcpy(cp, fs->fs_type); 323 new->fs_type = cp; 324 cp = malloc(strlen(fs->fs_spec) + 1); 325 strcpy(cp, fs->fs_spec); 326 new->fs_spec = cp; 327 new->fs_passno = fs->fs_passno; 328 new->fs_freq = fs->fs_freq; 329 return (new); 330 } 331 332 struct pfstab { 333 struct pfstab *pf_next; 334 struct fstab *pf_fstab; 335 }; 336 337 static struct pfstab *table = NULL; 338 339 getfstab() 340 { 341 register struct fstab *fs; 342 register struct pfstab *pf; 343 344 if (setfsent() == 0) { 345 msg("Can't open %s for dump table information.\n", _PATH_FSTAB); 346 return; 347 } 348 while (fs = getfsent()) { 349 if (strcmp(fs->fs_type, FSTAB_RW) && 350 strcmp(fs->fs_type, FSTAB_RO) && 351 strcmp(fs->fs_type, FSTAB_RQ)) 352 continue; 353 fs = allocfsent(fs); 354 pf = (struct pfstab *)malloc(sizeof (*pf)); 355 pf->pf_fstab = fs; 356 pf->pf_next = table; 357 table = pf; 358 } 359 endfsent(); 360 } 361 362 /* 363 * Search in the fstab for a file name. 364 * This file name can be either the special or the path file name. 365 * 366 * The entries in the fstab are the BLOCK special names, not the 367 * character special names. 368 * The caller of fstabsearch assures that the character device 369 * is dumped (that is much faster) 370 * 371 * The file name can omit the leading '/'. 372 */ 373 struct fstab * 374 fstabsearch(key) 375 char *key; 376 { 377 register struct pfstab *pf; 378 register struct fstab *fs; 379 char *rawname(); 380 381 if (table == NULL) 382 return ((struct fstab *)0); 383 for (pf = table; pf; pf = pf->pf_next) { 384 fs = pf->pf_fstab; 385 if (strcmp(fs->fs_file, key) == 0) 386 return (fs); 387 if (strcmp(fs->fs_spec, key) == 0) 388 return (fs); 389 if (strcmp(rawname(fs->fs_spec), key) == 0) 390 return (fs); 391 if (key[0] != '/'){ 392 if (*fs->fs_spec == '/' && 393 strcmp(fs->fs_spec + 1, key) == 0) 394 return (fs); 395 if (*fs->fs_file == '/' && 396 strcmp(fs->fs_file + 1, key) == 0) 397 return (fs); 398 } 399 } 400 return (0); 401 } 402 403 /* 404 * Tell the operator what to do 405 */ 406 lastdump(arg) 407 char arg; /* w ==> just what to do; W ==> most recent dumps */ 408 { 409 char *lastname; 410 char *date; 411 register int i; 412 time_t tnow; 413 register struct fstab *dt; 414 int dumpme; 415 register struct idates *itwalk; 416 417 int idatesort(); 418 419 time(&tnow); 420 getfstab(); /* /etc/fstab input */ 421 inititimes(); /* /etc/dumpdates input */ 422 qsort(idatev, nidates, sizeof(struct idates *), idatesort); 423 424 if (arg == 'w') 425 fprintf(stdout, "Dump these file systems:\n"); 426 else 427 fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n"); 428 lastname = "??"; 429 ITITERATE(i, itwalk){ 430 if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0) 431 continue; 432 date = (char *)ctime(&itwalk->id_ddate); 433 date[16] = '\0'; /* blast away seconds and year */ 434 lastname = itwalk->id_name; 435 dt = fstabsearch(itwalk->id_name); 436 dumpme = ( (dt != 0) 437 && (dt->fs_freq != 0) 438 && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY))); 439 if ( (arg != 'w') || dumpme) 440 fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 441 dumpme && (arg != 'w') ? '>' : ' ', 442 itwalk->id_name, 443 dt ? dt->fs_file : "", 444 itwalk->id_incno, 445 date 446 ); 447 } 448 } 449 450 int idatesort(p1, p2) 451 struct idates **p1, **p2; 452 { 453 int diff; 454 455 diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name)); 456 if (diff == 0) 457 return ((*p2)->id_ddate - (*p1)->id_ddate); 458 else 459 return (diff); 460 } 461 462 int max(a,b) 463 int a, b; 464 { 465 return(a>b?a:b); 466 } 467 int min(a,b) 468 int a, b; 469 { 470 return(a<b?a:b); 471 } 472