2 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
32 #include <sys/param.h>
34 #include "fsck_messages.h"
35 #include "fsck_keys.h"
36 #include "fsck_msgnums.h"
38 extern fsck_message_t fsck_messages_common
[];
40 // The following structures are used internally, only
45 struct messages
*next
, *prev
;
51 * The internal verson of fsck_ctx_t -- this describes the output type,
52 * where it goes, etc. It's an opaque type so that it can change size
53 * in the future without affecting any clients of the code.
57 FILE *fp
; // output file structure
58 int flags
; // various flags, mostly private
59 int verb
; // the verbosity of the program -- controls what is output
60 enum fsck_output_type style
;
61 enum fsck_default_answer_type resp
; // none, no, or yes
62 int num
; // number of messages in the array
63 fsck_message_t
**msgs
;
64 void (*writer
)(fsck_ctx_t
, const char*); // write strings to stdout
65 void (*logger
)(fsck_ctx_t
, const char *); // write strings to log file
68 char writeToLog
; // When 1, the string should be written to log file, otherwise to standard out.
69 fsckBlock_t preMessage
;
70 fsckBlock_t postMessage
;
74 * printv(fsck_ctxt_t, const char *, va_list)
75 * Take the format and ap list, and turn them into a string.
76 * Then call the writer to print it out (or do whatever
77 * the writer wants with it, if it's an app-supplised function).
81 printv(fsck_ctx_t c
, const char *fmt
, va_list ap
)
83 struct context
*ctx
= (struct context
*)c
;
90 __va_copy(ap2
, ap
); // Just in case we need it
91 length
= vsnprintf(buf
, BUFSIZ
, fmt
, ap
);
92 if (length
> BUFSIZ
) {
93 // We need to allocate space for it
94 size_t l2
= length
+ 1;
95 char *bufp
= malloc(l2
);
97 strcpy(buf
, "* * * cannot allocate memory * * *\n");
100 length
= vsnprintf(bufp
, length
, fmt
, ap2
);
101 if (length
>= l2
) { // This should not happen!
102 strcpy(buf
, " * * * cannot allocate memory * * *\n");
106 if (ctx
->writer
) (ctx
->writer
)(ctx
, bufp
);
115 // If the current state of printing is logging to file,
116 // call the logger that writes strings only in traditional
117 // output forms. Otherwise, print the strings in the
118 // format option provided by the caller.
119 if (ctx
->writeToLog
== 1) {
120 if (ctx
->logger
) (ctx
->logger
)(ctx
, buf
);
122 if (ctx
->writer
) (ctx
->writer
)(ctx
, buf
);
128 * printargs(fsck_ctx_t, const char *, ...)
129 * An argument-list verison of printv. It simply wraps up
130 * the argument list in a va_list, and then calls printv.
133 printargs(fsck_ctx_t c
, const char *fmt
, ...)
142 * stdprint(fsck_ctx_t, const char *)
143 * Default writer. Just prints to the set FILE*, or stdout
148 stdprint(fsck_ctx_t c
, const char *str
)
150 struct context
*ctx
= (struct context
*)c
;
152 fputs(str
, ctx
->fp
? ctx
->fp
: stdout
);
153 fflush(ctx
->fp
? ctx
->fp
: stdout
);
158 * typestring(int type)
159 * Return a string value corresponding to the type. This is used
160 * to present it during XML output, as one of the appropriate
170 return kfsckInformation
;
179 case fsckMsgDamageInfo
:
180 return kfsckDamageinfo
;
181 case fsckMsgProgress
:
182 return kfsckProgress
;
184 return kfsckInformation
;
191 * verbosity_string(int type)
192 * Return a string value corresponding to the verbosity. This is
193 * used to present it during XML output, as one of the appropriate
197 verbosity_string(int level
)
209 * convertfmt(const char *in)
210 * This is an ugly little function whose job is to convert
211 * from a normal printf-style string (e.g., "How now %s cow?")
212 * into something that can be used with Cocoa formatting. This
213 * means replacing each "%<formatter>" with "%<number>$@"; the
214 * reason we do this is so that the internationalized strings can
215 * move parameters around as desired (e.g., in language A, the third
216 * parameter may need to be first). The caller needs to free the
220 convertfmt(const char *in
)
225 enum { fNone
, fPercent
} fs
;
227 for (cp
= (char*)in
; cp
; cp
= strchr(cp
, '%')) {
232 retval
= calloc(1, strlen(in
) + numargs
* 5 + 1);
238 for (cp
= retval
; *in
; in
++) {
247 cp
+= sprintf(cp
, "%d$@", ++numargs
);
250 } else if (fs
== fPercent
) {
252 case 'd': case 'i': case 'o': case 'u': case 'x': case 'l':
253 case 'X': case 'D': case 'O': case 'U': case 'e':
254 case 'E': case 'f': case 'F': case 'g': case 'G':
255 case 'a': case 'A': case 'c': case 'C': case 's':
256 case 'S': case 'p': case 'n':
268 * Allocates space for an fsck_ctx_t context. It also sets up
269 * the standard message blocks (defined earlier in this file).
270 * It will return NULL in the case of any error.
275 struct context
*rv
= NULL
;
277 rv
= calloc(1, sizeof(*rv
));
281 if (fsckAddMessages(rv
, fsck_messages_common
) == -1) {
285 fsckSetWriter(rv
, &stdprint
);
287 return (fsck_ctx_t
)rv
;
292 * Sets the block to be called for the specific phase -- currently, only
293 * before or after a message is to be printed/logged. The block is copied
297 fsckSetBlock(fsck_ctx_t c
, fsck_block_phase_t phase
, fsckBlock_t bp
)
299 struct context
*ctx
= c
;
302 case fsckPhaseBeforeMessage
:
303 if (ctx
->preMessage
) {
304 Block_release(ctx
->preMessage
);
305 ctx
->preMessage
= NULL
;
308 ctx
->preMessage
= (fsckBlock_t
)Block_copy(bp
);
310 case fsckPhaseAfterMessage
:
311 if (ctx
->postMessage
) {
312 Block_release(ctx
->postMessage
);
313 ctx
->postMessage
= NULL
;
316 ctx
->postMessage
= (fsckBlock_t
)Block_copy(bp
);
319 /* Just here for compiler warnings */
329 * Return the pointer to the block for the specified phase. The block pointer
333 fsckGetBlock(fsck_ctx_t c
, fsck_block_phase_t phase
)
335 struct context
*ctx
= c
;
336 fsckBlock_t retval
= NULL
;
339 case fsckPhaseBeforeMessage
:
340 retval
= ctx
->preMessage
;
342 case fsckPhaseAfterMessage
:
343 retval
= ctx
->postMessage
;
353 * fsckSetWriter(context, void (*)(fsck_ctx_t, const char *)
354 * Call a function for each message to be printed.
355 * This defaults to stdprint (see above).
358 fsckSetWriter(fsck_ctx_t c
, void (*fp
)(fsck_ctx_t
, const char*))
360 struct context
*ctx
= c
;
369 /* Initialize the logger function that will write strings to log file */
371 fsckSetLogger(fsck_ctx_t c
, void (*fp
)(fsck_ctx_t
, const char*))
373 struct context
*ctx
= c
;
383 * fsckSetOutput(context, FILE*)
384 * Set the FILE* to be used for output. Returns
385 * 0 on success, and -1 if it has already been set.
388 fsckSetOutput(fsck_ctx_t c
, FILE *fp
)
390 struct context
*ctx
= c
;
400 * fsckSetFile(context, fd)
401 * Use a file descriptor, instead of a FILE*, for output.
402 * Because of how stdio works, you should not use 1 or 2
403 * for this -- use fsckSetOutput() with stdout/stderr instead.
404 * If you do use this, then fsckDestroy() will close the FILE*
406 * It returns -1 on error, and 0 on success.
409 fsckSetFile(fsck_ctx_t c
, int f
)
411 struct context
*ctx
= c
;
414 FILE *out
= fdopen(f
, "w");
418 ctx
->flags
|= cfFromFD
;
426 * fsckSetVerbosity(context, level)
427 * Sets the verbosity level associated with this context.
428 * This is used to determine which messages are output -- only
429 * messages with a level equal to, or less than, the context's
430 * verbosity level are output.
433 fsckSetVerbosity(fsck_ctx_t c
, int v
)
435 struct context
*ctx
= c
;
445 * fsckGetVerbosity(context)
446 * Return the verbosity level previously set, or -1 on error.
449 fsckGetVerbosity(fsck_ctx_t c
)
451 struct context
*ctx
= c
;
453 return ctx
? ctx
->verb
: -1;
457 * fsckSetOutputStyle(context, output_type)
458 * Set the output style to one of the defined style:
459 * Traditional (normal terminal-output); GUI (the parenthesized
460 * method used previously by DM/DU); and XML (the new plist
461 * format that is the raison d'etre for this code). It does not
462 * (yet) check if the input value is sane.
465 fsckSetOutputStyle(fsck_ctx_t c
, enum fsck_output_type s
)
467 struct context
*ctx
= c
;
477 * fsckGetStyle(context)
478 * Return the output style set for this context, or
479 * fsckOUtputUndefined.
481 enum fsck_output_type
482 fsckGetOutputStyle(fsck_ctx_t c
)
484 struct context
*ctx
= c
;
486 return ctx
? ctx
->style
: fsckOutputUndefined
;
490 * fsckSetDefaultResponse(context, default_answer_tye)
491 * The purpose of this function is to allow fsck to run without
492 * interaction, and have a default answer (yes or no) for any
493 * question that might be presented. See fsckAskPrompt()
496 fsckSetDefaultResponse(fsck_ctx_t c
, enum fsck_default_answer_type r
)
498 struct context
*ctx
= c
;
508 * fsckAskPrompt(context, prompt, ...)
509 * Ask a question of the user, preceded by the given
510 * printf-format prompt. E.g., "CONTINUE? "); the
511 * question mark should be included if you want it
512 * displayed. If a default answer has been set, then
513 * it will be used; otherwise, it will try to get an
514 * answer from the user. Return values are 1 for "yes",
515 * 0 for "no"; -1 for an invalid default; and -2 for error.
518 fsckAskPrompt(fsck_ctx_t c
, const char *prompt
, ...)
520 struct context
*ctx
= c
;
527 va_start(ap
, prompt
);
529 if (ctx
->style
== fsckOutputTraditional
&& ctx
->fp
) {
532 printv(ctx
, prompt
, ap
);
549 resp
= fgetln(stdin
, &len
);
550 if (resp
== NULL
|| len
== 0) {
552 // Only ask so many times...
554 printargs(ctx
, "%s", "\n");
573 printargs(ctx
, "%s", rv
== 0 ? "NO\n" : "YES\n");
593 * fsckDestroy(context)
594 * Finish up with a context, and release any resources
598 fsckDestroy(fsck_ctx_t c
)
600 struct context
*ctx
= c
;
608 if (ctx
->flags
& cfFromFD
) {
611 if (ctx
->preMessage
) {
612 Block_release(ctx
->preMessage
);
614 if (ctx
->postMessage
) {
615 Block_release(ctx
->postMessage
);
623 * msgCompar(void*, void*)
624 * Used by fsckAddMessages() for qsort(). All it does is
625 * compare the message number for two fsck_messages.
628 msgCompar(const void *p1
, const void *p2
)
630 fsck_message_t
*const *k1
= p1
, *const *k2
= p2
;
632 return ((*k1
)->msgnum
- (*k2
)->msgnum
);
636 * fsckAddMessages(context, message*)
637 * Add a block of messages to this context. We do not assume,
638 * or require, that they are in sorted order. This is probably
639 * not the best it could be, becasue first we look through the
640 * block once, counting how many messages there are; then we
641 * allocate extra space for the existing block, and copy in the
642 * messages to it. This means 2 passes through, which isn't ideal
643 * (however, it should be called very infrequently). After that,
644 * we sort the new block, sorting based on the message number.
645 * In the event of failure, it'll return -1.
646 * XXX We make no attempt to ensure that there are not duplicate
650 fsckAddMessages(fsck_ctx_t c
, fsck_message_t
*m
)
652 struct context
*ctx
= c
;
653 fsck_message_t
*ptr
, **new;
656 if (ctx
== NULL
|| m
== NULL
|| m
->msg
== NULL
)
659 for (cnt
= 0, ptr
= m
; ptr
->msg
; ptr
++, cnt
++)
662 new = realloc(ctx
->msgs
, sizeof(fsck_message_t
*) * (ctx
->num
+ cnt
));
667 for (i
= 0; i
< cnt
; i
++) {
668 ctx
->msgs
[i
+ ctx
->num
] = &m
[i
];
672 qsort(ctx
->msgs
, ctx
->num
, sizeof(fsck_message_t
*), msgCompar
);
678 * bCompar(void *, void *)
679 * An fsck_message_t* comparision function for
680 * bsearch(). The first parameter is a pointer to
681 * the message number we're searching for; the second
682 * parameter is a pointer to an fsck_message_t.
683 * bsearch() needs to know whether that message is less than,
684 * equal to, or greater than the desired one.
687 bCompar(const void *kp
, const void *ap
)
690 fsck_message_t
* const *mp
= ap
;
692 return (*ip
- (*mp
)->msgnum
);
696 * findmessage(context, msgnum)
697 * Find the desired message number in the context. It uses
698 * bsearch() and... does very little itself. (An earlier version
701 static fsck_message_t
*
702 findmessage(struct context
*ctx
, int msgnum
)
709 rv
= bsearch(&msgnum
, ctx
->msgs
, ctx
->num
, sizeof(rv
), bCompar
);
718 * fsckPrintToString(message, va_list)
719 * fsckPrintString(context, message, va_list)
720 * These two functions are used to print out a traditional message on the
721 * console. Note that it outputs "** " for the messages
722 * it does print out (Verify, Repair, Success, and Fail);
723 * other messages are not printed out.
725 * fsckPrintToString() is also used for message logging.
729 fsckPrintToString(fsck_message_t
*m
, va_list ap
)
733 char *astr
= ""; // String at beginning
734 char *pstr
= ""; // String at end
736 /* No progress messages required in traditional output */
737 if (m
->type
== fsckMsgProgress
) {
749 case fsckMsgDamageInfo
:
754 pstr
= astr
= " *****";
757 vasprintf(&tmpstr
, m
->msg
, ap
);
759 asprintf(&retval
, "%s%s%s\n", astr
, tmpstr
, pstr
);
766 fsckPrintString(struct context
*ctx
, fsck_message_t
*m
, va_list ap
)
768 // Traditional fsck doesn't print this out
769 if (m
->type
!= fsckMsgProgress
)
771 char *str
= fsckPrintToString(m
, ap
);
773 printargs(ctx
, "%s", str
);
780 static char* escapeCharactersXML(char *input_string
)
782 if (input_string
== NULL
) {
786 char *output_string
= NULL
;
788 // In the worst case, each character of the input_string could be a special character,
789 // Each special character can add at most 5 extra characters to the string.
790 char temp
[MAXPATHLEN
*6 + 1];
791 memset(temp
, 0, MAXPATHLEN
*6 + 1);
793 char *input_ptr
= input_string
;
794 char *temp_ptr
= &temp
[0];
796 while(*input_ptr
!= '\0') {
877 output_string
= strdup((const char *)(&temp
));
878 return output_string
;
882 * fsckPrintXML(context, message, va_list)
883 * Print out a message in XML (well, plist) format.
884 * This involves printint out a standard header and closer
885 * for each message, and calling fflush() when it's done.
888 fsckPrintXML(struct context
*ctx
, fsck_message_t
*m
, va_list ap
)
890 char *newmsg
= convertfmt(m
->msg
);
891 /* See convertfmt() for details */
892 if (newmsg
== NULL
) {
895 printargs(ctx
, "%s", "<plist version=\"1.0\">\n");
896 printargs(ctx
, "%s", "\t<dict>\n");
897 printargs(ctx
, "\t\t<key>%s</key> <string>%s</string>\n",
898 kfsckType
, typestring(m
->type
));
900 * XXX - should be a "cleaner" way of doing this: we only want
901 * to print out these keys if it's NOT a progress indicator.
903 if (m
->msgnum
!= fsckProgress
) {
904 printargs(ctx
, "\t\t<key>%s</key> <integer>%s</integer>\n",
905 kfsckVerbosity
, verbosity_string(m
->level
));
906 printargs(ctx
, "\t\t<key>%s</key> <integer>%u</integer>\n",
907 kfsckMsgNumber
, m
->msgnum
);
908 printargs(ctx
, "\t\t<key>%s</key> <string>%s</string>\n",
909 kfsckMsgString
, newmsg
);
911 if (m
->numargs
> 0) {
914 * Each parameter has a type. This basically boils down to
915 * a string or an integer, but some kinds of strings are
916 * handled specially. Specifically, paths, volume names,
919 printargs(ctx
, "\t\t<key>%s</key>\n", kfsckParams
);
920 printargs(ctx
, "%s", "\t\t<array>\n");
921 for (i
= 0; i
< m
->numargs
; i
++) {
922 if (m
->argtype
[i
] == fsckTypeInt
) {
923 int x
= va_arg(ap
, int);
924 printargs(ctx
, "\t\t\t<integer>%d</integer>\n", x
);
925 } else if (m
->argtype
[i
] == fsckTypeLong
) {
926 long x
= va_arg(ap
, long);
927 printargs(ctx
, "\t\t\t<integer>%ld</integer>\n", x
);
928 } else if (m
->argtype
[i
] == fsckTypeFileSize
) {
929 off_t x
= va_arg(ap
, off_t
);
930 printargs(ctx
, "\t\t\t<integer>%llu</integer>\n", x
);
931 } else if (m
->argtype
[i
] == fsckTypeString
) {
932 char *p
= va_arg(ap
, char*);
933 char *escapedP
= escapeCharactersXML(p
);
934 printargs(ctx
, "\t\t\t<string>%s</string>\n", escapedP
);
936 } else if (m
->argtype
[i
] == fsckTypePath
) {
937 char *p
= va_arg(ap
, char*);
938 char *escapedP
= escapeCharactersXML(p
);
939 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamPathKey
, escapedP
);
941 } else if (m
->argtype
[i
] == fsckTypeFile
) {
942 char *p
= va_arg(ap
, char*);
943 char *escapedP
= escapeCharactersXML(p
);
944 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamFileKey
, escapedP
);
946 } else if (m
->argtype
[i
] == fsckTypeDirectory
) {
947 char *p
= va_arg(ap
, char*);
948 char *escapedP
= escapeCharactersXML(p
);
949 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamDirectoryKey
, escapedP
);
951 } else if (m
->argtype
[i
] == fsckTypeVolume
) {
952 char *p
= va_arg(ap
, char*);
953 char *escapedP
= escapeCharactersXML(p
);
954 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamVolumeKey
, escapedP
);
956 } else if (m
->argtype
[i
] == fsckTypeFSType
) {
957 char *p
= va_arg(ap
, char*);
958 char *escapedP
= escapeCharactersXML(p
);
959 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamFSTypeKey
, escapedP
);
961 } else if (m
->argtype
[i
] == fsckTypeProgress
) {
962 int x
= va_arg(ap
, int);
963 printargs(ctx
, "\t\t\t<integer>%d</integer>\n", x
);
965 /* XXX - what should default be --- string, integer, pointer? */
966 void *p
= va_arg(ap
, void*);
967 printargs(ctx
, "\t\t\t<integer>%p</integer>\n", p
);
970 printargs(ctx
, "%s", "\t\t</array>\n");
972 printargs(ctx
, "%s", "\t</dict>\n");
973 printargs(ctx
, "%s", "</plist>\n");
979 * fsckPrintGUI(context, message, va_list)
980 * Print out a message for the previous interface for DM/DU;
982 * ('X', "message", z)
983 * where 'X' is a type ('S' for success, 'E' for error, and
984 * '%' for progress), and z is an argument count. (Okay,
985 * progress counts are just "(% z)", where "z" is a number
986 * between 0 and 100). If there are any arguments, they follow
990 fsckPrintGUI(struct context
*ctx
, fsck_message_t
*m
, va_list ap
)
994 char *newmsg
= convertfmt(m
->msg
);
1002 case fsckMsgSuccess
:
1007 case fsckMsgDamageInfo
:
1009 case fsckMsgProgress
:
1014 if (m
->msgnum
!= fsckProgress
) {
1015 printargs(ctx
, "(%c,\"%s\",%d)\n", t
, newmsg
, m
->numargs
);
1017 for (i
= 0; i
< m
->numargs
; i
++) {
1018 switch (m
->argtype
[i
]) {
1020 printargs(ctx
, "%d\n", (int)va_arg(ap
, int)); break;
1022 printargs(ctx
, "%ld\n", (long)va_arg(ap
, long)); break;
1023 case fsckTypeFileSize
:
1024 printargs(ctx
, "%llu\n", (off_t
)va_arg(ap
, off_t
)); break;
1025 case fsckTypeProgress
:
1026 printargs(ctx
, "(%d %%)\n", (int)va_arg(ap
, int)); break;
1027 case fsckTypeString
:
1030 case fsckTypeDirectory
:
1031 case fsckTypeVolume
:
1032 case fsckTypeFSType
:
1033 printargs(ctx
, "%s\n", (char*)va_arg(ap
, char*)); break;
1035 printargs(ctx
, "%p\n", (void*)va_arg(ap
, void*)); break;
1043 * fsckPrintNothing(context, message, va_list)
1044 * Don't actually print anything. Used for testing and debugging, nothing
1048 fsckPrintNothing(struct context
*ctx
, fsck_message_t
*m
, va_list ap
)
1054 * fsckPrint(context, msgnum, ...)
1055 * Print out a message identified by msgnum, using the data and
1056 * context information in the contexxt. This will look up the message,
1057 * and then print it out to the requested output stream using the style
1058 * that was selected. It returns 0 on success, and -1 on failure.
1060 * Note: WriteError() and RcdError() call fsckPrint internally, and
1061 * therefore take care of generating the output correctly.
1064 fsckPrint(fsck_ctx_t c
, int m
, ...)
1066 int (*func
)(struct context
*, fsck_message_t
*, va_list);
1067 struct context
*ctx
= c
;
1068 fsck_message_t
*msg
;
1077 msg
= findmessage(ctx
, m
);
1078 assert(msg
!= NULL
);
1080 return -1; // Should log something
1083 switch (ctx
->style
) {
1084 case fsckOutputTraditional
:
1085 func
= fsckPrintString
;
1088 func
= fsckPrintGUI
;
1091 func
= fsckPrintXML
;
1094 func
= fsckPrintNothing
;
1098 if (ctx
->preMessage
) {
1100 fsck_block_status_t rv
;
1102 va_copy(vaBlock
, ap
);
1103 rv
= (ctx
->preMessage
)(c
, m
, vaBlock
);
1104 if (rv
== fsckBlockAbort
) {
1108 if (rv
== fsckBlockIgnore
) {
1114 // Write string in traditional form to log file first
1115 ctx
->writeToLog
= 1;
1117 va_copy(logfile_ap
, ap
);
1118 retval
= fsckPrintString(ctx
, msg
, logfile_ap
);
1119 ctx
->writeToLog
= 0;
1122 // Now write string to standard output now as per caller's specifications
1123 retval
= (*func
)(ctx
, msg
, ap
);
1125 retval
= 0; // NULL fp means don't output anything
1127 if (ctx
->postMessage
) {
1129 fsck_block_status_t rv
;
1131 va_copy(vaBlock
, ap
);
1132 rv
= (ctx
->postMessage
)(c
, m
, vaBlock
);
1133 if (rv
== fsckBlockAbort
) {
1137 if (rv
== fsckBlockIgnore
) {
1148 * fsckMsgClass(context, msgnum)
1149 * Return the message class (Verify, Successs, Failure, etc.)
1150 * for a given message number. If the message number is unknown,
1151 * it returns fsckMsgUnknown.
1154 fsckMsgClass(fsck_ctx_t c
, int msgNum
)
1156 struct context
*ctx
= c
;
1160 return fsckMsgUnknown
;
1162 m
= findmessage(ctx
, msgNum
);
1164 return fsckMsgUnknown
;
1170 * The following section is used to make the internationalizable
1171 * string file; this is a file that contains each message string,
1172 * followed by an '=' and then the string again. This is then doctored
1173 * by the internationalization folks. By putting it in here, this means
1174 * we need to compile the source file (and any others that have the messages
1175 * we care about) specially, and then be run as part of the build process.
1177 #ifdef FSCK_MAKESTRINGS
1179 main(int ac
, char **av
)
1181 fsck_message_t
*msg
;
1182 extern fsck_message_t hfs_errors
[];
1183 extern fsck_message_t hfs_messages
[];
1185 printf("/* Standard messages */\n");
1186 for (msg
= fsck_messages_common
;
1189 char *newstr
= convertfmt(msg
->msg
);
1191 if (newstr
== NULL
) {
1192 printf("\"%s\" = \"%s\";\n", msg
->msg
, msg
->msg
);
1194 printf("\"%s\" = \"%s\";\n", newstr
, newstr
);
1199 printf("\n/* HFS-specific standard messages */\n");
1200 for (msg
= hfs_messages
;
1203 char *newstr
= convertfmt(msg
->msg
);
1205 if (newstr
== NULL
) {
1206 printf("\"%s\" = \"%s\";\n", msg
->msg
, msg
->msg
);
1208 printf("\"%s\" = \"%s\";\n", newstr
, newstr
);
1213 printf("\n/* HFS-specific errors */\n");
1214 for (msg
= hfs_errors
;
1217 char *newstr
= convertfmt(msg
->msg
);
1219 if (newstr
== NULL
) {
1220 printf("\"%s\" = \"%s\";\n", msg
->msg
, msg
->msg
);
1222 printf("\"%s\" = \"%s\";\n", newstr
, newstr
);
1229 #endif /* FSCK_MAKESTRINGS */
1232 * This is used only for testing; it'll take some dumb arguments on
1233 * the command line, and then print out some messages. It tests the
1234 * allocation, initialization, and searching.
1237 main(int ac
, char **av
)
1240 enum fsck_output_type t
= fsckOutputUndefined
;
1241 int (*func
)(fsck_ctx_t
, int, ...);
1244 fctx
= fsckCreate();
1247 if (!strcmp(av
[1], "-g")) {
1249 fsckSetStyle(fctx
, t
);
1250 fsckSetDefaultResponse(fctx
, fsckDefaultYes
);
1251 } else if (!strcmp(av
[1], "-s")) {
1252 t
= fsckOutputTraditional
;
1253 fsckSetStyle(fctx
, t
);
1254 } else if (!strcmp(av
[1], "-x")) {
1256 fsckSetStyle(fctx
, t
);
1257 fsckSetDefaultResponse(fctx
, fsckDefaultYes
);
1261 fsckSetOutput(fctx
, stdout
);
1262 fsckPrint(fctx
, fsckInformation
, "fsck", "version");
1264 i
= fsckAskPrompt(fctx
, "Unknown file %s; remove? [y|n] ", "/tmp/foo");
1266 fprintf(stderr
, "\n\nfile %s is to be removed\n\n", "/tmp/foo");
1268 fsckPrint(fctx
, fsckProgress
, 10);
1269 fsckPrint(fctx
, fsckVolumeNotRepaired
);
1276 #endif /* FSCK_TEST */