]> git.saurik.com Git - apple/hfs.git/blob - fsck_hfs/utilities.c
hfs-305.10.1.tar.gz
[apple/hfs.git] / fsck_hfs / utilities.c
1 /*
2 * Copyright (c) 1999-2000, 2002, 2004, 2007-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright (c) 1980, 1986, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55 #include <stddef.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <sys/errno.h>
59 #include <sys/syslimits.h>
60 #include <pwd.h>
61
62 #include <ctype.h>
63 #include <err.h>
64 #include <stdio.h>
65 #include <string.h>
66 #include <unistd.h>
67 #include <stdlib.h>
68 #include <sys/sysctl.h>
69
70 #include "fsck_hfs.h"
71
72 char *rawname __P((char *name));
73 char *unrawname __P((char *name));
74
75
76 int
77 reply(char *question)
78 {
79 int persevere;
80 char c;
81
82 if (preen)
83 pfatal("INTERNAL ERROR: GOT TO reply()");
84 persevere = !strcmp(question, "CONTINUE");
85 plog("\n");
86 if (!persevere && (nflag || fswritefd < 0)) {
87 plog("%s? no\n\n", question);
88 return (0);
89 }
90 if (yflag || (persevere && nflag)) {
91 plog("%s? yes\n\n", question);
92 return (1);
93 }
94 do {
95 plog("%s? [yn] ", question);
96 (void) fflush(stdout);
97 c = getc(stdin);
98 while (c != '\n' && getc(stdin) != '\n')
99 if (feof(stdin))
100 return (0);
101 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
102 plog("\n");
103 if (c == 'y' || c == 'Y')
104 return (1);
105 return (0);
106 }
107
108
109 void
110 ckfini(markclean)
111 int markclean;
112 {
113 // register struct bufarea *bp, *nbp;
114 // int ofsmodified, cnt = 0;
115
116 (void) CacheDestroy(&fscache);
117
118 if (fswritefd < 0) {
119 (void)close(fsreadfd);
120 return;
121 }
122 #if 0
123 flush(fswritefd, &sblk);
124 if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
125 !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
126 sblk.b_bno = SBOFF / dev_bsize;
127 sbdirty();
128 flush(fswritefd, &sblk);
129 }
130 flush(fswritefd, &cgblk);
131 free(cgblk.b_un.b_buf);
132 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
133 cnt++;
134 flush(fswritefd, bp);
135 nbp = bp->b_prev;
136 free(bp->b_un.b_buf);
137 free((char *)bp);
138 }
139 if (bufhead.b_size != cnt)
140 errx(EEXIT, "Panic: lost %d buffers", bufhead.b_size - cnt);
141 pbp = pdirbp = (struct bufarea *)0;
142 if (markclean && sblock.fs_clean == 0) {
143 sblock.fs_clean = 1;
144 sbdirty();
145 ofsmodified = fsmodified;
146 flush(fswritefd, &sblk);
147 fsmodified = ofsmodified;
148 if (!preen)
149 plog("\n***** FILE SYSTEM MARKED CLEAN *****\n");
150 }
151 if (debug)
152 plog("cache missed %ld of %ld (%d%%)\n", diskreads,
153 totalreads, (int)(diskreads * 100 / totalreads));
154 #endif
155 (void)close(fsreadfd);
156 (void)close(fswritefd);
157 }
158
159
160 char *
161 blockcheck(char *origname)
162 {
163 struct stat stslash, stblock, stchar;
164 char *newname, *raw;
165 int retried = 0;
166
167 hotroot = 0;
168 if (stat("/", &stslash) < 0) {
169 perror("/");
170 plog("Can't stat root\n");
171 return (origname);
172 }
173 newname = origname;
174 retry:
175 if (stat(newname, &stblock) < 0) {
176 perror(newname);
177 plog("Can't stat %s\n", newname);
178 return (origname);
179 }
180 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
181 if (stslash.st_dev == stblock.st_rdev)
182 hotroot++;
183 raw = rawname(newname);
184 if (stat(raw, &stchar) < 0) {
185 perror(raw);
186 plog("Can't stat %s\n", raw);
187 return (origname);
188 }
189 if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
190 return (raw);
191 } else {
192 plog("%s is not a character device\n", raw);
193 return (origname);
194 }
195 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
196 newname = unrawname(newname);
197 retried++;
198 goto retry;
199 }
200 /*
201 * Not a block or character device, just return name and
202 * let the caller decide whether to use it.
203 */
204 return (origname);
205 }
206
207
208 char *
209 rawname(char *name)
210
211 {
212 static char rawbuf[32];
213 char *dp;
214
215 if ((dp = strrchr(name, '/')) == 0)
216 return (0);
217 *dp = 0;
218 (void)strlcpy(rawbuf, name, sizeof(rawbuf));
219 *dp = '/';
220 (void)strlcat(rawbuf, "/r", sizeof(rawbuf));
221 (void)strlcat(rawbuf, &dp[1], sizeof(rawbuf));
222
223 return (rawbuf);
224 }
225
226
227 char *
228 unrawname(char *name)
229 {
230 char *dp;
231 struct stat stb;
232
233 if ((dp = strrchr(name, '/')) == 0)
234 return (name);
235 if (stat(name, &stb) < 0)
236 return (name);
237 if ((stb.st_mode & S_IFMT) != S_IFCHR)
238 return (name);
239 if (dp[1] != 'r')
240 return (name);
241 memmove(&dp[1], &dp[2], strlen(&dp[2]) + 1);
242
243 return (name);
244 }
245
246
247 void
248 catch(sig)
249 int sig;
250 {
251 if (!upgrading)
252 ckfini(0);
253 exit(12);
254 }
255
256
257 //
258 // Logging stuff...
259 //
260 //
261 #include <stdarg.h>
262 #include <pthread.h>
263 #include <time.h>
264
265 #define FSCK_LOG_FILE "/var/log/fsck_hfs.log"
266
267 extern char lflag; // indicates if we're doing a live fsck (defined in fsck_hfs.c)
268 extern char guiControl; // indicates if we're outputting for the gui (defined in fsck_hfs.c)
269
270 FILE *log_file = NULL;
271
272 /* Variables for in-memory log for strings that will be written to log file */
273 char *in_mem_log = NULL;
274 char *cur_in_mem_log = NULL;
275 size_t in_mem_log_size = 0;
276
277 /* Variables for in-memory log for strings that will be printed on standard out */
278 char *in_mem_out = NULL;
279 char *cur_in_mem_out = NULL;
280 size_t in_mem_out_size = 0;
281
282 int live_fsck = 0;
283
284 #define DEFAULT_IN_MEM_SIZE 4096
285
286 static pthread_mutex_t mem_buf_lock = PTHREAD_MUTEX_INITIALIZER;
287 static pthread_cond_t mem_buf_cond;
288
289 static pthread_t printing_thread;
290 static pthread_t logging_thread;
291 static volatile int keep_going = 1;
292
293 #undef fprintf
294 #undef printf
295
296 // prototype
297 void print_to_mem(int type, int mem_type, const char *fmt, const char *str, va_list ap);
298
299 #define DO_VPRINT 1 // types for print_to_mem
300 #define DO_STR 2
301
302 /* Types for mem_type */
303 #define IN_MEM_LOG 1 // in-memory log strings
304 #define IN_MEM_OUT 2 // in-memory stdout strings
305
306 static void *
307 fsck_logging_thread(void *arg)
308 {
309 int copy_amt;
310 char buff[1024], *ptr;
311
312 /* Handle writing to the log file */
313 while(keep_going || cur_in_mem_log != in_mem_log) {
314
315 pthread_mutex_lock(&mem_buf_lock);
316 while (keep_going != 0 && cur_in_mem_log == in_mem_log) {
317 int err;
318
319 err = pthread_cond_wait(&mem_buf_cond, &mem_buf_lock);
320 if (err != 0) {
321 fprintf(stderr, "error %d from cond wait\n", err);
322 break;
323 }
324 }
325
326 copy_amt = (cur_in_mem_log - in_mem_log);
327 if (copy_amt == 0) {
328 pthread_mutex_unlock(&mem_buf_lock);
329 continue;
330 }
331
332 if (copy_amt >= sizeof(buff)) {
333 copy_amt = sizeof(buff) - 1;
334 memcpy(buff, in_mem_log, copy_amt);
335
336 memmove(in_mem_log, &in_mem_log[copy_amt], (cur_in_mem_log - in_mem_log) - copy_amt);
337 cur_in_mem_log -= copy_amt;
338 } else {
339 memcpy(buff, in_mem_log, copy_amt);
340 cur_in_mem_log = in_mem_log;
341 }
342
343 buff[copy_amt] = '\0';
344
345 pthread_mutex_unlock(&mem_buf_lock);
346
347 for(ptr=buff; *ptr; ) {
348 char *start;
349
350 start = ptr;
351 while(*ptr && *ptr != '\n') {
352 ptr++;
353 }
354 if (*ptr == '\n') {
355 *ptr++ = '\0';
356 if (log_file) {
357 fprintf(log_file, "%s: %s\n", cdevname ? cdevname : "UNKNOWN-DEV", start);
358 }
359 } else {
360 if (log_file) {
361 fprintf(log_file, "%s", start);
362 }
363 }
364
365 }
366
367 fflush(stdout);
368 }
369
370 return NULL;
371 }
372
373 static void *
374 fsck_printing_thread(void *arg)
375 {
376 int copy_amt;
377 char buff[1024], *ptr;
378
379 /* Handle writing to the out file */
380 while(keep_going || cur_in_mem_out != in_mem_out) {
381
382 pthread_mutex_lock(&mem_buf_lock);
383 while (keep_going != 0 && cur_in_mem_out == in_mem_out) {
384 int err;
385
386 err = pthread_cond_wait(&mem_buf_cond, &mem_buf_lock);
387 if (err != 0) {
388 fprintf(stderr, "error %d from cond wait\n", err);
389 break;
390 }
391 }
392
393 copy_amt = (cur_in_mem_out - in_mem_out);
394 if (copy_amt == 0) {
395 pthread_mutex_unlock(&mem_buf_lock);
396 continue;
397 }
398
399 if (copy_amt >= sizeof(buff)) {
400 copy_amt = sizeof(buff) - 1;
401 memcpy(buff, in_mem_out, copy_amt);
402
403 memmove(in_mem_out, &in_mem_out[copy_amt], (cur_in_mem_out - in_mem_out) - copy_amt);
404 cur_in_mem_out -= copy_amt;
405 } else {
406 memcpy(buff, in_mem_out, copy_amt);
407 cur_in_mem_out = in_mem_out;
408 }
409
410 buff[copy_amt] = '\0';
411
412 pthread_mutex_unlock(&mem_buf_lock);
413
414 for(ptr=buff; *ptr; ) {
415 char *start;
416
417 start = ptr;
418 while(*ptr && *ptr != '\n') {
419 ptr++;
420 }
421 if (*ptr == '\n') {
422 *ptr++ = '\0';
423 printf("%s\n", start);
424 } else {
425 printf("%s", start);
426 }
427
428 }
429
430 fflush(stdout);
431 }
432
433 return NULL;
434 }
435
436
437 int was_signaled = 0;
438
439 void
440 shutdown_logging(void)
441 {
442 keep_going = 0;
443 time_t t;
444
445 /* Log fsck_hfs check completion time */
446 t = time(NULL);
447 if (in_mem_log) {
448 va_list empty_list = {0};
449 print_to_mem(DO_STR, IN_MEM_LOG, "fsck_hfs completed at %s\n", ctime(&t), empty_list);
450 } else {
451 fprintf(log_file, "%s: fsck_hfs completed at %s\n", cdevname ? cdevname : "UNKNOWN-DEV", ctime(&t));
452 }
453
454 if (was_signaled) {
455 // if we were signaled, we can't really call any of these
456 // functions from the context of a signal handler (which
457 // is how we're called if we don't have a signal handler).
458 // so we have our own signal handler which sets this var
459 // which tells us to just bail out.
460 return;
461 }
462
463 if (log_file && !live_fsck) {
464 fflush(log_file);
465 fclose(log_file);
466 log_file = NULL;
467 } else if ((in_mem_out || in_mem_log) && live_fsck && log_file) {
468 // make sure the printing and logging threads are woken up...
469 pthread_mutex_lock(&mem_buf_lock);
470 pthread_cond_broadcast(&mem_buf_cond);
471 pthread_mutex_unlock(&mem_buf_lock);
472
473 // then wait for them
474 pthread_join(printing_thread, NULL);
475 pthread_join(logging_thread, NULL);
476
477 free(in_mem_out);
478 in_mem_out = cur_in_mem_out = NULL;
479 in_mem_out_size = 0;
480
481 free(in_mem_log);
482 in_mem_log = cur_in_mem_log = NULL;
483 in_mem_log_size = 0;
484
485 if (log_file) {
486 fflush(log_file);
487 fclose(log_file);
488 log_file = NULL;
489 }
490 } else if (in_mem_log) {
491 int ret;
492
493 if (getuid() == 0) {
494 // just in case, flush any pending output
495 fflush(stdout);
496 fflush(stderr);
497
498 //
499 // fork so that the child can wait around until the
500 // root volume is mounted read-write and we can add
501 // our output to the log
502 //
503 ret = fork();
504 } else {
505 // if we're not root we don't need to fork
506 ret = 0;
507 }
508 if (ret == 0) {
509 int i;
510 char *fname = FSCK_LOG_FILE, path[PATH_MAX];
511
512 // Disk Management waits for fsck_hfs' stdout to close rather
513 // than the process death to understand if fsck_hfs has exited
514 // or not. Since we do not use stdout any further, close all
515 // the file descriptors so that Disk Management does not wait
516 // for 60 seconds unnecessarily on read-only boot volumes.
517 fclose(stdout);
518 fclose(stdin);
519 fclose(stderr);
520
521 // non-root will never be able to write to /var/log
522 // so point the file somewhere else.
523 if (getuid() != 0) {
524 struct passwd *pwd;
525 fname = NULL;
526 // each user will get their own log as ~/Library/Logs/fsck_hfs.log
527 pwd = getpwuid(getuid());
528 if (pwd) {
529 snprintf(path, sizeof(path), "%s/Library/Logs/fsck_hfs.log", pwd->pw_dir);
530 fname = &path[0];
531 }
532 }
533
534 for(i=0; i < 60; i++) {
535 log_file = fopen(fname, "a");
536 if (log_file) {
537 fwrite(in_mem_log, cur_in_mem_log - in_mem_log, 1, log_file);
538
539 fflush(log_file);
540 fclose(log_file);
541 log_file = NULL;
542
543 free(in_mem_log);
544 in_mem_log = cur_in_mem_log = NULL;
545 in_mem_log_size = 0;
546
547 break;
548 } else {
549 // hmmm, failed to open the output file so wait
550 // a while only if the fs is read-only and then
551 // try again
552 if (errno == EROFS) {
553 sleep(1);
554 } else {
555 break;
556 }
557 }
558 }
559 }
560 }
561 }
562
563 static void
564 my_sighandler(int sig)
565 {
566 was_signaled = 1;
567 cleanup_fs_fd();
568 exit(sig);
569 }
570
571
572 void
573 setup_logging(void)
574 {
575 static int at_exit_setup = 0;
576 time_t t;
577
578 // if this is set, we don't have to do anything
579 if (at_exit_setup) {
580 return;
581 }
582
583 if (guiControl) {
584 setlinebuf(stdout);
585 setlinebuf(stderr);
586 }
587
588 // our copy of this variable since we may
589 // need to change it to make the right thing
590 // happen for fsck on the root volume.
591 live_fsck = (int)lflag;
592
593 if (log_file == NULL) {
594 log_file = fopen(FSCK_LOG_FILE, "a");
595 if (log_file) {
596 setlinebuf(log_file);
597 } else {
598 //
599 // if we can't open the output file it's either because
600 // we're being run on the root volume during early boot
601 // or we were not run as the root user and so we can't
602 // write to /var/log/fsck_hfs.log. in either case we
603 // turn off "live_fsck" so that the right thing happens
604 // in here with respect to where output goes.
605 //
606 live_fsck = 0;
607 }
608
609 if (!live_fsck && log_file) {
610 t = time(NULL);
611 fprintf(log_file, "\n%s: fsck_hfs started at %s", cdevname ? cdevname : "UNKNOWN-DEV", ctime(&t));
612 fflush(log_file);
613
614 } else if (live_fsck || in_mem_log == NULL || in_mem_out == NULL) {
615 //
616 // hmm, we couldn't open the log file (or it's a
617 // live fsck). let's just squirrel away a copy
618 // of the data in memory and then deal with it
619 // later (or print it out from a separate thread
620 // if we're doing a live fsck).
621 //
622 in_mem_log = (char *)malloc(DEFAULT_IN_MEM_SIZE);
623 in_mem_out = (char *)malloc(DEFAULT_IN_MEM_SIZE);
624 if ((in_mem_log != NULL) && (in_mem_out != NULL)) {
625 in_mem_log_size = DEFAULT_IN_MEM_SIZE;
626 in_mem_log[0] = '\0';
627 cur_in_mem_log = in_mem_log;
628
629 in_mem_out_size = DEFAULT_IN_MEM_SIZE;
630 in_mem_out[0] = '\0';
631 cur_in_mem_out = in_mem_out;
632
633 t = time(NULL);
634 va_list empty_list = {0};
635 print_to_mem(DO_STR, IN_MEM_LOG, "\nfsck_hfs started at %s", ctime(&t), empty_list);
636
637 if (live_fsck && log_file) {
638 pthread_cond_init(&mem_buf_cond, NULL);
639
640 signal(SIGINT, my_sighandler);
641 signal(SIGHUP, my_sighandler);
642 signal(SIGTERM, my_sighandler);
643 signal(SIGQUIT, my_sighandler);
644 signal(SIGBUS, my_sighandler);
645 signal(SIGSEGV, my_sighandler);
646 signal(SIGILL, my_sighandler);
647
648 pthread_create(&printing_thread, NULL, fsck_printing_thread, NULL);
649 pthread_create(&logging_thread, NULL, fsck_logging_thread, NULL);
650
651 }
652 }
653 }
654
655 if (at_exit_setup == 0 && (log_file || in_mem_log || in_mem_out)) {
656 atexit(shutdown_logging);
657 at_exit_setup = 1;
658 }
659 }
660 }
661
662
663 void
664 print_to_mem(int type, int mem_type, const char *fmt, const char *str, va_list ap)
665 {
666 int ret;
667 size_t size_remaining;
668 va_list ap_copy;
669 char *cur_in_mem;
670 char *in_mem_data;
671 size_t in_mem_data_size;
672
673 if (type == DO_VPRINT) {
674 va_copy(ap_copy, ap);
675 }
676
677 if (mem_type == IN_MEM_LOG) {
678 cur_in_mem = cur_in_mem_log;
679 in_mem_data = in_mem_log;
680 in_mem_data_size = in_mem_log_size;
681 } else {
682 cur_in_mem = cur_in_mem_out;
683 in_mem_data = in_mem_out;
684 in_mem_data_size = in_mem_out_size;
685 }
686
687 /* Grab the lock only when adding output strings to the in-memory data */
688 if (live_fsck && (mem_type == IN_MEM_OUT)) {
689 pthread_mutex_lock(&mem_buf_lock);
690 }
691
692 size_remaining = in_mem_data_size - (ptrdiff_t)(cur_in_mem - in_mem_data);
693 if (type == DO_VPRINT) {
694 ret = vsnprintf(cur_in_mem, size_remaining, fmt, ap);
695 } else {
696 ret = snprintf(cur_in_mem, size_remaining, fmt, str);
697 }
698 if (ret > size_remaining) {
699 char *new_log;
700 size_t amt;
701
702 if (ret >= DEFAULT_IN_MEM_SIZE) {
703 amt = (ret + 4095) & (~4095); // round up to a 4k boundary
704 } else {
705 amt = DEFAULT_IN_MEM_SIZE;
706 }
707
708 new_log = realloc(in_mem_data, in_mem_data_size + amt);
709 if (new_log == NULL) {
710 if (live_fsck && (mem_type == IN_MEM_OUT)) {
711 pthread_cond_signal(&mem_buf_cond);
712 pthread_mutex_unlock(&mem_buf_lock);
713 }
714 goto done;
715 }
716
717 in_mem_data_size += amt;
718 cur_in_mem = new_log + (cur_in_mem - in_mem_data);
719 in_mem_data = new_log;
720 size_remaining = in_mem_data_size - (ptrdiff_t)(cur_in_mem - new_log);
721 if (type == DO_VPRINT) {
722 ret = vsnprintf(cur_in_mem, size_remaining, fmt, ap_copy);
723 } else {
724 ret = snprintf(cur_in_mem, size_remaining, fmt, str);
725 }
726 if (ret <= size_remaining) {
727 cur_in_mem += ret;
728 }
729 } else {
730 cur_in_mem += ret;
731 }
732
733 if (live_fsck && (mem_type == IN_MEM_OUT)) {
734 pthread_cond_signal(&mem_buf_cond);
735 pthread_mutex_unlock(&mem_buf_lock);
736 }
737
738 done:
739
740 if (mem_type == IN_MEM_LOG) {
741 cur_in_mem_log = cur_in_mem;
742 in_mem_log = in_mem_data;
743 in_mem_log_size = in_mem_data_size;
744 } else {
745 cur_in_mem_out = cur_in_mem;
746 in_mem_out = in_mem_data;
747 in_mem_out_size = in_mem_data_size;
748 }
749
750 if (type == DO_VPRINT) {
751 va_end(ap_copy);
752 }
753 }
754
755
756 static int need_prefix=1;
757
758 #define LOG_PREFIX \
759 if (need_prefix) { \
760 fprintf(log_file, "%s: ", cdevname); \
761 if (strchr(fmt, '\n')) { \
762 need_prefix = 1; \
763 } else { \
764 need_prefix = 0; \
765 } \
766 } else if (strchr(fmt, '\n')) { \
767 need_prefix = 1; \
768 }
769
770 /* Print output string on given stream or store it into in-memory buffer */
771 #define VOUT(stream, fmt, ap) \
772 if (!live_fsck) { \
773 vfprintf(stream, fmt, ap); \
774 } else { \
775 print_to_mem(DO_VPRINT, IN_MEM_OUT, fmt, NULL, ap); \
776 }
777
778 #define FOUT(fmt, str) \
779 print_to_mem(DO_STR, IN_MEM_OUT, fmt, str, NULL);
780
781 /* Store output string written to fsck_hfs.log into file or in-memory buffer */
782 #define VLOG(fmt, ap) \
783 va_start(ap, fmt); \
784 VLOG_INTERNAL(fmt, ap);
785
786 #define VLOG_INTERNAL(fmt, ap) \
787 if (log_file && !live_fsck) { \
788 LOG_PREFIX \
789 vfprintf(log_file, fmt, ap); \
790 } else { \
791 print_to_mem(DO_VPRINT, IN_MEM_LOG, fmt, NULL, ap); \
792 }
793
794 #define FLOG(fmt, str) \
795 if (log_file && !live_fsck) { \
796 LOG_PREFIX; \
797 fprintf(log_file, fmt, str); \
798 } else { \
799 va_list empty_list = {0}; \
800 print_to_mem(DO_STR, IN_MEM_LOG, fmt, str, empty_list); \
801 }
802
803
804 #if __STDC__
805 #include <stdarg.h>
806 #else
807 #include <varargs.h>
808 #endif
809
810 /*
811 * An unexpected inconsistency occurred.
812 * Die if preening, otherwise just print message and continue.
813 */
814 void
815 #if __STDC__
816 pfatal(const char *fmt, ...)
817 #else
818 pfatal(fmt, va_alist)
819 char *fmt;
820 va_dcl
821 #endif
822 {
823 va_list ap;
824
825 setup_logging();
826
827 #if __STDC__
828 va_start(ap, fmt);
829 #else
830 va_start(ap);
831 #endif
832 if (!preen) {
833 (void)vfprintf(stderr, fmt, ap);
834 VLOG(fmt, ap);
835 va_end(ap);
836 return;
837 }
838 if (!live_fsck)
839 (void)fprintf(stderr, "%s: ", cdevname);
840 FLOG("%s: ", cdevname);
841
842 if (!live_fsck)
843 (void)vfprintf(stderr, fmt, ap);
844 VLOG(fmt, ap);
845
846 if (!live_fsck)
847 (void)fprintf(stderr,
848 "\n%s: UNEXPECTED INCONSISTENCY; RUN fsck_hfs MANUALLY.\n",
849 cdevname);
850 FLOG("\n%s: UNEXPECTED INCONSISTENCY; RUN fsck_hfs MANUALLY.\n", cdevname);
851
852 exit(EEXIT);
853 }
854
855 /*
856 * Pwarn just prints a message when not preening,
857 * or a warning (preceded by filename) when preening.
858 */
859 void
860 #if __STDC__
861 pwarn(const char *fmt, ...)
862 #else
863 pwarn(fmt, va_alist)
864 char *fmt;
865 va_dcl
866 #endif
867 {
868 va_list ap;
869
870 setup_logging();
871
872 #if __STDC__
873 va_start(ap, fmt);
874 #else
875 va_start(ap);
876 #endif
877 if (preen) {
878 (void)fprintf(stderr, "%s: ", cdevname);
879 FLOG("%s: ", cdevname);
880 }
881 if (!live_fsck)
882 (void)vfprintf(stderr, fmt, ap);
883 VLOG(fmt, ap);
884
885 va_end(ap);
886 }
887
888 /* Write a string and parameters, if any, directly to the log file.
889 * These strings will not be printed to standard out/error.
890 */
891 void
892 logstring(void *c, const char *str)
893 {
894 llog("%s", str);
895 }
896
897 /* Write a string and parameters, if any, directly to standard out/error.
898 * These strings will not be printed to log file.
899 */
900 void
901 outstring(void *c, const char *str)
902 {
903 olog("%s", str);
904 }
905
906 /* Write to both standard out and log file */
907 void
908 plog(const char *fmt, ...)
909 {
910 va_list ap;
911 va_start(ap, fmt);
912 vplog(fmt, ap);
913 va_end(ap);
914 }
915
916 /* Write to only standard out */
917 void
918 olog(const char *fmt, ...)
919 {
920 va_list ap;
921 va_start(ap, fmt);
922
923 setup_logging();
924
925 /* For live fsck_hfs, add output strings to in-memory log,
926 * and for non-live fsck_hfs, print output to stdout.
927 */
928 VOUT(stdout, fmt, ap);
929
930 va_end(ap);
931 }
932
933 /* Write to only log file */
934 void
935 llog(const char *fmt, ...)
936 {
937 va_list ap;
938 va_start(ap, fmt);
939
940 setup_logging();
941 need_prefix = 1;
942 VLOG(fmt, ap);
943
944 va_end(ap);
945 }
946
947 /* Write to both standard out and log file */
948 void
949 vplog(const char *fmt, va_list ap)
950 {
951 va_list copy_ap;
952
953 va_copy(copy_ap, ap);
954
955 setup_logging();
956
957 /* Always print prefix to strings written to log files */
958 need_prefix = 1;
959
960 /* Handle output strings, print to stdout or store in-memory */
961 VOUT(stdout, fmt, ap);
962
963 /* Add log strings to the log file. VLOG() handles live case internally */
964 VLOG_INTERNAL(fmt, copy_ap);
965 }
966
967 /* Write to both standard out and log file */
968 void
969 fplog(FILE *stream, const char *fmt, ...)
970 {
971 va_list ap, copy_ap;
972 va_start(ap, fmt);
973 va_copy(copy_ap, ap);
974
975 setup_logging();
976 need_prefix = 1;
977
978 /* Handle output strings, print to given stream or store in-memory */
979 VOUT(stream, fmt, ap);
980
981 /* Add log strings to the log file. VLOG() handles live case internally */
982 VLOG(fmt, copy_ap);
983
984 va_end(ap);
985 }
986
987 #define kProgressToggle "kern.progressmeterenable"
988 #define kProgress "kern.progressmeter"
989
990 void
991 start_progress(void)
992 {
993 int rv;
994 int enable = 1;
995 if (hotroot == 0)
996 return;
997 rv = sysctlbyname(kProgressToggle, NULL, NULL, &enable, sizeof(enable));
998 if (debug && rv == -1 && errno != ENOENT) {
999 warn("sysctl(%s) failed", kProgressToggle);
1000 }
1001 }
1002
1003 void
1004 draw_progress(int pct)
1005 {
1006 int rv;
1007 if (hotroot == 0)
1008 return;
1009 rv = sysctlbyname(kProgress, NULL, NULL, &pct, sizeof(pct));
1010 if (debug && rv == -1 && errno != ENOENT) {
1011 warn("sysctl(%s) failed", kProgress);
1012 }
1013 }
1014
1015 void
1016 end_progress(void)
1017 {
1018 int rv;
1019 int enable = 0;
1020 if (hotroot == 0)
1021 return;
1022 rv = sysctlbyname(kProgressToggle, NULL, NULL, &enable, sizeof(enable));
1023 if (debug && rv == -1 && errno != ENOENT) {
1024 warn("sysctl(%s) failed", kProgressToggle);
1025 }
1026 }
1027