2 * Copyright (c) 2011, Collabora Ltd.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * * Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the
10 * following disclaimer.
11 * * Redistributions in binary form must reproduce the
12 * above copyright notice, this list of conditions and
13 * the following disclaimer in the documentation and/or
14 * other materials provided with the distribution.
15 * * The names of contributors to this software may not be
16 * used to endorse or promote products derived from this
17 * software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32 * Author: Stef Walter <stefw@collabora.co.uk>
56 int (*function) (int, char*[]);
60 { "extract", p11_tool_extract, "Extract certificates" },
62 { "list-modules", p11_tool_list_modules, "List modules and tokens"},
67 short_option (int opt)
69 if (isalpha (opt) || isdigit (opt))
74 static const struct option *
75 find_option (const struct option *longopts,
80 for (i = 0; longopts[i].name != NULL; i++) {
81 if (longopts[i].val == opt)
89 p11_tool_usage (const p11_tool_desc *usages,
90 const struct option *longopts)
92 const struct option *longopt;
93 const int indent = 22;
94 const char *long_name;
95 const char *description;
102 for (i = 0; usages[i].text != NULL; i++) {
104 /* If no option, then this is a heading */
105 if (!usages[i].option) {
106 printf ("%s\n\n", usages[i].text);
110 longopt = find_option (longopts, usages[i].option);
111 long_name = longopt ? longopt->name : NULL;
112 short_name = short_option (usages[i].option);
113 description = usages[i].text;
115 if (short_name && long_name)
116 len = printf (" -%c, --%s", (int)short_name, long_name);
118 len = printf (" --%s", long_name);
120 len = printf (" -%c", (int)short_name);
121 if (longopt && longopt->has_arg)
122 len += printf ("%s<%s>",
123 long_name ? "=" : " ",
124 usages[i].arg ? usages[i].arg : "...");
126 spaces = indent - len;
131 while (description) {
134 next = strchr (description, '\n');
137 printf ("%.*s", (int)(next - description), description);
141 printf ("%s\n", description);
150 p11_tool_getopt (int argc,
152 const struct option *longopts)
159 if (!p11_buffer_init_null (&buf, 64))
160 return_val_if_reached (-1);
162 for (i = 0; longopts[i].name != NULL; i++) {
163 opt = short_option (longopts[i].val);
165 p11_buffer_add (&buf, &opt, 1);
166 assert (longopts[i].has_arg != optional_argument);
167 if (longopts[i].has_arg == required_argument)
168 p11_buffer_add (&buf, ":", 1);
172 ret = getopt_long (argc, argv, buf.data, longopts, NULL);
174 p11_buffer_uninit (&buf);
184 printf ("usage: p11-kit command <args>...\n");
185 printf ("\nCommon p11-kit commands are:\n");
186 for (i = 0; commands[i].name != NULL; i++)
187 printf (" %-15s %s\n", commands[i].name, commands[i].text);
188 printf ("\nSee 'p11-kit <command> --help' for more information\n");
192 exec_external (const char *command,
200 if (!asprintf (&filename, "p11-kit-%s", command) < 0)
201 return_if_reached ();
203 /* Add our libexec directory to the path */
204 path = getenv ("PATH");
205 if (!asprintf (&env, "PATH=%s%s%s", path ? path : "", path ? P11_PATH_SEP : "", PRIVATEDIR))
206 return_if_reached ();
210 execvp (filename, argv);
216 putenv ("P11_KIT_DEBUG=all");
224 putenv ("P11_KIT_DEBUG=");
226 p11_message_quiet ();
230 main (int argc, char *argv[])
232 char *command = NULL;
233 bool want_help = false;
239 * Parse the global options. We rearrange the options as
240 * necessary, in order to pass relevant options through
241 * to the commands, but also have them take effect globally.
244 for (in = 1, out = 1; in < argc; in++, out++) {
246 /* The non-option is the command, take it out of the arguments */
247 if (argv[in][0] != '-') {
253 /* The global long options */
254 } else if (argv[in][1] == '-') {
257 if (strcmp (argv[in], "--") == 0) {
259 p11_message ("no command specified");
265 } else if (strcmp (argv[in], "--verbose") == 0) {
268 } else if (strcmp (argv[in], "--quiet") == 0) {
271 } else if (strcmp (argv[in], "--help") == 0) {
274 } else if (!command) {
275 p11_message ("unknown global option: %s", argv[in]);
279 /* The global short options */
283 for (i = 1; argv[in][i] != '\0'; i++) {
284 switch (argv[in][i]) {
289 /* Compatibility option */
291 command = "list-modules";
304 p11_message ("unknown global option: -%c", (int)argv[in][i]);
312 /* Skipping this argument? */
316 argv[out] = argv[in];
319 /* Initialize tool's debugging after setting env vars above */
322 if (command == NULL) {
323 /* As a special favor if someone just typed 'p11-kit', help them out */
327 } else if (want_help) {
331 p11_message ("no command specified");
338 /* Look for the command */
339 for (i = 0; commands[i].name != NULL; i++) {
340 if (strcmp (commands[i].name, command) == 0) {
342 return (commands[i].function) (argc, argv);
346 /* Got here because no command matched */
347 exec_external (command, argc, argv);
349 /* At this point we have no command */
350 p11_message ("'%s' is not a valid p11-kit command. See 'p11-kit --help'", command);