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