2 * Copyright (c) 2003-2010,2013-2017 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@
26 #include "SecurityTool.h"
27 #include "SecInternalReleasePriv.h"
29 #include <SecurityTool/readline.h>
40 #include <CoreFoundation/CFRunLoop.h>
43 #include <securityd/spi.h>
46 /* Maximum length of an input line in interactive mode. */
47 #define MAX_LINE_LEN 4096
48 /* Maximum number of arguments on an input line in interactive mode. */
52 /* The default prompt. */
53 const char *prompt_string
= "security> ";
55 /* Forward declarations of static functions. */
58 /* Global variables. */
62 /* Return 1 if name matches command. */
64 match_command(const char *command_name
, const char *name
)
66 return !strncmp(command_name
, name
, strlen(name
));
69 /* The help command. */
71 help(int argc
, char * const *argv
)
78 for (arg
= argv
+ 1; *arg
; ++arg
)
82 for (c
= commands
; c
->c_name
; ++c
)
84 if (match_command(c
->c_name
, *arg
))
92 printf("Usage: %s %s\n", c
->c_name
, c
->c_usage
);
95 fprintf(stderr
, "%s: no such command: %s", argv
[0], *arg
);
102 for (c
= commands
; c
->c_name
; ++c
)
103 printf(" %-17s %s\n", c
->c_name
, c
->c_help
);
109 /* States for split_line parser. */
119 /* Split a line into multiple arguments and return them in *pargc and *pargv. */
121 split_line(char *line
, int *pargc
, char * const **pargv
)
123 static char *argvec
[MAX_ARGS
+ 1];
127 parse_state state
= SKIP_WS
;
130 for (ptr
= line
; *ptr
; ++ptr
)
132 if (state
== SKIP_WS
)
137 if (*ptr
== '"' || *ptr
== '\'')
142 continue; /* Skip the quote. */
151 if (state
== READ_ARG
)
155 state
= READ_ARG_ESCAPED
;
158 else if (isspace(*ptr
))
160 /* 0 terminate each arg. */
164 if (argc
>= MAX_ARGS
)
171 if (state
== QUOTED_ARG
)
175 state
= QUOTED_ARG_ESCAPED
;
178 if (*ptr
== quote_ch
)
180 /* 0 terminate each arg. */
184 if (argc
>= MAX_ARGS
)
191 if (state
== READ_ARG_ESCAPED
)
197 if (state
== QUOTED_ARG_ESCAPED
)
204 if (state
!= SKIP_WS
)
206 /* Terminate last arg. */
211 /* Teminate arg vector. */
218 /* Print a (hopefully) useful usage message. */
223 "Usage: %s [-h] [-i] [-l] [-p prompt] [-q] [-v] [command] [opt ...]\n"
224 " -i Run in interactive mode.\n"
225 " -l Run /usr/bin/leaks -nocontext before exiting.\n"
226 " -p Set the prompt to \"prompt\" (implies -i).\n"
227 " -q Be less verbose.\n"
228 " -v Be more verbose about what's going on.\n"
229 "%s commands are:\n", getprogname(), getprogname());
234 /* Execute a single command. */
236 execute_command(int argc
, char * const *argv
)
245 for (c
= commands
; c
->c_name
; ++c
)
247 if (match_command(c
->c_name
, argv
[0]))
258 /* Reset getopt for command proc. */
266 fprintf(stderr
, "%s", c
->c_name
);
267 for (ix
= 1; ix
< argc
; ++ix
)
268 fprintf(stderr
, " \"%s\"", argv
[ix
]);
269 fprintf(stderr
, "\n");
272 result
= c
->c_func(argc
, argv
);
274 fprintf(stderr
, "Usage: %s %s\n %s\n", c
->c_name
, c
->c_usage
, c
->c_help
);
280 warnx("unknown command: %s", argv
[0]);
286 receive_notifications(void)
288 /* Run the CFRunloop to get any pending notifications. */
289 while (CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, TRUE
) == kCFRunLoopRunHandledSource
);
293 main(int argc
, char * const *argv
)
297 int do_interactive
= 0;
301 if (!SecIsInternalRelease()) {
302 errx(1, "command unavailable");
305 /* Do getopt stuff for global options. */
308 while ((ch
= getopt(argc
, argv
, "hilp:qv")) != -1)
323 prompt_string
= optarg
;
348 /* Munge argc/argv so that argv[0] is something. */
349 return help(argc
+ 1, argv
- 1);
353 receive_notifications();
354 result
= execute_command(argc
, argv
);
355 receive_notifications();
357 else if (do_interactive
)
359 /* In interactive mode we just read commands and run them until readline returns NULL. */
361 /* Only show prompt string if stdin is a tty. */
362 int show_prompt
= isatty(0);
366 static char buffer
[MAX_LINE_LEN
];
367 char * const *av
, *input
;
371 fprintf(stderr
, "%s", prompt_string
);
373 input
= readline(buffer
, MAX_LINE_LEN
);
377 split_line(input
, &ac
, &av
);
378 receive_notifications();
379 result
= execute_command(ac
, av
);
380 receive_notifications();
387 if (result
&& ! do_quiet
)
389 fprintf(stderr
, "%s: returned %d\n", av
[0], result
);
398 char *const argvec
[3] = { "leaks", "-nocontext", NULL
};