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