]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/arguments.c
autotools: add -Wimplicit-fallthrough
[mirror_lxc.git] / src / lxc / tools / arguments.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
8 * Michel Normand <normand at fr.ibm.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #define _GNU_SOURCE
26 #include <ctype.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #include <lxc/lxccontainer.h>
37 #include <lxc/version.h>
38
39 #include "arguments.h"
40 #include "compiler.h"
41 #include "namespace.h"
42 #include "initutils.h"
43
44 static int build_shortopts(const struct option *a_options, char *a_shortopts,
45 size_t a_size)
46 {
47 size_t i = 0;
48 const struct option *opt;
49
50 if (!a_options || !a_shortopts || !a_size)
51 return -1;
52
53 for (opt = a_options; opt->name; opt++) {
54 if (!isascii(opt->val))
55 continue;
56
57 if (i < a_size)
58 a_shortopts[i++] = opt->val;
59 else
60 goto is2big;
61
62 if (opt->has_arg == no_argument)
63 continue;
64
65 if (i < a_size)
66 a_shortopts[i++] = ':';
67 else
68 goto is2big;
69
70 if (opt->has_arg == required_argument)
71 continue;
72
73 if (i < a_size)
74 a_shortopts[i++] = ':';
75 else
76 goto is2big;
77 }
78
79 if (i < a_size)
80 a_shortopts[i] = '\0';
81 else
82 goto is2big;
83
84 return 0;
85
86 is2big:
87 errno = E2BIG;
88 return -1;
89 }
90
91 __noreturn__ static void print_usage_exit(const struct option longopts[],
92 const struct lxc_arguments *a_args)
93
94 {
95 int i;
96 const struct option *opt;
97
98 fprintf(stderr, "Usage: %s ", a_args->progname);
99
100 for (opt = longopts, i = 1; opt->name; opt++, i++) {
101 fprintf(stderr, "[");
102
103 if (isprint(opt->val))
104 fprintf(stderr, "-%c|", opt->val);
105
106 fprintf(stderr, "--%s", opt->name);
107
108 if ((opt->has_arg == required_argument) ||
109 (opt->has_arg == optional_argument)) {
110 int j;
111 char *uppername;
112
113 uppername = strdup(opt->name);
114 if (!uppername)
115 exit(-ENOMEM);
116
117 for (j = 0; uppername[j]; j++)
118 uppername[j] = toupper(uppername[j]);
119
120 if (opt->has_arg == required_argument)
121 fprintf(stderr, "=%s", uppername);
122 else // optional_argument
123 fprintf(stderr, "[=%s]", uppername);
124
125 free(uppername);
126 }
127
128 fprintf(stderr, "] ");
129
130 if (!(i % 4))
131 fprintf(stderr, "\n\t");
132 }
133
134 fprintf(stderr, "\n");
135 exit(0);
136 }
137
138 __noreturn__ static void print_version_exit()
139 {
140 printf("%s\n", lxc_get_version());
141 exit(0);
142 }
143
144 __noreturn__ static void print_help_exit(const struct lxc_arguments *args,
145 int code)
146 {
147 fprintf(stderr, "\
148 Usage: %s %s\
149 \n\
150 Common options :\n\
151 -o, --logfile=FILE Output log to FILE instead of stderr\n\
152 -l, --logpriority=LEVEL Set log priority to LEVEL\n\
153 -q, --quiet Don't produce any output\n\
154 -P, --lxcpath=PATH Use specified container path\n\
155 -?, --help Give this help list\n\
156 --usage Give a short usage message\n\
157 --version Print the version number\n\
158 \n\
159 Mandatory or optional arguments to long options are also mandatory or optional\n\
160 for any corresponding short options.\n\
161 \n\
162 See the %s man page for further information.\n\n",
163 args->progname, args->help, args->progname);
164
165 if (args->helpfn)
166 args->helpfn(args);
167
168 exit(code);
169 }
170
171 static int lxc_arguments_lxcpath_add(struct lxc_arguments *args,
172 const char *lxcpath)
173 {
174 if (args->lxcpath_additional != -1 &&
175 args->lxcpath_cnt > args->lxcpath_additional) {
176 fprintf(stderr,
177 "This command only accepts %d -P,--lxcpath arguments\n",
178 args->lxcpath_additional + 1);
179 exit(EXIT_FAILURE);
180 }
181
182 args->lxcpath = realloc(
183 args->lxcpath, (args->lxcpath_cnt + 1) * sizeof(args->lxcpath[0]));
184 if (args->lxcpath == NULL) {
185 lxc_error(args, "no memory");
186 return -ENOMEM;
187 }
188
189 args->lxcpath[args->lxcpath_cnt++] = lxcpath;
190 return 0;
191 }
192
193 extern int lxc_arguments_parse(struct lxc_arguments *args, int argc,
194 char *const argv[])
195 {
196 int ret = 0;
197 bool logfile = false;
198 char shortopts[256];
199
200 ret = build_shortopts(args->options, shortopts, sizeof(shortopts));
201 if (ret < 0) {
202 lxc_error(args, "build_shortopts() failed : %s",
203 strerror(errno));
204 return ret;
205 }
206
207 while (true) {
208 int c;
209 int index = 0;
210
211 c = getopt_long(argc, argv, shortopts, args->options, &index);
212 if (c == -1)
213 break;
214
215 switch (c) {
216 case 'n':
217 args->name = optarg;
218 break;
219 case 'o':
220 args->log_file = optarg;
221 logfile = true;
222 break;
223 case 'l':
224 args->log_priority = optarg;
225 if (!logfile &&
226 args->log_file &&
227 strcmp(args->log_file, "none") == 0)
228 args->log_file = NULL;
229 break;
230 case 'q':
231 args->quiet = 1;
232 break;
233 case OPT_RCFILE:
234 args->rcfile = optarg;
235 break;
236 case 'P':
237 remove_trailing_slashes(optarg);
238 ret = lxc_arguments_lxcpath_add(args, optarg);
239 if (ret < 0)
240 return ret;
241 break;
242 case OPT_USAGE:
243 print_usage_exit(args->options, args);
244 case OPT_VERSION:
245 print_version_exit();
246 case '?':
247 print_help_exit(args, 1);
248 case 'h':
249 print_help_exit(args, 0);
250 default:
251 if (args->parser) {
252 ret = args->parser(args, c, optarg);
253 if (ret)
254 goto error;
255 }
256 }
257 }
258
259 /*
260 * Reclaim the remaining command arguments
261 */
262 args->argv = &argv[optind];
263 args->argc = argc - optind;
264
265 /* If no lxcpaths were given, use default */
266 if (!args->lxcpath_cnt) {
267 ret = lxc_arguments_lxcpath_add(
268 args, lxc_get_global_config_item("lxc.lxcpath"));
269 if (ret < 0)
270 return ret;
271 }
272
273 /* Check the command options */
274 if (!args->name && strncmp(args->progname, "lxc-autostart", strlen(args->progname)) != 0
275 && strncmp(args->progname, "lxc-unshare", strlen(args->progname)) != 0) {
276 if (args->argv) {
277 args->name = argv[optind];
278 optind++;
279 args->argv = &argv[optind];
280 args->argc = argc - optind;
281 }
282
283 if (!args->name) {
284 lxc_error(args, "No container name specified");
285 return -1;
286 }
287 }
288
289 if (args->checker)
290 ret = args->checker(args);
291
292 error:
293 if (ret)
294 lxc_error(args, "could not parse command line");
295
296 return ret;
297 }
298
299 int lxc_arguments_str_to_int(struct lxc_arguments *args, const char *str)
300 {
301 long val;
302 char *endptr;
303
304 errno = 0;
305 val = strtol(str, &endptr, 10);
306 if (errno) {
307 lxc_error(args, "invalid statefd '%s' : %s", str,
308 strerror(errno));
309 return -1;
310 }
311
312 if (*endptr) {
313 lxc_error(args, "invalid digit for statefd '%s'", str);
314 return -1;
315 }
316
317 return (int)val;
318 }
319
320 bool lxc_setup_shared_ns(struct lxc_arguments *args, struct lxc_container *c)
321 {
322 int i;
323
324 for (i = 0; i < LXC_NS_MAX; i++) {
325 const char *key, *value;
326
327 value = args->share_ns[i];
328 if (!value)
329 continue;
330
331 if (i == LXC_NS_NET)
332 key = "lxc.namespace.share.net";
333 else if (i == LXC_NS_IPC)
334 key = "lxc.namespace.share.ipc";
335 else if (i == LXC_NS_UTS)
336 key = "lxc.namespace.share.uts";
337 else if (i == LXC_NS_PID)
338 key = "lxc.namespace.share.pid";
339 else
340 continue;
341
342 if (!c->set_config_item(c, key, value)) {
343 lxc_error(args, "Failed to set \"%s = %s\"", key, value);
344 return false;
345 }
346 }
347
348 return true;
349 }