2 * Copyright (c) 2003-2010,2013 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"
28 #include <SecurityTool/readline.h>
38 #include <CoreFoundation/CFRunLoop.h>
41 #include <securityd/spi.h>
44 /* Maximum length of an input line in interactive mode. */
45 #define MAX_LINE_LEN 4096
46 /* Maximum number of arguments on an input line in interactive mode. */
50 /* The default prompt. */
51 const char *prompt_string
= "security> ";
53 /* The name of this program. */
54 const char *prog_name
;
57 /* Forward declarations of static functions. */
60 /* Global variables. */
64 /* Return 1 if name matches command. */
66 match_command(const char *command_name
, const char *name
)
68 return !strncmp(command_name
, name
, strlen(name
));
71 /* The help command. */
73 help(int argc
, char * const *argv
)
80 for (arg
= argv
+ 1; *arg
; ++arg
)
84 for (c
= commands
; c
->c_name
; ++c
)
86 if (match_command(c
->c_name
, *arg
))
94 printf("Usage: %s %s\n", c
->c_name
, c
->c_usage
);
97 fprintf(stderr
, "%s: no such command: %s", argv
[0], *arg
);
104 for (c
= commands
; c
->c_name
; ++c
)
105 printf(" %-17s %s\n", c
->c_name
, c
->c_help
);
111 /* States for split_line parser. */
121 /* Split a line into multiple arguments and return them in *pargc and *pargv. */
123 split_line(char *line
, int *pargc
, char * const **pargv
)
125 static char *argvec
[MAX_ARGS
+ 1];
129 parse_state state
= SKIP_WS
;
132 for (ptr
= line
; *ptr
; ++ptr
)
134 if (state
== SKIP_WS
)
139 if (*ptr
== '"' || *ptr
== '\'')
144 continue; /* Skip the quote. */
153 if (state
== READ_ARG
)
157 state
= READ_ARG_ESCAPED
;
160 else if (isspace(*ptr
))
162 /* 0 terminate each arg. */
166 if (argc
>= MAX_ARGS
)
173 if (state
== QUOTED_ARG
)
177 state
= QUOTED_ARG_ESCAPED
;
180 if (*ptr
== quote_ch
)
182 /* 0 terminate each arg. */
186 if (argc
>= MAX_ARGS
)
193 if (state
== READ_ARG_ESCAPED
)
199 if (state
== QUOTED_ARG_ESCAPED
)
206 if (state
!= SKIP_WS
)
208 /* Terminate last arg. */
213 /* Teminate arg vector. */
220 /* Print a (hopefully) useful usage message. */
225 "Usage: %s [-h] [-i] [-l] [-p prompt] [-q] [-v] [command] [opt ...]\n"
226 " -i Run in interactive mode.\n"
227 " -l Run /usr/bin/leaks -nocontext before exiting.\n"
228 " -p Set the prompt to \"prompt\" (implies -i).\n"
229 " -q Be less verbose.\n"
230 " -v Be more verbose about what's going on.\n"
231 "%s commands are:\n", prog_name
, prog_name
);
236 /* Execute a single command. */
238 execute_command(int argc
, char * const *argv
)
247 for (c
= commands
; c
->c_name
; ++c
)
249 if (match_command(c
->c_name
, argv
[0]))
260 /* Reset getopt for command proc. */
268 fprintf(stderr
, "%s", c
->c_name
);
269 for (ix
= 1; ix
< argc
; ++ix
)
270 fprintf(stderr
, " \"%s\"", argv
[ix
]);
271 fprintf(stderr
, "\n");
274 result
= c
->c_func(argc
, argv
);
276 fprintf(stderr
, "Usage: %s %s\n %s\n", c
->c_name
, c
->c_usage
, c
->c_help
);
282 fprintf(stderr
, "unknown command \"%s\"", argv
[0]);
288 receive_notifications(void)
290 /* Run the CFRunloop to get any pending notifications. */
291 while (CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, TRUE
) == kCFRunLoopRunHandledSource
);
295 main(int argc
, char * const *argv
)
299 int do_interactive
= 0;
303 /* Remember my name. */
304 prog_name
= strrchr(argv
[0], '/');
305 prog_name
= prog_name
? prog_name
+ 1 : argv
[0];
307 /* Do getopt stuff for global options. */
310 while ((ch
= getopt(argc
, argv
, "hilp:qv")) != -1)
325 prompt_string
= optarg
;
350 /* Munge argc/argv so that argv[0] is something. */
351 return help(argc
+ 1, argv
- 1);
355 receive_notifications();
356 result
= execute_command(argc
, argv
);
357 receive_notifications();
359 else if (do_interactive
)
361 /* In interactive mode we just read commands and run them until readline returns NULL. */
363 /* Only show prompt string if stdin is a tty. */
364 int show_prompt
= isatty(0);
368 static char buffer
[MAX_LINE_LEN
];
369 char * const *av
, *input
;
373 fprintf(stderr
, "%s", prompt_string
);
375 input
= readline(buffer
, MAX_LINE_LEN
);
379 split_line(input
, &ac
, &av
);
380 receive_notifications();
381 result
= execute_command(ac
, av
);
382 receive_notifications();
389 if (result
&& ! do_quiet
)
391 fprintf(stderr
, "%s: returned %d\n", av
[0], result
);
400 char *const argvec
[3] = { "leaks", "-nocontext", NULL
};