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@
33 #include "fsck_messages.h"
34 #include "fsck_keys.h"
35 #include "fsck_msgnums.h"
37 extern fsck_message_t fsck_messages_common
[];
39 // The following structures are used internally, only
44 struct messages
*next
, *prev
;
50 * The internal verson of fsck_ctx_t -- this describes the output type,
51 * where it goes, etc. It's an opaque type so that it can change size
52 * in the future without affecting any clients of the code.
56 FILE *fp
; // output file structure
57 int flags
; // various flags, mostly private
58 int verb
; // the verbosity of the program -- controls what is output
59 enum fsck_output_type style
;
60 enum fsck_default_answer_type resp
; // none, no, or yes
61 int num
; // number of messages in the array
62 fsck_message_t
**msgs
;
63 void (*writer
)(fsck_ctx_t
, const char*); // write strings to stdout
64 void (*logger
)(fsck_ctx_t
, const char *); // write strings to log file
67 char writeToLog
; // When 1, the string should be written to log file, otherwise to standard out.
68 fsckBlock_t preMessage
;
69 fsckBlock_t postMessage
;
73 * printv(fsck_ctxt_t, const char *, va_list)
74 * Take the format and ap list, and turn them into a string.
75 * Then call the writer to print it out (or do whatever
76 * the writer wants with it, if it's an app-supplised function).
80 printv(fsck_ctx_t c
, const char *fmt
, va_list ap
)
82 struct context
*ctx
= (struct context
*)c
;
89 __va_copy(ap2
, ap
); // Just in case we need it
90 length
= vsnprintf(buf
, BUFSIZ
, fmt
, ap
);
91 if (length
> BUFSIZ
) {
92 // We need to allocate space for it
93 size_t l2
= length
+ 1;
94 char *bufp
= malloc(l2
);
96 strcpy(buf
, "* * * cannot allocate memory * * *\n");
99 length
= vsnprintf(bufp
, length
, fmt
, ap2
);
100 if (length
>= l2
) { // This should not happen!
101 strcpy(buf
, " * * * cannot allocate memory * * *\n");
105 if (ctx
->writer
) (ctx
->writer
)(ctx
, bufp
);
114 // If the current state of printing is logging to file,
115 // call the logger that writes strings only in traditional
116 // output forms. Otherwise, print the strings in the
117 // format option provided by the caller.
118 if (ctx
->writeToLog
== 1) {
119 if (ctx
->logger
) (ctx
->logger
)(ctx
, buf
);
121 if (ctx
->writer
) (ctx
->writer
)(ctx
, buf
);
127 * printargs(fsck_ctx_t, const char *, ...)
128 * An argument-list verison of printv. It simply wraps up
129 * the argument list in a va_list, and then calls printv.
132 printargs(fsck_ctx_t c
, const char *fmt
, ...)
141 * stdprint(fsck_ctx_t, const char *)
142 * Default writer. Just prints to the set FILE*, or stdout
147 stdprint(fsck_ctx_t c
, const char *str
)
149 struct context
*ctx
= (struct context
*)c
;
151 fputs(str
, ctx
->fp
? ctx
->fp
: stdout
);
152 fflush(ctx
->fp
? ctx
->fp
: stdout
);
157 * typestring(int type)
158 * Return a string value corresponding to the type. This is used
159 * to present it during XML output, as one of the appropriate
169 return kfsckInformation
;
178 case fsckMsgDamageInfo
:
179 return kfsckDamageinfo
;
180 case fsckMsgProgress
:
181 return kfsckProgress
;
183 return kfsckInformation
;
190 * verbosity_string(int type)
191 * Return a string value corresponding to the verbosity. This is
192 * used to present it during XML output, as one of the appropriate
196 verbosity_string(int level
)
208 * convertfmt(const char *in)
209 * This is an ugly little function whose job is to convert
210 * from a normal printf-style string (e.g., "How now %s cow?")
211 * into something that can be used with Cocoa formatting. This
212 * means replacing each "%<formatter>" with "%<number>$@"; the
213 * reason we do this is so that the internationalized strings can
214 * move parameters around as desired (e.g., in language A, the third
215 * parameter may need to be first). The caller needs to free the
219 convertfmt(const char *in
)
224 enum { fNone
, fPercent
} fs
;
226 for (cp
= (char*)in
; cp
; cp
= strchr(cp
, '%')) {
231 retval
= calloc(1, strlen(in
) + numargs
* 5 + 1);
237 for (cp
= retval
; *in
; in
++) {
246 cp
+= sprintf(cp
, "%d$@", ++numargs
);
249 } else if (fs
== fPercent
) {
251 case 'd': case 'i': case 'o': case 'u': case 'x': case 'l':
252 case 'X': case 'D': case 'O': case 'U': case 'e':
253 case 'E': case 'f': case 'F': case 'g': case 'G':
254 case 'a': case 'A': case 'c': case 'C': case 's':
255 case 'S': case 'p': case 'n':
267 * Allocates space for an fsck_ctx_t context. It also sets up
268 * the standard message blocks (defined earlier in this file).
269 * It will return NULL in the case of any error.
274 struct context
*rv
= NULL
;
276 rv
= calloc(1, sizeof(*rv
));
280 if (fsckAddMessages(rv
, fsck_messages_common
) == -1) {
284 fsckSetWriter(rv
, &stdprint
);
286 return (fsck_ctx_t
)rv
;
291 * Sets the block to be called for the specific phase -- currently, only
292 * before or after a message is to be printed/logged. The block is copied
296 fsckSetBlock(fsck_ctx_t c
, fsck_block_phase_t phase
, fsckBlock_t bp
)
298 struct context
*ctx
= c
;
301 case fsckPhaseBeforeMessage
:
302 if (ctx
->preMessage
) {
303 Block_release(ctx
->preMessage
);
304 ctx
->preMessage
= NULL
;
307 ctx
->preMessage
= (fsckBlock_t
)Block_copy(bp
);
309 case fsckPhaseAfterMessage
:
310 if (ctx
->postMessage
) {
311 Block_release(ctx
->postMessage
);
312 ctx
->postMessage
= NULL
;
315 ctx
->postMessage
= (fsckBlock_t
)Block_copy(bp
);
318 /* Just here for compiler warnings */
328 * Return the pointer to the block for the specified phase. The block pointer
332 fsckGetBlock(fsck_ctx_t c
, fsck_block_phase_t phase
)
334 struct context
*ctx
= c
;
335 fsckBlock_t retval
= NULL
;
338 case fsckPhaseBeforeMessage
:
339 retval
= ctx
->preMessage
;
341 case fsckPhaseAfterMessage
:
342 retval
= ctx
->postMessage
;
352 * fsckSetWriter(context, void (*)(fsck_ctx_t, const char *)
353 * Call a function for each message to be printed.
354 * This defaults to stdprint (see above).
357 fsckSetWriter(fsck_ctx_t c
, void (*fp
)(fsck_ctx_t
, const char*))
359 struct context
*ctx
= c
;
368 /* Initialize the logger function that will write strings to log file */
370 fsckSetLogger(fsck_ctx_t c
, void (*fp
)(fsck_ctx_t
, const char*))
372 struct context
*ctx
= c
;
382 * fsckSetOutput(context, FILE*)
383 * Set the FILE* to be used for output. Returns
384 * 0 on success, and -1 if it has already been set.
387 fsckSetOutput(fsck_ctx_t c
, FILE *fp
)
389 struct context
*ctx
= c
;
399 * fsckSetFile(context, fd)
400 * Use a file descriptor, instead of a FILE*, for output.
401 * Because of how stdio works, you should not use 1 or 2
402 * for this -- use fsckSetOutput() with stdout/stderr instead.
403 * If you do use this, then fsckDestroy() will close the FILE*
405 * It returns -1 on error, and 0 on success.
408 fsckSetFile(fsck_ctx_t c
, int f
)
410 struct context
*ctx
= c
;
413 FILE *out
= fdopen(f
, "w");
417 ctx
->flags
|= cfFromFD
;
425 * fsckSetVerbosity(context, level)
426 * Sets the verbosity level associated with this context.
427 * This is used to determine which messages are output -- only
428 * messages with a level equal to, or less than, the context's
429 * verbosity level are output.
432 fsckSetVerbosity(fsck_ctx_t c
, int v
)
434 struct context
*ctx
= c
;
444 * fsckGetVerbosity(context)
445 * Return the verbosity level previously set, or -1 on error.
448 fsckGetVerbosity(fsck_ctx_t c
)
450 struct context
*ctx
= c
;
452 return ctx
? ctx
->verb
: -1;
456 * fsckSetOutputStyle(context, output_type)
457 * Set the output style to one of the defined style:
458 * Traditional (normal terminal-output); GUI (the parenthesized
459 * method used previously by DM/DU); and XML (the new plist
460 * format that is the raison d'etre for this code). It does not
461 * (yet) check if the input value is sane.
464 fsckSetOutputStyle(fsck_ctx_t c
, enum fsck_output_type s
)
466 struct context
*ctx
= c
;
476 * fsckGetStyle(context)
477 * Return the output style set for this context, or
478 * fsckOUtputUndefined.
480 enum fsck_output_type
481 fsckGetOutputStyle(fsck_ctx_t c
)
483 struct context
*ctx
= c
;
485 return ctx
? ctx
->style
: fsckOutputUndefined
;
489 * fsckSetDefaultResponse(context, default_answer_tye)
490 * The purpose of this function is to allow fsck to run without
491 * interaction, and have a default answer (yes or no) for any
492 * question that might be presented. See fsckAskPrompt()
495 fsckSetDefaultResponse(fsck_ctx_t c
, enum fsck_default_answer_type r
)
497 struct context
*ctx
= c
;
507 * fsckAskPrompt(context, prompt, ...)
508 * Ask a question of the user, preceded by the given
509 * printf-format prompt. E.g., "CONTINUE? "); the
510 * question mark should be included if you want it
511 * displayed. If a default answer has been set, then
512 * it will be used; otherwise, it will try to get an
513 * answer from the user. Return values are 1 for "yes",
514 * 0 for "no"; -1 for an invalid default; and -2 for error.
517 fsckAskPrompt(fsck_ctx_t c
, const char *prompt
, ...)
519 struct context
*ctx
= c
;
526 va_start(ap
, prompt
);
528 if (ctx
->style
== fsckOutputTraditional
&& ctx
->fp
) {
531 printv(ctx
, prompt
, ap
);
548 resp
= fgetln(stdin
, &len
);
549 if (resp
== NULL
|| len
== 0) {
551 // Only ask so many times...
553 printargs(ctx
, "%s", "\n");
572 printargs(ctx
, "%s", rv
== 0 ? "NO\n" : "YES\n");
592 * fsckDestroy(context)
593 * Finish up with a context, and release any resources
597 fsckDestroy(fsck_ctx_t c
)
599 struct context
*ctx
= c
;
607 if (ctx
->flags
& cfFromFD
) {
610 if (ctx
->preMessage
) {
611 Block_release(ctx
->preMessage
);
613 if (ctx
->postMessage
) {
614 Block_release(ctx
->postMessage
);
622 * msgCompar(void*, void*)
623 * Used by fsckAddMessages() for qsort(). All it does is
624 * compare the message number for two fsck_messages.
627 msgCompar(const void *p1
, const void *p2
)
629 fsck_message_t
*const *k1
= p1
, *const *k2
= p2
;
631 return ((*k1
)->msgnum
- (*k2
)->msgnum
);
635 * fsckAddMessages(context, message*)
636 * Add a block of messages to this context. We do not assume,
637 * or require, that they are in sorted order. This is probably
638 * not the best it could be, becasue first we look through the
639 * block once, counting how many messages there are; then we
640 * allocate extra space for the existing block, and copy in the
641 * messages to it. This means 2 passes through, which isn't ideal
642 * (however, it should be called very infrequently). After that,
643 * we sort the new block, sorting based on the message number.
644 * In the event of failure, it'll return -1.
645 * XXX We make no attempt to ensure that there are not duplicate
649 fsckAddMessages(fsck_ctx_t c
, fsck_message_t
*m
)
651 struct context
*ctx
= c
;
652 fsck_message_t
*ptr
, **new;
655 if (ctx
== NULL
|| m
== NULL
|| m
->msg
== NULL
)
658 for (cnt
= 0, ptr
= m
; ptr
->msg
; ptr
++, cnt
++)
661 new = realloc(ctx
->msgs
, sizeof(fsck_message_t
*) * (ctx
->num
+ cnt
));
666 for (i
= 0; i
< cnt
; i
++) {
667 ctx
->msgs
[i
+ ctx
->num
] = &m
[i
];
671 qsort(ctx
->msgs
, ctx
->num
, sizeof(fsck_message_t
*), msgCompar
);
677 * bCompar(void *, void *)
678 * An fsck_message_t* comparision function for
679 * bsearch(). The first parameter is a pointer to
680 * the message number we're searching for; the second
681 * parameter is a pointer to an fsck_message_t.
682 * bsearch() needs to know whether that message is less than,
683 * equal to, or greater than the desired one.
686 bCompar(const void *kp
, const void *ap
)
689 fsck_message_t
* const *mp
= ap
;
691 return (*ip
- (*mp
)->msgnum
);
695 * findmessage(context, msgnum)
696 * Find the desired message number in the context. It uses
697 * bsearch() and... does very little itself. (An earlier version
700 static fsck_message_t
*
701 findmessage(struct context
*ctx
, int msgnum
)
708 rv
= bsearch(&msgnum
, ctx
->msgs
, ctx
->num
, sizeof(rv
), bCompar
);
717 * fsckPrintToString(message, va_list)
718 * fsckPrintString(context, message, va_list)
719 * These two functions are used to print out a traditional message on the
720 * console. Note that it outputs "** " for the messages
721 * it does print out (Verify, Repair, Success, and Fail);
722 * other messages are not printed out.
724 * fsckPrintToString() is also used for message logging.
728 fsckPrintToString(fsck_message_t
*m
, va_list ap
)
732 char *astr
= ""; // String at beginning
733 char *pstr
= ""; // String at end
735 /* No progress messages required in traditional output */
736 if (m
->type
== fsckMsgProgress
) {
748 case fsckMsgDamageInfo
:
753 pstr
= astr
= " *****";
756 vasprintf(&tmpstr
, m
->msg
, ap
);
758 asprintf(&retval
, "%s%s%s\n", astr
, tmpstr
, pstr
);
765 fsckPrintString(struct context
*ctx
, fsck_message_t
*m
, va_list ap
)
767 // Traditional fsck doesn't print this out
768 if (m
->type
!= fsckMsgProgress
)
770 char *str
= fsckPrintToString(m
, ap
);
772 printargs(ctx
, "%s", str
);
780 * fsckPrintXML(context, message, va_list)
781 * Print out a message in XML (well, plist) format.
782 * This involves printint out a standard header and closer
783 * for each message, and calling fflush() when it's done.
786 fsckPrintXML(struct context
*ctx
, fsck_message_t
*m
, va_list ap
)
788 char *newmsg
= convertfmt(m
->msg
);
789 /* See convertfmt() for details */
790 if (newmsg
== NULL
) {
793 printargs(ctx
, "%s", "<plist version=\"1.0\">\n");
794 printargs(ctx
, "%s", "\t<dict>\n");
795 printargs(ctx
, "\t\t<key>%s</key> <string>%s</string>\n",
796 kfsckType
, typestring(m
->type
));
798 * XXX - should be a "cleaner" way of doing this: we only want
799 * to print out these keys if it's NOT a progress indicator.
801 if (m
->msgnum
!= fsckProgress
) {
802 printargs(ctx
, "\t\t<key>%s</key> <integer>%s</integer>\n",
803 kfsckVerbosity
, verbosity_string(m
->level
));
804 printargs(ctx
, "\t\t<key>%s</key> <integer>%u</integer>\n",
805 kfsckMsgNumber
, m
->msgnum
);
806 printargs(ctx
, "\t\t<key>%s</key> <string>%s</string>\n",
807 kfsckMsgString
, newmsg
);
809 if (m
->numargs
> 0) {
812 * Each parameter has a type. This basically boils down to
813 * a string or an integer, but some kinds of strings are
814 * handled specially. Specifically, paths, volume names,
817 printargs(ctx
, "\t\t<key>%s</key>\n", kfsckParams
);
818 printargs(ctx
, "%s", "\t\t<array>\n");
819 for (i
= 0; i
< m
->numargs
; i
++) {
820 if (m
->argtype
[i
] == fsckTypeInt
) {
821 int x
= va_arg(ap
, int);
822 printargs(ctx
, "\t\t\t<integer>%d</integer>\n", x
);
823 } else if (m
->argtype
[i
] == fsckTypeLong
) {
824 long x
= va_arg(ap
, long);
825 printargs(ctx
, "\t\t\t<integer>%ld</integer>\n", x
);
826 } else if (m
->argtype
[i
] == fsckTypeFileSize
) {
827 off_t x
= va_arg(ap
, off_t
);
828 printargs(ctx
, "\t\t\t<integer>%llu</integer>\n", x
);
829 } else if (m
->argtype
[i
] == fsckTypeString
) {
830 char *p
= va_arg(ap
, char*);
831 printargs(ctx
, "\t\t\t<string>%s</string>\n", p
);
832 } else if (m
->argtype
[i
] == fsckTypePath
) {
833 char *p
= va_arg(ap
, char*);
834 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamPathKey
, p
);
835 } else if (m
->argtype
[i
] == fsckTypeFile
) {
836 char *p
= va_arg(ap
, char*);
837 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamFileKey
, p
);
838 } else if (m
->argtype
[i
] == fsckTypeDirectory
) {
839 char *p
= va_arg(ap
, char*);
840 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamDirectoryKey
, p
);
841 } else if (m
->argtype
[i
] == fsckTypeVolume
) {
842 char *p
= va_arg(ap
, char*);
843 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamVolumeKey
, p
);
844 } else if (m
->argtype
[i
] == fsckTypeFSType
) {
845 char *p
= va_arg(ap
, char*);
846 printargs(ctx
, "\t\t\t<dict><key>%s</key> <string>%s</string></dict>\n", kfsckParamFSTypeKey
, p
);
847 } else if (m
->argtype
[i
] == fsckTypeProgress
) {
848 int x
= va_arg(ap
, int);
849 printargs(ctx
, "\t\t\t<integer>%d</integer>\n", x
);
851 /* XXX - what should default be --- string, integer, pointer? */
852 void *p
= va_arg(ap
, void*);
853 printargs(ctx
, "\t\t\t<integer>%p</integer>\n", p
);
856 printargs(ctx
, "%s", "\t\t</array>\n");
858 printargs(ctx
, "%s", "\t</dict>\n");
859 printargs(ctx
, "%s", "</plist>\n");
865 * fsckPrintGUI(context, message, va_list)
866 * Print out a message for the previous interface for DM/DU;
868 * ('X', "message", z)
869 * where 'X' is a type ('S' for success, 'E' for error, and
870 * '%' for progress), and z is an argument count. (Okay,
871 * progress counts are just "(% z)", where "z" is a number
872 * between 0 and 100). If there are any arguments, they follow
876 fsckPrintGUI(struct context
*ctx
, fsck_message_t
*m
, va_list ap
)
880 char *newmsg
= convertfmt(m
->msg
);
893 case fsckMsgDamageInfo
:
895 case fsckMsgProgress
:
900 if (m
->msgnum
!= fsckProgress
) {
901 printargs(ctx
, "(%c,\"%s\",%d)\n", t
, newmsg
, m
->numargs
);
903 for (i
= 0; i
< m
->numargs
; i
++) {
904 switch (m
->argtype
[i
]) {
906 printargs(ctx
, "%d\n", (int)va_arg(ap
, int)); break;
908 printargs(ctx
, "%ld\n", (long)va_arg(ap
, long)); break;
909 case fsckTypeFileSize
:
910 printargs(ctx
, "%llu\n", (off_t
)va_arg(ap
, off_t
)); break;
911 case fsckTypeProgress
:
912 printargs(ctx
, "(%d %%)\n", (int)va_arg(ap
, int)); break;
916 case fsckTypeDirectory
:
919 printargs(ctx
, "%s\n", (char*)va_arg(ap
, char*)); break;
921 printargs(ctx
, "%p\n", (void*)va_arg(ap
, void*)); break;
929 * fsckPrintNothing(context, message, va_list)
930 * Don't actually print anything. Used for testing and debugging, nothing
934 fsckPrintNothing(struct context
*ctx
, fsck_message_t
*m
, va_list ap
)
940 * fsckPrint(context, msgnum, ...)
941 * Print out a message identified by msgnum, using the data and
942 * context information in the contexxt. This will look up the message,
943 * and then print it out to the requested output stream using the style
944 * that was selected. It returns 0 on success, and -1 on failure.
946 * Note: WriteError() and RcdError() call fsckPrint internally, and
947 * therefore take care of generating the output correctly.
950 fsckPrint(fsck_ctx_t c
, int m
, ...)
952 int (*func
)(struct context
*, fsck_message_t
*, va_list);
953 struct context
*ctx
= c
;
963 msg
= findmessage(ctx
, m
);
966 return -1; // Should log something
969 switch (ctx
->style
) {
970 case fsckOutputTraditional
:
971 func
= fsckPrintString
;
980 func
= fsckPrintNothing
;
984 if (ctx
->preMessage
) {
986 fsck_block_status_t rv
;
988 va_copy(vaBlock
, ap
);
989 rv
= (ctx
->preMessage
)(c
, m
, vaBlock
);
990 if (rv
== fsckBlockAbort
) {
994 if (rv
== fsckBlockIgnore
) {
1000 // Write string in traditional form to log file first
1001 ctx
->writeToLog
= 1;
1003 va_copy(logfile_ap
, ap
);
1004 retval
= fsckPrintString(ctx
, msg
, logfile_ap
);
1005 ctx
->writeToLog
= 0;
1008 // Now write string to standard output now as per caller's specifications
1009 retval
= (*func
)(ctx
, msg
, ap
);
1011 retval
= 0; // NULL fp means don't output anything
1013 if (ctx
->postMessage
) {
1015 fsck_block_status_t rv
;
1017 va_copy(vaBlock
, ap
);
1018 rv
= (ctx
->postMessage
)(c
, m
, vaBlock
);
1019 if (rv
== fsckBlockAbort
) {
1023 if (rv
== fsckBlockIgnore
) {
1034 * fsckMsgClass(context, msgnum)
1035 * Return the message class (Verify, Successs, Failure, etc.)
1036 * for a given message number. If the message number is unknown,
1037 * it returns fsckMsgUnknown.
1040 fsckMsgClass(fsck_ctx_t c
, int msgNum
)
1042 struct context
*ctx
= c
;
1046 return fsckMsgUnknown
;
1048 m
= findmessage(ctx
, msgNum
);
1050 return fsckMsgUnknown
;
1056 * The following section is used to make the internationalizable
1057 * string file; this is a file that contains each message string,
1058 * followed by an '=' and then the string again. This is then doctored
1059 * by the internationalization folks. By putting it in here, this means
1060 * we need to compile the source file (and any others that have the messages
1061 * we care about) specially, and then be run as part of the build process.
1063 #ifdef FSCK_MAKESTRINGS
1065 main(int ac
, char **av
)
1067 fsck_message_t
*msg
;
1068 extern fsck_message_t hfs_errors
[];
1069 extern fsck_message_t hfs_messages
[];
1071 printf("/* Standard messages */\n");
1072 for (msg
= fsck_messages_common
;
1075 char *newstr
= convertfmt(msg
->msg
);
1077 if (newstr
== NULL
) {
1078 printf("\"%s\" = \"%s\";\n", msg
->msg
, msg
->msg
);
1080 printf("\"%s\" = \"%s\";\n", newstr
, newstr
);
1085 printf("\n/* HFS-specific standard messages */\n");
1086 for (msg
= hfs_messages
;
1089 char *newstr
= convertfmt(msg
->msg
);
1091 if (newstr
== NULL
) {
1092 printf("\"%s\" = \"%s\";\n", msg
->msg
, msg
->msg
);
1094 printf("\"%s\" = \"%s\";\n", newstr
, newstr
);
1099 printf("\n/* HFS-specific errors */\n");
1100 for (msg
= hfs_errors
;
1103 char *newstr
= convertfmt(msg
->msg
);
1105 if (newstr
== NULL
) {
1106 printf("\"%s\" = \"%s\";\n", msg
->msg
, msg
->msg
);
1108 printf("\"%s\" = \"%s\";\n", newstr
, newstr
);
1115 #endif /* FSCK_MAKESTRINGS */
1118 * This is used only for testing; it'll take some dumb arguments on
1119 * the command line, and then print out some messages. It tests the
1120 * allocation, initialization, and searching.
1123 main(int ac
, char **av
)
1126 enum fsck_output_type t
= fsckOutputUndefined
;
1127 int (*func
)(fsck_ctx_t
, int, ...);
1130 fctx
= fsckCreate();
1133 if (!strcmp(av
[1], "-g")) {
1135 fsckSetStyle(fctx
, t
);
1136 fsckSetDefaultResponse(fctx
, fsckDefaultYes
);
1137 } else if (!strcmp(av
[1], "-s")) {
1138 t
= fsckOutputTraditional
;
1139 fsckSetStyle(fctx
, t
);
1140 } else if (!strcmp(av
[1], "-x")) {
1142 fsckSetStyle(fctx
, t
);
1143 fsckSetDefaultResponse(fctx
, fsckDefaultYes
);
1147 fsckSetOutput(fctx
, stdout
);
1148 fsckPrint(fctx
, fsckInformation
, "fsck", "version");
1150 i
= fsckAskPrompt(fctx
, "Unknown file %s; remove? [y|n] ", "/tmp/foo");
1152 fprintf(stderr
, "\n\nfile %s is to be removed\n\n", "/tmp/foo");
1154 fsckPrint(fctx
, fsckProgress
, 10);
1155 fsckPrint(fctx
, fsckVolumeNotRepaired
);
1162 #endif /* FSCK_TEST */