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>
30 #include "SecurityTool/security_tool_commands.h"
41 #include <CoreFoundation/CFRunLoop.h>
44 #include <securityd/spi.h>
47 /* Maximum length of an input line in interactive mode. */
48 #define MAX_LINE_LEN 4096
49 /* Maximum number of arguments on an input line in interactive mode. */
53 /* The default prompt. */
54 const char *prompt_string
= "security> ";
56 /* Forward declarations of static functions. */
59 /* Global variables. */
63 /* Return 1 if name matches command. */
65 match_command(const char *command_name
, const char *name
)
67 return !strncmp(command_name
, name
, strlen(name
));
70 /* The help command. */
72 help(int argc
, char * const *argv
)
79 for (arg
= argv
+ 1; *arg
; ++arg
)
83 for (c
= commands
; c
->c_name
; ++c
)
85 if (match_command(c
->c_name
, *arg
))
93 printf("Usage: %s %s\n", c
->c_name
, c
->c_usage
);
96 fprintf(stderr
, "%s: no such command: %s", argv
[0], *arg
);
103 for (c
= commands
; c
->c_name
; ++c
)
104 printf(" %-17s %s\n", c
->c_name
, c
->c_help
);
110 /* States for split_line parser. */
120 /* Split a line into multiple arguments and return them in *pargc and *pargv. */
122 split_line(char *line
, int *pargc
, char * const **pargv
)
124 static char *argvec
[MAX_ARGS
+ 1];
128 parse_state state
= SKIP_WS
;
131 for (ptr
= line
; *ptr
; ++ptr
)
133 if (state
== SKIP_WS
)
138 if (*ptr
== '"' || *ptr
== '\'')
143 continue; /* Skip the quote. */
152 if (state
== READ_ARG
)
156 state
= READ_ARG_ESCAPED
;
159 else if (isspace(*ptr
))
161 /* 0 terminate each arg. */
165 if (argc
>= MAX_ARGS
)
172 if (state
== QUOTED_ARG
)
176 state
= QUOTED_ARG_ESCAPED
;
179 if (*ptr
== quote_ch
)
181 /* 0 terminate each arg. */
185 if (argc
>= MAX_ARGS
)
192 if (state
== READ_ARG_ESCAPED
)
198 if (state
== QUOTED_ARG_ESCAPED
)
205 if (state
!= SKIP_WS
)
207 /* Terminate last arg. */
212 /* Teminate arg vector. */
219 /* Print a (hopefully) useful usage message. */
224 "Usage: %s [-h] [-i] [-l] [-p prompt] [-q] [-v] [command] [opt ...]\n"
225 " -i Run in interactive mode.\n"
226 " -l Run /usr/bin/leaks -nocontext before exiting.\n"
227 " -p Set the prompt to \"prompt\" (implies -i).\n"
228 " -q Be less verbose.\n"
229 " -v Be more verbose about what's going on.\n"
230 "%s commands are:\n", getprogname(), getprogname());
232 return SHOW_USAGE_MESSAGE
;
235 /* Execute a single command. */
237 execute_command(int argc
, char * const *argv
)
246 for (c
= commands
; c
->c_name
; ++c
)
248 if (match_command(c
->c_name
, argv
[0]))
259 /* Reset getopt for command proc. */
267 fprintf(stderr
, "%s", c
->c_name
);
268 for (ix
= 1; ix
< argc
; ++ix
)
269 fprintf(stderr
, " \"%s\"", argv
[ix
]);
270 fprintf(stderr
, "\n");
273 result
= c
->c_func(argc
, argv
);
275 fprintf(stderr
, "Usage: %s %s\n %s\n", c
->c_name
, c
->c_usage
, c
->c_help
);
281 warnx("unknown command: %s", argv
[0]);
287 receive_notifications(void)
289 /* Run the CFRunloop to get any pending notifications. */
290 while (CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, TRUE
) == kCFRunLoopRunHandledSource
);
294 main(int argc
, char * const *argv
)
298 int do_interactive
= 0;
302 if (!SecIsInternalRelease()) {
303 errx(1, "command unavailable");
306 /* Do getopt stuff for global options. */
309 while ((ch
= getopt(argc
, argv
, "hilp:qv")) != -1)
324 prompt_string
= optarg
;
349 /* Munge argc/argv so that argv[0] is something. */
350 return help(argc
+ 1, argv
- 1);
354 receive_notifications();
355 result
= execute_command(argc
, argv
);
356 receive_notifications();
358 else if (do_interactive
)
360 /* In interactive mode we just read commands and run them until readline returns NULL. */
362 /* Only show prompt string if stdin is a tty. */
363 int show_prompt
= isatty(0);
367 static char buffer
[MAX_LINE_LEN
];
368 char * const *av
, *input
;
372 fprintf(stderr
, "%s", prompt_string
);
374 input
= readline(buffer
, MAX_LINE_LEN
);
378 split_line(input
, &ac
, &av
);
379 receive_notifications();
380 result
= execute_command(ac
, av
);
381 receive_notifications();
388 if (result
&& ! do_quiet
)
390 fprintf(stderr
, "%s: returned %d\n", av
[0], result
);
399 char *const argvec
[3] = { "leaks", "-nocontext", NULL
};