]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/arguments.c
f6ee123dce813b12c58ba14ad820baa9202dfc09
[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 "namespace.h"
41 #include "initutils.h"
42
43 static int build_shortopts(const struct option *a_options, char *a_shortopts,
44 size_t a_size)
45 {
46 size_t i = 0;
47 const struct option *opt;
48
49 if (!a_options || !a_shortopts || !a_size)
50 return -1;
51
52 for (opt = a_options; opt->name; opt++) {
53 if (!isascii(opt->val))
54 continue;
55
56 if (i < a_size)
57 a_shortopts[i++] = opt->val;
58 else
59 goto is2big;
60
61 if (opt->has_arg == no_argument)
62 continue;
63
64 if (i < a_size)
65 a_shortopts[i++] = ':';
66 else
67 goto is2big;
68
69 if (opt->has_arg == required_argument)
70 continue;
71
72 if (i < a_size)
73 a_shortopts[i++] = ':';
74 else
75 goto is2big;
76 }
77
78 if (i < a_size)
79 a_shortopts[i] = '\0';
80 else
81 goto is2big;
82
83 return 0;
84
85 is2big:
86 errno = E2BIG;
87 return -1;
88 }
89
90 static void print_usage_exit(const struct option longopts[],
91 const struct lxc_arguments *a_args)
92
93 {
94 int i;
95 const struct option *opt;
96
97 fprintf(stderr, "Usage: %s ", a_args->progname);
98
99 for (opt = longopts, i = 1; opt->name; opt++, i++) {
100 fprintf(stderr, "[");
101
102 if (isprint(opt->val))
103 fprintf(stderr, "-%c|", opt->val);
104
105 fprintf(stderr, "--%s", opt->name);
106
107 if ((opt->has_arg == required_argument) ||
108 (opt->has_arg == optional_argument)) {
109 int j;
110 char *uppername;
111
112 uppername = strdup(opt->name);
113 if (!uppername)
114 exit(-ENOMEM);
115
116 for (j = 0; uppername[j]; j++)
117 uppername[j] = toupper(uppername[j]);
118
119 if (opt->has_arg == required_argument)
120 fprintf(stderr, "=%s", uppername);
121 else // optional_argument
122 fprintf(stderr, "[=%s]", uppername);
123
124 free(uppername);
125 }
126
127 fprintf(stderr, "] ");
128
129 if (!(i % 4))
130 fprintf(stderr, "\n\t");
131 }
132
133 fprintf(stderr, "\n");
134 exit(0);
135 }
136
137 static void print_version_exit()
138 {
139 printf("%s\n", lxc_get_version());
140 exit(0);
141 }
142
143 static void print_help_exit(const struct lxc_arguments *args, int code)
144 {
145 fprintf(stderr, "\
146 Usage: %s %s\
147 \n\
148 Common options :\n\
149 -o, --logfile=FILE Output log to FILE instead of stderr\n\
150 -l, --logpriority=LEVEL Set log priority to LEVEL\n\
151 -q, --quiet Don't produce any output\n\
152 -P, --lxcpath=PATH Use specified container path\n\
153 -?, --help Give this help list\n\
154 --usage Give a short usage message\n\
155 --version Print the version number\n\
156 \n\
157 Mandatory or optional arguments to long options are also mandatory or optional\n\
158 for any corresponding short options.\n\
159 \n\
160 See the %s man page for further information.\n\n",
161 args->progname, args->help, args->progname);
162
163 if (args->helpfn)
164 args->helpfn(args);
165
166 exit(code);
167 }
168
169 static int lxc_arguments_lxcpath_add(struct lxc_arguments *args,
170 const char *lxcpath)
171 {
172 if (args->lxcpath_additional != -1 &&
173 args->lxcpath_cnt > args->lxcpath_additional) {
174 fprintf(stderr,
175 "This command only accepts %d -P,--lxcpath arguments\n",
176 args->lxcpath_additional + 1);
177 exit(EXIT_FAILURE);
178 }
179
180 args->lxcpath = realloc(
181 args->lxcpath, (args->lxcpath_cnt + 1) * sizeof(args->lxcpath[0]));
182 if (args->lxcpath == NULL) {
183 lxc_error(args, "no memory");
184 return -ENOMEM;
185 }
186
187 args->lxcpath[args->lxcpath_cnt++] = lxcpath;
188 return 0;
189 }
190
191 extern int lxc_arguments_parse(struct lxc_arguments *args, int argc,
192 char *const argv[])
193 {
194 int ret = 0;
195 bool logfile = false;
196 char shortopts[256];
197
198 ret = build_shortopts(args->options, shortopts, sizeof(shortopts));
199 if (ret < 0) {
200 lxc_error(args, "build_shortopts() failed : %s",
201 strerror(errno));
202 return ret;
203 }
204
205 while (true) {
206 int c;
207 int index = 0;
208
209 c = getopt_long(argc, argv, shortopts, args->options, &index);
210 if (c == -1)
211 break;
212
213 switch (c) {
214 case 'n':
215 args->name = optarg;
216 break;
217 case 'o':
218 args->log_file = optarg;
219 logfile = true;
220 break;
221 case 'l':
222 args->log_priority = optarg;
223 if (!logfile &&
224 args->log_file &&
225 strcmp(args->log_file, "none") == 0)
226 args->log_file = NULL;
227 break;
228 case 'q':
229 args->quiet = 1;
230 break;
231 case OPT_RCFILE:
232 args->rcfile = optarg;
233 break;
234 case 'P':
235 remove_trailing_slashes(optarg);
236 ret = lxc_arguments_lxcpath_add(args, optarg);
237 if (ret < 0)
238 return ret;
239 break;
240 case OPT_USAGE:
241 print_usage_exit(args->options, args);
242 case OPT_VERSION:
243 print_version_exit();
244 case '?':
245 print_help_exit(args, 1);
246 case 'h':
247 print_help_exit(args, 0);
248 default:
249 if (args->parser) {
250 ret = args->parser(args, c, optarg);
251 if (ret)
252 goto error;
253 }
254 }
255 }
256
257 /*
258 * Reclaim the remaining command arguments
259 */
260 args->argv = &argv[optind];
261 args->argc = argc - optind;
262
263 /* If no lxcpaths were given, use default */
264 if (!args->lxcpath_cnt) {
265 ret = lxc_arguments_lxcpath_add(
266 args, lxc_get_global_config_item("lxc.lxcpath"));
267 if (ret < 0)
268 return ret;
269 }
270
271 /* Check the command options */
272 if (!args->name && strncmp(args->progname, "lxc-autostart", strlen(args->progname)) != 0
273 && strncmp(args->progname, "lxc-unshare", strlen(args->progname)) != 0) {
274 if (args->argv) {
275 args->name = argv[optind];
276 optind++;
277 args->argv = &argv[optind];
278 args->argc = argc - optind;
279 }
280
281 if (!args->name) {
282 lxc_error(args, "No container name specified");
283 return -1;
284 }
285 }
286
287 if (args->checker)
288 ret = args->checker(args);
289
290 error:
291 if (ret)
292 lxc_error(args, "could not parse command line");
293
294 return ret;
295 }
296
297 int lxc_arguments_str_to_int(struct lxc_arguments *args, const char *str)
298 {
299 long val;
300 char *endptr;
301
302 errno = 0;
303 val = strtol(str, &endptr, 10);
304 if (errno) {
305 lxc_error(args, "invalid statefd '%s' : %s", str,
306 strerror(errno));
307 return -1;
308 }
309
310 if (*endptr) {
311 lxc_error(args, "invalid digit for statefd '%s'", str);
312 return -1;
313 }
314
315 return (int)val;
316 }
317
318 bool lxc_setup_shared_ns(struct lxc_arguments *args, struct lxc_container *c)
319 {
320 int i;
321
322 for (i = 0; i < LXC_NS_MAX; i++) {
323 const char *key, *value;
324
325 value = args->share_ns[i];
326 if (!value)
327 continue;
328
329 if (i == LXC_NS_NET)
330 key = "lxc.namespace.share.net";
331 else if (i == LXC_NS_IPC)
332 key = "lxc.namespace.share.ipc";
333 else if (i == LXC_NS_UTS)
334 key = "lxc.namespace.share.uts";
335 else if (i == LXC_NS_PID)
336 key = "lxc.namespace.share.pid";
337 else
338 continue;
339
340 if (!c->set_config_item(c, key, value)) {
341 lxc_error(args, "Failed to set \"%s = %s\"", key, value);
342 return false;
343 }
344 }
345
346 return true;
347 }