]> git.saurik.com Git - apple/libc.git/blob - libdarwin/ctl.c
Libc-1439.100.3.tar.gz
[apple/libc.git] / libdarwin / ctl.c
1 #include "internal.h"
2
3 #pragma mark Definitions
4 #define CTL_OUTPUT_WIDTH (80)
5 #define CTL_OUTPUT_OPTARG_INDENT (32)
6 #define CTL_OUTPUT_OPTARG_OVERFLOW (CTL_OUTPUT_OPTARG_INDENT - 4)
7 #define SUBCOMMAND_LINKER_SET "__subcommands"
8
9 #define OS_SUBCOMMAND_OPTIONS_FOREACH(_osco_i, _osc, _which, _i) \
10 while (((_osco_i) = &osc->osc_ ## _which[(_i)]) && \
11 ((_i) += 1, 1) && \
12 !((_osco_i)->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_TERMINATOR))
13
14 #pragma mark Types
15 OS_ENUM(os_subcommand_option_spec_fmt, uint64_t,
16 OS_SUBCOMMAND_OPTION_SPEC_SHORT,
17 OS_SUBCOMMAND_OPTION_SPEC_LONG,
18 OS_SUBCOMMAND_OPTION_SPEC_COMBINED,
19 );
20
21 #pragma mark Forward Declarations
22 static void _print_header(
23 FILE *f,
24 const char *hdr,
25 bool *already_done);
26 static const os_subcommand_t *_os_subcommand_find(
27 const char *name);
28 static void _os_subcommand_print_usage(
29 const os_subcommand_t *osc,
30 FILE *f);
31 static void _os_subcommand_print_help_line(
32 const os_subcommand_t *osc,
33 FILE *f);
34 static void _print_subcommand_list(
35 const os_subcommand_t *osc,
36 FILE *f);
37
38 #pragma mark Module Globals
39 static const os_subcommand_t __help_cmd;
40 static const os_subcommand_t *_help_cmd = &__help_cmd;
41
42 static const os_subcommand_t __main_cmd;
43 static const os_subcommand_t *_main_cmd = &__main_cmd;
44 static const os_subcommand_t *_internal_main_cmd = &__main_cmd;
45
46 static struct ttysize __ttys = {
47 .ts_lines = 24,
48 .ts_cols = CTL_OUTPUT_WIDTH,
49 };
50
51 static const struct ttysize *_ttys = &__ttys;
52
53 #pragma mark Module Private
54 static void
55 _init_column_count(void)
56 {
57 const char *columns_env = NULL;
58 char *end = NULL;
59 struct ttysize ttys = {
60 .ts_lines = 24,
61 .ts_cols = CTL_OUTPUT_WIDTH,
62 };
63 int ret = -1;
64
65 columns_env = getenv("COLUMNS");
66 if (columns_env) {
67 unsigned short cols = -1;
68
69 cols = strtoul(columns_env, &end, 0);
70 if (end != columns_env && end[0] != 0) {
71 ttys.ts_lines = cols;
72 }
73 } else {
74 ret = ioctl(0, TIOCGSIZE, &ttys);
75 if (ret) {
76 ttys.ts_lines = 24;
77 ttys.ts_cols = CTL_OUTPUT_WIDTH;
78 }
79 }
80
81 __ttys = ttys;
82 }
83
84 static void
85 _stoupper(char *str)
86 {
87 size_t i = 0;
88 size_t len = strlen(str);
89
90 for (i = 0; i < len; i++) {
91 char *cp = &str[i];
92 *cp = ___toupper(*cp);
93 }
94 }
95
96 #pragma mark Main Subcommand
97 static int _main_invoke(const os_subcommand_t *osc,
98 int argc,
99 const char *argv[]);
100
101 static const os_subcommand_option_t _main_positional[] = {
102 [0] = {
103 .osco_version = OS_SUBCOMMAND_OPTION_VERSION,
104 .osco_flags = 0,
105 .osco_option = NULL,
106 .osco_argument_usage = "subcommand",
107 .osco_argument_human = "The subcommand to invoke",
108 },
109 OS_SUBCOMMAND_OPTION_TERMINATOR,
110 };
111
112 static const os_subcommand_t __main_cmd = {
113 .osc_version = OS_SUBCOMMAND_VERSION,
114 .osc_flags = OS_SUBCOMMAND_FLAG_MAIN,
115 .osc_name = "_main",
116 .osc_desc = "main command",
117 .osc_optstring = NULL,
118 .osc_options = NULL,
119 .osc_required = NULL,
120 .osc_optional = NULL,
121 .osc_positional = _main_positional,
122 .osc_invoke = &_main_invoke,
123 };
124
125 static int
126 _main_invoke(const os_subcommand_t *osc, int argc, const char *argv[])
127 {
128 return 0;
129 }
130
131 #pragma mark Help Subcommand
132 static int _help_invoke(const os_subcommand_t *osc,
133 int argc,
134 const char *argv[]);
135
136 static const os_subcommand_option_t _help_positional[] = {
137 [0] = {
138 .osco_version = OS_SUBCOMMAND_OPTION_VERSION,
139 .osco_flags = 0,
140 .osco_option = NULL,
141 .osco_argument_usage = "SUBCOMMAND",
142 .osco_argument_human = "The subcommand to query for help",
143 },
144 OS_SUBCOMMAND_OPTION_TERMINATOR,
145 };
146
147 static const os_subcommand_t __help_cmd = {
148 .osc_version = OS_SUBCOMMAND_VERSION,
149 .osc_flags = 0,
150 .osc_name = "help",
151 .osc_desc = "prints helpful information",
152 .osc_optstring = NULL,
153 .osc_options = NULL,
154 .osc_required = NULL,
155 .osc_optional = NULL,
156 .osc_positional = _help_positional,
157 .osc_invoke = &_help_invoke,
158 };
159
160 static int
161 _help_invoke(const os_subcommand_t *osc, int argc, const char *argv[])
162 {
163 int xit = -1;
164 const char *cmdname = NULL;
165 const os_subcommand_t *target = NULL;
166 FILE *f = stdout;
167
168 if (argc > 1) {
169 cmdname = argv[1];
170 }
171
172 // Print usage information for the requested subcommand.
173 target = _os_subcommand_find(cmdname);
174 if (!target) {
175 // If it's a bogus subcommand, just print top-level usage.
176 fprintf(stderr, "unrecognized subcommand: %s\n", cmdname);
177 target = _main_cmd;
178 xit = EX_UNAVAILABLE;
179 } else {
180 xit = 0;
181 }
182
183 if (xit) {
184 f = stderr;
185 }
186
187 _os_subcommand_print_usage(target, f);
188
189 if (target == _main_cmd) {
190 _print_subcommand_list(_help_cmd, f);
191 }
192
193 return xit;
194 }
195
196 #pragma mark Utilities
197 static void
198 _print_header(FILE *f, const char *hdr, bool *already_done)
199 {
200 if (already_done && *already_done) {
201 return;
202 }
203
204 crfprintf_np(f, "");
205 crfprintf_np(f, "%s:", hdr);
206 crfprintf_np(f, "");
207
208 if (already_done) {
209 *already_done = true;
210 }
211 }
212
213 #pragma mark Module Routines
214 static char *
215 _os_subcommand_copy_option_spec_short(const os_subcommand_t *osc,
216 const os_subcommand_option_t *osco)
217 {
218 const struct option *opt = osco->osco_option;
219 char optbuff[64] = "";
220 char argbuff[64] = "";
221 char *final = NULL;
222 int ret = -1;
223
224 if (opt) {
225 snprintf(optbuff, sizeof(optbuff), "-%c", opt->val);
226
227 switch (opt->has_arg) {
228 case no_argument:
229 break;
230 case optional_argument:
231 snprintf(argbuff, sizeof(argbuff), "[%s]",
232 osco->osco_argument_usage);
233 break;
234 case required_argument:
235 snprintf(argbuff, sizeof(argbuff), "<%s>",
236 osco->osco_argument_usage);
237 break;
238 default:
239 __builtin_unreachable();
240 }
241
242 if (!(osco->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_ENUM)) {
243 _stoupper(argbuff);
244 }
245 } else {
246 snprintf(optbuff, sizeof(optbuff), "%s", osco->osco_argument_usage);
247 if (!(osco->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_ENUM)) {
248 _stoupper(optbuff);
249 }
250 }
251
252 ret = asprintf(&final, "%s%s", optbuff, argbuff);
253 if (ret < 0) {
254 os_assert_zero(ret);
255 }
256
257 return final;
258 }
259
260 static char *
261 _os_subcommand_copy_option_spec_long(const os_subcommand_t *osc,
262 const os_subcommand_option_t *osco)
263 {
264 const struct option *opt = osco->osco_option;
265 char optbuff[64] = "";
266 char argbuff[64] = "";
267 char *final = NULL;
268 int ret = -1;
269
270 if (opt) {
271 snprintf(optbuff, sizeof(optbuff), "--%s", opt->name);
272
273 switch (opt->has_arg) {
274 case no_argument:
275 break;
276 case optional_argument:
277 snprintf(argbuff, sizeof(argbuff), "[=%s]",
278 osco->osco_argument_usage);
279 break;
280 case required_argument:
281 snprintf(argbuff, sizeof(argbuff), "=<%s>",
282 osco->osco_argument_usage);
283 break;
284 default:
285 __builtin_unreachable();
286 }
287
288 if (!(osco->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_ENUM)) {
289 _stoupper(argbuff);
290 }
291 } else {
292 snprintf(optbuff, sizeof(optbuff), "%s", osco->osco_argument_usage);
293 if (!(osco->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_ENUM)) {
294 _stoupper(optbuff);
295 }
296 }
297
298 ret = asprintf(&final, "%s%s", optbuff, argbuff);
299 if (ret < 0) {
300 os_assert_zero(ret);
301 }
302
303 return final;
304 }
305
306 static char *
307 _os_subcommand_copy_option_spec(const os_subcommand_t *osc,
308 const os_subcommand_option_t *osco, os_subcommand_option_spec_fmt_t fmt)
309 {
310 int ret = -1;
311 char *spec = NULL;
312 char *__os_free spec_old = NULL;
313
314 switch (fmt) {
315 case OS_SUBCOMMAND_OPTION_SPEC_SHORT:
316 _os_subcommand_copy_option_spec_short(osc, osco);
317 break;
318 case OS_SUBCOMMAND_OPTION_SPEC_LONG:
319 _os_subcommand_copy_option_spec_long(osc, osco);
320 break;
321 case OS_SUBCOMMAND_OPTION_SPEC_COMBINED:
322 spec = _os_subcommand_copy_option_spec_long(osc, osco);
323 if (osco->osco_option) {
324 spec_old = spec;
325
326 ret = asprintf(&spec, "-%c | %s", osco->osco_option->val, spec);
327 if (ret < 0) {
328 os_assert_zero(ret);
329 }
330 }
331
332 break;
333 default:
334 __builtin_unreachable();
335 }
336
337 return spec;
338 }
339
340 static char *
341 _os_subcommand_copy_usage_line(const os_subcommand_t *osc)
342 {
343 char *usage_line = NULL;
344 size_t i = 0;
345 const os_subcommand_option_t *osco_i = NULL;
346 const char *optional_spec = "";
347 char subcmd_name[64];
348 int ret = -1;
349
350 // The usage line does not enumerate all possible optional options, just the
351 // required options. If there are optional options, then display that but
352 // otherwise leave them to be described by more extensive usage information.
353 if (osc->osc_optional) {
354 optional_spec = " [options]";
355 }
356
357 if (osc == _main_cmd) {
358 strlcpy(subcmd_name, "", sizeof(subcmd_name));
359 } else {
360 snprintf(subcmd_name, sizeof(subcmd_name), " %s", osc->osc_name);
361 }
362
363 ret = asprintf(&usage_line, "%s%s%s",
364 getprogname(), subcmd_name, optional_spec);
365 if (ret < 0) {
366 os_assert_zero(ret);
367 }
368
369 i = 0;
370 OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, required, i) {
371 char *__os_free usage_line_old = NULL;
372 char *__os_free osco_spec = NULL;
373
374 usage_line_old = usage_line;
375
376 osco_spec = _os_subcommand_copy_option_spec_long(osc, osco_i);
377 ret = asprintf(&usage_line, "%s %s", usage_line, osco_spec);
378 if (ret < 0) {
379 os_assert_zero(ret);
380 }
381 }
382
383 i = 0;
384 OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, positional, i) {
385 char *__os_free usage_line_old = NULL;
386 char *__os_free osco_spec = NULL;
387 const char *braces[] = {
388 "<",
389 ">",
390 };
391
392 if (osco_i->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS) {
393 braces[0] = "[";
394 braces[1] = "]";
395 }
396
397 usage_line_old = usage_line;
398
399 osco_spec = _os_subcommand_copy_option_spec_long(osc, osco_i);
400 ret = asprintf(&usage_line, "%s %s%s%s",
401 usage_line, braces[0], osco_spec, braces[1]);
402 if (ret < 0) {
403 os_assert_zero(ret);
404 }
405 }
406
407 if (osc == _main_cmd && osc != _internal_main_cmd) {
408 // Always include the positional subcommand when printing usage for the
409 // main subcommand. We do not expect it to be specified in a user-
410 // provided main subcommand.
411 const os_subcommand_option_t *subopt = &_main_positional[0];
412 char *__os_free usage_line_old = NULL;
413 char *__os_free osco_spec = NULL;
414
415 usage_line_old = usage_line;
416
417 osco_spec = _os_subcommand_copy_option_spec_long(osc, subopt);
418 ret = asprintf(&usage_line, "%s <%s>", usage_line, osco_spec);
419 if (ret < 0) {
420 os_assert_zero(ret);
421 }
422 }
423
424 return usage_line;
425 }
426
427 static void
428 _os_subcommand_print_option_usage(const os_subcommand_t *osc,
429 const os_subcommand_option_t *osco, FILE *f)
430 {
431 char *__os_free opt_spec = NULL;
432 ssize_t initpad = -CTL_OUTPUT_OPTARG_INDENT;
433
434 opt_spec = _os_subcommand_copy_option_spec(osc, osco,
435 OS_SUBCOMMAND_OPTION_SPEC_COMBINED);
436 fprintf(f, " %-24s ", opt_spec);
437
438 // If the usage specifier is long, start the description on the next line.
439 if (strlen(opt_spec) >= CTL_OUTPUT_OPTARG_OVERFLOW) {
440 initpad = CTL_OUTPUT_OPTARG_INDENT;
441 crfprintf_np(f, "");
442 }
443
444 wfprintf_np(f, initpad, CTL_OUTPUT_OPTARG_INDENT, _ttys->ts_cols, "%s",
445 osco->osco_argument_human);
446 }
447
448 static void
449 _os_subcommand_print_help_line(const os_subcommand_t *osc, FILE *f)
450 {
451 ssize_t initpad = -CTL_OUTPUT_OPTARG_INDENT;
452
453 fprintf(f, " %-24s ", osc->osc_name);
454
455 // If the usage specifier is long, start the description on the next line.
456 if (strlen(osc->osc_name) >= CTL_OUTPUT_OPTARG_OVERFLOW) {
457 initpad = CTL_OUTPUT_OPTARG_INDENT;
458 crfprintf_np(f, "");
459 }
460
461 wfprintf_np(f, initpad, CTL_OUTPUT_OPTARG_INDENT, _ttys->ts_cols, "%s",
462 osc->osc_desc);
463 }
464
465 static void
466 _os_subcommand_print_usage(const os_subcommand_t *osc, FILE *f)
467 {
468 size_t i = 0;
469 const os_subcommand_option_t *osco_i = NULL;
470 char *__os_free usage_line = NULL;
471 bool header_printed = false;
472
473 usage_line = _os_subcommand_copy_usage_line(osc);
474
475 wfprintf_np(f, 0, 4, _ttys->ts_cols, "USAGE:");
476 crfprintf_np(f, "");
477 wfprintf_np(f, 4, 4, _ttys->ts_cols, "%s", usage_line);
478
479 if (osc->osc_long_desc) {
480 // The long description gets printed in its own paragraph.
481 _print_header(f, "DESCRIPTION", NULL);
482 wfprintf_np(f, 4, 4, _ttys->ts_cols, "%s", osc->osc_long_desc);
483 } else if (osc->osc_desc) {
484 // The short description gets printed on the same line.
485 crfprintf_np(f, "");
486 wfprintf_np(f, 0, 4, _ttys->ts_cols, "DESCRIPTION: %s",
487 osc->osc_desc);
488 }
489
490 if (osc->osc_required || osc->osc_positional || osc == _main_cmd) {
491 i = 0;
492 OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, required, i) {
493 _print_header(f, "REQUIRED", &header_printed);
494 _os_subcommand_print_option_usage(osc, osco_i, f);
495 }
496
497 i = 0;
498 OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, positional, i) {
499 _print_header(f, "REQUIRED", &header_printed);
500
501 if (osco_i->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS) {
502 continue;
503 }
504
505 _os_subcommand_print_option_usage(osc, osco_i, f);
506 }
507
508 if (osc == _main_cmd && osc != _internal_main_cmd) {
509 // We do not expect the user's main command to specify that a
510 // subcommand must follow, so always defer to ours.
511 _print_header(f, "REQUIRED", &header_printed);
512 _os_subcommand_print_option_usage(osc, &_main_positional[0], f);
513 }
514 }
515
516 header_printed = false;
517
518 if (osc->osc_optional || osc->osc_positional) {
519 i = 0;
520 OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, optional, i) {
521 _print_header(f, "OPTIONAL", &header_printed);
522 _os_subcommand_print_option_usage(osc, osco_i, f);
523 }
524
525 i = 0;
526 OS_SUBCOMMAND_OPTIONS_FOREACH(osco_i, osc, positional, i) {
527 if (osco_i->osco_flags & OS_SUBCOMMAND_OPTION_FLAG_OPTIONAL_POS) {
528 _print_header(f, "OPTIONAL", &header_printed);
529 _os_subcommand_print_option_usage(osc, osco_i, f);
530 }
531 }
532 }
533 }
534
535 static const os_subcommand_t *
536 _os_subcommand_find(const char *name)
537 {
538 const os_subcommand_t **oscip = NULL;
539
540 if (!name) {
541 return _main_cmd;
542 }
543
544 if (strcmp(_help_cmd->osc_name, name) == 0) {
545 return &__help_cmd;
546 }
547
548 LINKER_SET_FOREACH(oscip, const os_subcommand_t **, SUBCOMMAND_LINKER_SET) {
549 const os_subcommand_t *osci = *oscip;
550
551 if (osci->osc_flags & OS_SUBCOMMAND_FLAG_MAIN) {
552 // The main subcommand cannot be invoked directly.
553 continue;
554 }
555
556 if (strcmp(osci->osc_name, name) == 0) {
557 return osci;
558 }
559 }
560
561 return NULL;
562 }
563
564 static int
565 _os_subcommand_be_helpful(const os_subcommand_t *osc,
566 int argc, const char *argv[])
567 {
568 int res = 0;
569
570 if (osc->osc_flags & OS_SUBCOMMAND_FLAG_HELPFUL) {
571 if (argc == 1) {
572 _os_subcommand_print_usage(osc, stdout);
573 res = 1;
574 goto __out;
575 }
576 }
577
578 if (osc->osc_flags & OS_SUBCOMMAND_FLAG_HELPFUL_FIRST_OPTION) {
579 if (argc == 2 && (strcmp(argv[1], "help") == 0 ||
580 strcmp(argv[1], "-h") == 0 ||
581 strcmp(argv[1], "-help") == 0 ||
582 strcmp(argv[1], "--help") == 0)) {
583 _os_subcommand_print_usage(osc, stdout);
584 res = 1;
585 goto __out;
586 }
587 }
588
589 __out:
590 return res;
591 }
592
593 static void
594 _print_subcommand_list(const os_subcommand_t *osc, FILE *f)
595 {
596 const os_subcommand_t **oscip = NULL;
597 bool header_printed = false;
598
599 LINKER_SET_FOREACH(oscip, const os_subcommand_t **,
600 SUBCOMMAND_LINKER_SET) {
601 const os_subcommand_t *osci = *oscip;
602
603 _print_header(f, "SUBCOMMANDS", &header_printed);
604
605 if ((osci->osc_flags & OS_SUBCOMMAND_FLAG_MAIN) ||
606 (osci->osc_flags & OS_SUBCOMMAND_FLAG_HIDDEN)) {
607 continue;
608 }
609
610 _os_subcommand_print_help_line(osci, f);
611 }
612
613 // Print the help subcommand last.
614 _os_subcommand_print_help_line(osc, f);
615 }
616
617 #pragma mark API
618 int
619 os_subcommand_main(int argc, const char *argv[],
620 os_subcommand_main_flags_t flags)
621 {
622 int xit = -1;
623 const char *cmdname = NULL;
624 const os_subcommand_t *osc = NULL;
625 const os_subcommand_t **oscip = NULL;
626
627 _init_column_count();
628
629 // Find the main subcommand if any exists. Otherwise we'll just use our pre-
630 // canned main subcommand.
631 LINKER_SET_FOREACH(oscip, const os_subcommand_t **, SUBCOMMAND_LINKER_SET) {
632 osc = *oscip;
633 if (osc->osc_flags & OS_SUBCOMMAND_FLAG_MAIN) {
634 _main_cmd = osc;
635 break;
636 }
637 }
638
639 osc = NULL;
640
641 // See if we just need to print help for the main command.
642 if (_os_subcommand_be_helpful(_main_cmd, argc, argv)) {
643 _print_subcommand_list(_help_cmd, stdout);
644 xit = 0;
645 goto __out;
646 }
647
648 // Invoke the main subcommand to snarf any global options. Our default
649 // implementation does nothing and just returns 0.
650 xit = _main_cmd->osc_invoke(_main_cmd, argc, argv);
651 if (xit) {
652 goto __out;
653 }
654
655 // Advance argument pointer and make the subcommand argv[0].
656 argc -= optind;
657 argv += optind;
658 cmdname = argv[0];
659
660 if (argc < 1) {
661 os_subcommand_fprintf(NULL, stderr, "please provide a subcommand");
662 xit = EX_USAGE;
663 goto __out;
664 }
665
666 osc = _os_subcommand_find(cmdname);
667 if (osc) {
668 if (osc->osc_flags & OS_SUBCOMMAND_FLAG_REQUIRE_ROOT) {
669 if (geteuid()) {
670 os_subcommand_fprintf(osc, stderr,
671 "subcommand requires root: %s",
672 cmdname);
673 xit = EX_NOPERM;
674 goto __out;
675 }
676 }
677
678 if (osc->osc_flags & OS_SUBCOMMAND_FLAG_TTYONLY) {
679 if (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO)) {
680 os_subcommand_fprintf(osc, stderr,
681 "subcommand requires a tty: %s",
682 cmdname);
683 xit = EX_UNAVAILABLE;
684 goto __out;
685 }
686 }
687
688 if (_os_subcommand_be_helpful(osc, argc, argv)) {
689 xit = 0;
690 goto __out;
691 }
692
693 xit = osc->osc_invoke(osc, argc, argv);
694 } else {
695 os_subcommand_fprintf(NULL, stderr, "unknown subcommand: %s", cmdname);
696 xit = EX_USAGE;
697 }
698
699 __out:
700 if (xit == EX_USAGE) {
701 if (!osc) {
702 // If we couldn't find the subcommand, then print the list of known
703 // subcommands.
704 _print_subcommand_list(_help_cmd, stderr);
705 } else {
706 _os_subcommand_print_usage(osc, stderr);
707 }
708 }
709
710 return xit;
711 }
712
713 void
714 os_subcommand_fprintf(const os_subcommand_t *osc, FILE *f,
715 const char *fmt, ...)
716 {
717 va_list ap;
718
719 va_start(ap, fmt);
720 vcrfprintf_np(f, fmt, ap);
721 va_end(ap);
722 }
723
724 void
725 os_subcommand_vfprintf(const os_subcommand_t *osc, FILE *f,
726 const char *fmt, va_list ap)
727 {
728 if (!osc || (osc->osc_flags & OS_SUBCOMMAND_FLAG_MAIN)) {
729 fprintf(f, "%s: ", getprogname());
730 } else {
731 fprintf(f, "%s-%s: ", getprogname(), osc->osc_name);
732 }
733
734 vcrfprintf_np(f, fmt, ap);
735 }