Mercurial > illumos > onarm
annotate usr/src/cmd/backup/dump/dumpoptr.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * Copyright (c) 1998 by Sun Microsystems, Inc. | |
3 * All rights reserved. | |
4 */ | |
5 | |
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ | |
7 /* All Rights Reserved */ | |
8 | |
9 /* | |
10 * Copyright (c) 1980 Regents of the University of California. | |
11 * All rights reserved. The Berkeley software License Agreement | |
12 * specifies the terms and conditions for redistribution. | |
13 */ | |
14 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
15 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 16 |
17 #include <errno.h> | |
18 #include "dump.h" | |
19 | |
20 static unsigned int timeout; /* current timeout */ | |
21 static char *attnmessage, *saveattn; /* attention message */ | |
22 | |
23 #ifdef __STDC__ | |
24 static void alarmcatch(); | |
25 static int idatesort(const void *, const void *); | |
26 #else /* !__STDC__ */ | |
27 static void alarmcatch(); | |
28 static int idatesort(); | |
29 #endif | |
30 | |
31 #ifdef DEBUG | |
32 extern int xflag; | |
33 #endif | |
34 | |
35 /* | |
36 * Query the operator; This fascist piece of code requires | |
37 * an exact response. | |
38 * It is intended to protect dump aborting by inquisitive | |
39 * people banging on the console terminal to see what is | |
40 * happening which might cause dump to croak, destroying | |
41 * a large number of hours of work. | |
42 * | |
43 * Every time += 2 minutes we reprint the message, alerting others | |
44 * that dump needs attention. | |
45 */ | |
46 int | |
47 query(question) | |
48 char *question; | |
49 { | |
50 int def = -1; | |
51 | |
52 while (def == -1) | |
53 def = query_once(question, -1); | |
54 return (def); | |
55 } | |
56 | |
57 static int in_query_once; | |
58 static jmp_buf sjalarmbuf; | |
59 | |
60 /* real simple check-sum */ | |
61 static int | |
62 addem(s) | |
63 char *s; | |
64 { | |
65 int total = 0; | |
66 | |
67 if (s == (char *)NULL) | |
68 return (total); | |
69 while (*s) | |
70 total += *s++; | |
71 return (total); | |
72 } | |
73 | |
74 int | |
75 query_once(question, def) | |
76 char *question; | |
77 int def; | |
78 { | |
79 static char *lastmsg; | |
80 static int lastmsgsum; | |
81 int msgsum; | |
82 char replybuffer[BUFSIZ]; | |
83 int back; | |
84 time32_t timeclockstate; | |
85 pollfd_t pollset; | |
86 struct sigvec sv; | |
87 | |
88 /* special hook to flush timeout cache */ | |
89 if (question == NULL) { | |
90 lastmsg = (char *)NULL; | |
91 lastmsgsum = 0; | |
92 return (0); | |
93 } | |
94 | |
95 attnmessage = question; | |
96 /* | |
97 * Only reset the state if the message changed somehow | |
98 */ | |
99 msgsum = addem(question); | |
100 if (lastmsg != question || lastmsgsum != msgsum) { | |
101 timeout = 0; | |
102 if (telapsed && tstart_writing) | |
103 *telapsed += time((time_t *)0) - *tstart_writing; | |
104 lastmsg = question; | |
105 lastmsgsum = msgsum; | |
106 } | |
107 timeclockstate = timeclock((time_t)0); | |
108 if (setjmp(sjalarmbuf) != 0) { | |
109 if (def != -1) { | |
110 if (def) | |
111 msgtail(gettext("YES\n")); | |
112 else | |
113 msgtail(gettext("NO\n")); | |
114 } | |
115 back = def; | |
116 goto done; | |
117 } | |
118 alarmcatch(); | |
119 in_query_once = 1; | |
120 pollset.fd = -1; | |
121 pollset.events = 0; | |
122 pollset.revents = 0; | |
123 if (isatty(fileno(stdin))) { | |
124 pollset.fd = fileno(stdin); | |
125 pollset.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; | |
126 } else { | |
127 dumpabort(); | |
128 /*NOTREACHED*/ | |
129 } | |
130 for (;;) { | |
131 if (poll(&pollset, 1, -1) < 0) { | |
132 if (errno == EINTR) | |
133 continue; | |
134 perror("poll(stdin)"); | |
135 dumpabort(); | |
136 /*NOTREACHED*/ | |
137 } | |
138 if (pollset.revents == 0) | |
139 continue; /* sanity check */ | |
140 if (fgets(replybuffer, sizeof (replybuffer), stdin) == NULL) { | |
141 if (ferror(stdin)) { | |
142 clearerr(stdin); | |
143 continue; | |
144 } else { | |
145 dumpabort(); | |
146 /*NOTREACHED*/ | |
147 } | |
148 } | |
149 timeout = 0; | |
150 if (strcasecmp(replybuffer, gettext("yes\n")) == 0) { | |
151 back = 1; | |
152 lastmsg = (char *)NULL; | |
153 lastmsgsum = 0; | |
154 goto done; | |
155 } else if (strcasecmp(replybuffer, gettext("no\n")) == 0) { | |
156 back = 0; | |
157 lastmsg = (char *)NULL; | |
158 lastmsgsum = 0; | |
159 goto done; | |
160 } else { | |
161 msg(gettext("\"yes\" or \"no\"?\n")); | |
162 in_query_once = 0; | |
163 alarmcatch(); | |
164 in_query_once = 1; | |
165 } | |
166 } | |
167 done: | |
168 /* | |
169 * Turn off the alarm, and reset the signal to trap out.. | |
170 */ | |
171 (void) alarm(0); | |
172 attnmessage = NULL; | |
173 sv.sv_handler = sigAbort; | |
174 sv.sv_flags = SA_RESTART; | |
175 (void) sigemptyset(&sv.sa_mask); | |
176 (void) sigvec(SIGALRM, &sv, (struct sigvec *)0); | |
177 if (tstart_writing) | |
178 (void) time(tstart_writing); | |
179 (void) timeclock(timeclockstate); | |
180 in_query_once = 0; | |
181 return (back); | |
182 } | |
183 /* | |
184 * Alert the console operator, and enable the alarm clock to | |
185 * sleep for time += 2 minutes in case nobody comes to satisfy dump | |
186 * If the alarm goes off while in the query_once for loop, we just | |
187 * longjmp back there and return the default answer. | |
188 */ | |
189 static void | |
190 #ifdef __STDC__ | |
191 alarmcatch(void) | |
192 #else | |
193 alarmcatch() | |
194 #endif | |
195 { | |
196 struct sigvec sv; | |
197 | |
198 if (in_query_once) { | |
199 longjmp(sjalarmbuf, 1); | |
200 } | |
201 if (timeout) { | |
202 msgtail("\n"); | |
203 } | |
204 | |
205 timeout += 120; | |
206 msg(gettext("NEEDS ATTENTION: %s"), attnmessage); | |
207 sv.sv_handler = alarmcatch; | |
208 sv.sv_flags = SA_RESTART; | |
209 (void) sigemptyset(&sv.sa_mask); | |
210 (void) sigvec(SIGALRM, &sv, (struct sigvec *)0); | |
211 (void) alarm(timeout); | |
212 } | |
213 | |
214 /* | |
215 * Here if an inquisitive operator interrupts the dump program | |
216 */ | |
217 /*ARGSUSED*/ | |
218 void | |
219 interrupt(sig) | |
220 int sig; | |
221 { | |
222 if (!saveattn) { | |
223 saveattn = attnmessage; | |
224 } | |
225 msg(gettext("Interrupt received.\n")); | |
226 if (query(gettext( | |
227 "Do you want to abort dump?: (\"yes\" or \"no\") "))) { | |
228 dumpabort(); | |
229 /*NOTREACHED*/ | |
230 } | |
231 if (saveattn) { | |
232 attnmessage = saveattn; | |
233 saveattn = NULL; | |
234 alarmcatch(); | |
235 } | |
236 } | |
237 | |
238 /* | |
239 * We use wall(1) to do the actual broadcasting, so | |
240 * that we don't have to worry about duplicated code | |
241 * only getting fixed in one place. This also saves | |
242 * us from having to worry about process groups, | |
243 * controlling terminals, and the like. | |
244 */ | |
245 void | |
246 broadcast(message) | |
247 char *message; | |
248 { | |
249 time_t clock; | |
250 pid_t pid; | |
251 int saverr; | |
252 int fildes[2]; | |
253 FILE *wall; | |
254 struct tm *localclock; | |
255 | |
256 if (!notify) | |
257 return; | |
258 | |
259 if (pipe(fildes) < 0) { | |
260 saverr = errno; | |
261 msg(gettext("pipe: %s\n"), strerror(saverr)); | |
262 return; | |
263 } | |
264 | |
265 switch (pid = fork()) { | |
266 case -1: | |
267 return; | |
268 case 0: | |
269 close(fildes[0]); | |
270 if (dup2(fildes[1], 0) < 0) { | |
271 saverr = errno; | |
272 msg(gettext("dup2: %s\n"), strerror(saverr)); | |
273 exit(1); | |
274 } | |
275 execl("/usr/sbin/wall", "wall", "-g", OPGRENT, (char *)NULL); | |
276 saverr = errno; | |
277 msg(gettext("execl: %s\n"), strerror(saverr)); | |
278 exit(1); | |
279 default: | |
280 break; /* parent */ | |
281 } | |
282 | |
283 close(fildes[1]); | |
284 wall = fdopen(fildes[0], "r+"); | |
285 if (wall == (FILE *)NULL) { | |
286 saverr = errno; | |
287 msg(gettext("fdopen: %s\n"), strerror(saverr)); | |
288 return; | |
289 } | |
290 | |
291 clock = time((time_t *)0); | |
292 localclock = localtime(&clock); | |
293 | |
294 (void) fprintf(wall, gettext( | |
295 "\n\007\007\007Message from the dump program to all operators at \ | |
296 %d:%02d ...\n\n%s"), | |
297 localclock->tm_hour, localclock->tm_min, message); | |
298 fclose(wall); | |
299 | |
300 while (wait((int *)0) != pid) { | |
301 continue; | |
302 /*LINTED [empty loop body]*/ | |
303 } | |
304 } | |
305 | |
306 /* | |
307 * print out an estimate of the amount of time left to do the dump | |
308 */ | |
309 #define EST_SEC 600 /* every 10 minutes */ | |
310 void | |
311 timeest(force, blkswritten) | |
312 int force; | |
313 int blkswritten; | |
314 { | |
315 time_t tnow, deltat; | |
316 char *msgp; | |
317 | |
318 if (tschedule == NULL) | |
319 return; | |
320 if (*tschedule == 0) | |
321 *tschedule = time((time_t *)0) + EST_SEC; | |
322 (void) time(&tnow); | |
323 if ((force || tnow >= *tschedule) && blkswritten) { | |
324 *tschedule = tnow + EST_SEC; | |
325 if (!force && blkswritten < 50 * ntrec) | |
326 return; | |
327 deltat = (*telapsed + (tnow - *tstart_writing)) | |
328 * ((double)esize / blkswritten - 1.0); | |
329 msgp = gettext("%3.2f%% done, finished in %d:%02d\n"); | |
330 msg(msgp, (blkswritten*100.0)/esize, | |
331 deltat/3600, (deltat%3600)/60); | |
332 } | |
333 } | |
334 | |
335 #include <stdarg.h> | |
336 | |
337 /* VARARGS1 */ | |
338 void | |
339 msg(const char *fmt, ...) | |
340 { | |
341 char buf[1024], *cp; | |
342 size_t size; | |
343 va_list args; | |
344 | |
345 va_start(args, fmt); | |
346 (void) strcpy(buf, " DUMP: "); | |
347 cp = &buf[strlen(buf)]; | |
348 #ifdef TDEBUG | |
349 (void) sprintf(cp, "pid=%d ", getpid()); | |
350 cp = &buf[strlen(buf)]; | |
351 #endif | |
352 /* don't need -1, vsnprintf does it right */ | |
353 /* LINTED pointer arithmetic result fits in size_t */ | |
354 size = ((size_t)sizeof (buf)) - (size_t)(cp - buf); | |
355 (void) vsnprintf(cp, size, fmt, args); | |
356 (void) fputs(buf, stderr); | |
357 (void) fflush(stdout); | |
358 (void) fflush(stderr); | |
359 va_end(args); | |
360 } | |
361 | |
362 /* VARARGS1 */ | |
363 void | |
364 msgtail(const char *fmt, ...) | |
365 { | |
366 va_list args; | |
367 | |
368 va_start(args, fmt); | |
369 (void) vfprintf(stderr, fmt, args); | |
370 va_end(args); | |
371 } | |
372 | |
373 #define MINUTES(x) ((x) * 60) | |
374 | |
375 /* | |
376 * Tell the operator what has to be done; | |
377 * we don't actually do it | |
378 */ | |
379 void | |
380 lastdump(arg) /* w ==> just what to do; W ==> most recent dumps */ | |
381 int arg; | |
382 { | |
383 char *lastname; | |
384 char *date; | |
385 int i; | |
386 time_t tnow, ddate; | |
387 struct mntent *dt; | |
388 int dumpme = 0; | |
389 struct idates *itwalk; | |
390 | |
391 (void) time(&tnow); | |
392 mnttabread(); /* /etc/fstab input */ | |
393 inititimes(); /* /etc/dumpdates input */ | |
394 | |
395 /* Don't use msg(), this isn't a tell-the-world kind of thing */ | |
396 if (arg == 'w') | |
397 (void) fprintf(stdout, gettext("Dump these file systems:\n")); | |
398 else | |
399 (void) fprintf(stdout, gettext( | |
400 "Last dump(s) done (Dump '>' file systems):\n")); | |
401 | |
402 if (idatev != NULL) { | |
403 qsort((char *)idatev, nidates, sizeof (*idatev), idatesort); | |
404 lastname = "??"; | |
405 ITITERATE(i, itwalk) { | |
406 if (strncmp(lastname, itwalk->id_name, | |
407 sizeof (itwalk->id_name)) == 0) | |
408 continue; | |
409 /* must be ctime(), per ufsdump(4) */ | |
410 ddate = itwalk->id_ddate; | |
411 date = (char *)ctime(&ddate); | |
412 date[16] = '\0'; /* blow away seconds and year */ | |
413 lastname = itwalk->id_name; | |
414 dt = mnttabsearch(itwalk->id_name, 0); | |
415 if ((time_t)(itwalk->id_ddate) < (tnow - DAY)) { | |
416 dumpme = 1; | |
417 } | |
418 | |
419 if ((arg == 'w') && dumpme) { | |
420 /* | |
421 * Handle the w option: print out file systems | |
422 * which haven't been backed up within a day. | |
423 */ | |
424 (void) printf(gettext("%8s\t(%6s)\n"), | |
425 itwalk->id_name, dt ? dt->mnt_dir : ""); | |
426 } | |
427 if (arg == 'W') { | |
428 /* | |
429 * Handle the W option: print out ALL | |
430 * filesystems including recent dump dates and | |
431 * dump levels. Mark the backup-needing | |
432 * filesystems with a >. | |
433 */ | |
434 (void) printf(gettext( | |
435 "%c %8s\t(%6s) Last dump: Level %c, Date %s\n"), | |
436 dumpme ? '>' : ' ', | |
437 itwalk->id_name, | |
438 dt ? dt->mnt_dir : "", | |
439 (uchar_t)itwalk->id_incno, | |
440 date); | |
441 } | |
442 dumpme = 0; | |
443 } | |
444 } | |
445 } | |
446 | |
447 static int | |
448 idatesort(v1, v2) | |
449 #ifdef __STDC__ | |
450 const void *v1; | |
451 const void *v2; | |
452 #else | |
453 void *v1; | |
454 void *v2; | |
455 #endif | |
456 { | |
457 struct idates **p1 = (struct idates **)v1; | |
458 struct idates **p2 = (struct idates **)v2; | |
459 int diff; | |
460 | |
461 diff = strcoll((*p1)->id_name, (*p2)->id_name); | |
462 if (diff == 0) { | |
463 /* | |
464 * Time may eventually become unsigned, so can't | |
465 * rely on subtraction to give a useful result. | |
466 * Note that we are sorting dates into reverse | |
467 * order, so that we will report based on the | |
468 * most-recent record for a particular filesystem. | |
469 */ | |
470 if ((*p1)->id_ddate > (*p2)->id_ddate) | |
471 diff = -1; | |
472 else if ((*p1)->id_ddate < (*p2)->id_ddate) | |
473 diff = 1; | |
474 } | |
475 return (diff); | |
476 } |