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