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