]>
Commit | Line | Data |
---|---|---|
cc73685d | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
23500ef5 | 2 | |
d38dd64a CB |
3 | #ifndef _GNU_SOURCE |
4 | #define _GNU_SOURCE 1 | |
5 | #endif | |
23500ef5 CB |
6 | #include <libgen.h> |
7 | #include <limits.h> | |
ea467969 | 8 | #include <stdio.h> |
23500ef5 | 9 | #include <string.h> |
ea467969 | 10 | #include <sys/types.h> |
d38dd64a | 11 | #include <unistd.h> |
ea467969 | 12 | |
12ae2a33 | 13 | #include "lxc.h" |
ea467969 | 14 | |
58db1a61 | 15 | #include "netns_ifaddrs.h" |
d38dd64a CB |
16 | #include "arguments.h" |
17 | #include "config.h" | |
a9cb0fb8 | 18 | #include "log.h" |
19 | #include "utils.h" | |
20 | ||
9fe16387 | 21 | lxc_log_define(lxc_device, lxc); |
22 | ||
23 | static bool is_interface(const char *dev_name, pid_t pid); | |
24 | ||
ea467969 DY |
25 | static const struct option my_longopts[] = { |
26 | LXC_COMMON_OPTIONS | |
27 | }; | |
28 | ||
29 | static struct lxc_arguments my_args = { | |
9fe16387 | 30 | .progname = "lxc-device", |
31 | .help = "\ | |
ea467969 DY |
32 | --name=NAME -- add|del DEV\n\ |
33 | \n\ | |
34 | lxc-device attach or detach DEV to or from container.\n\ | |
35 | \n\ | |
36 | Options :\n\ | |
50b737a3 WB |
37 | -n, --name=NAME NAME of the container\n\ |
38 | --rcfile=FILE Load configuration file FILE\n", | |
9fe16387 | 39 | .options = my_longopts, |
40 | .parser = NULL, | |
41 | .checker = NULL, | |
42 | .log_priority = "ERROR", | |
43 | .log_file = "none", | |
ea467969 DY |
44 | }; |
45 | ||
a9cb0fb8 | 46 | static bool is_interface(const char *dev_name, pid_t pid) |
ea467969 DY |
47 | { |
48 | pid_t p = fork(); | |
ea467969 | 49 | if (p < 0) { |
80287d7d | 50 | ERROR("Failed to fork task"); |
f0c6ee28 | 51 | exit(EXIT_FAILURE); |
ea467969 DY |
52 | } |
53 | ||
54 | if (p == 0) { | |
b1e44ed1 | 55 | struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; |
ea467969 DY |
56 | |
57 | if (!switch_to_ns(pid, "net")) { | |
80287d7d | 58 | ERROR("Failed to enter netns of container"); |
a9cb0fb8 | 59 | _exit(-1); |
ea467969 DY |
60 | } |
61 | ||
62 | /* Grab the list of interfaces */ | |
b1e44ed1 | 63 | if (netns_getifaddrs(&interfaceArray, -1, &(bool){false})) { |
a9cb0fb8 | 64 | ERROR("Failed to get interfaces list"); |
65 | _exit(-1); | |
ea467969 DY |
66 | } |
67 | ||
68 | /* Iterate through the interfaces */ | |
69 | for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) { | |
80287d7d | 70 | if (strncmp(tempIfAddr->ifa_name, dev_name, strlen(tempIfAddr->ifa_name)) == 0) |
a9cb0fb8 | 71 | _exit(EXIT_SUCCESS); |
ea467969 | 72 | } |
a9cb0fb8 | 73 | |
74 | _exit(EXIT_FAILURE); | |
ea467969 DY |
75 | } |
76 | ||
a9cb0fb8 | 77 | if (wait_for_pid(p) == 0) |
ea467969 | 78 | return true; |
a9cb0fb8 | 79 | |
ea467969 DY |
80 | return false; |
81 | } | |
82 | ||
83 | int main(int argc, char *argv[]) | |
84 | { | |
85 | struct lxc_container *c; | |
73b910a3 | 86 | struct lxc_log log; |
ea467969 | 87 | char *cmd, *dev_name, *dst_name; |
30a5e436 | 88 | bool ret = false; |
ea467969 DY |
89 | |
90 | if (geteuid() != 0) { | |
a9cb0fb8 | 91 | ERROR("%s must be run as root", argv[0]); |
b52b0595 | 92 | exit(EXIT_FAILURE); |
ea467969 DY |
93 | } |
94 | ||
95 | if (lxc_arguments_parse(&my_args, argc, argv)) | |
9fe16387 | 96 | exit(EXIT_FAILURE); |
ea467969 | 97 | |
9fe16387 | 98 | log.name = my_args.name; |
99 | log.file = my_args.log_file; | |
100 | log.level = my_args.log_priority; | |
101 | log.prefix = my_args.progname; | |
102 | log.quiet = my_args.quiet; | |
103 | log.lxcpath = my_args.lxcpath[0]; | |
104 | ||
105 | if (lxc_log_init(&log)) | |
106 | exit(EXIT_FAILURE); | |
ea467969 DY |
107 | |
108 | c = lxc_container_new(my_args.name, my_args.lxcpath[0]); | |
109 | if (!c) { | |
a9cb0fb8 | 110 | ERROR("%s doesn't exist", my_args.name); |
9fe16387 | 111 | exit(EXIT_FAILURE); |
ea467969 DY |
112 | } |
113 | ||
50b737a3 WB |
114 | if (my_args.rcfile) { |
115 | c->clear_config(c); | |
a9cb0fb8 | 116 | |
50b737a3 | 117 | if (!c->load_config(c, my_args.rcfile)) { |
a9cb0fb8 | 118 | ERROR("Failed to load rcfile"); |
9fe16387 | 119 | goto err; |
50b737a3 | 120 | } |
a9cb0fb8 | 121 | |
6118210e WB |
122 | c->configfile = strdup(my_args.rcfile); |
123 | if (!c->configfile) { | |
a9cb0fb8 | 124 | ERROR("Out of memory setting new config filename"); |
9fe16387 | 125 | goto err; |
6118210e | 126 | } |
50b737a3 WB |
127 | } |
128 | ||
ea467969 | 129 | if (!c->is_running(c)) { |
80287d7d | 130 | ERROR("Container %s is not running", c->name); |
9fe16387 | 131 | goto err; |
ea467969 DY |
132 | } |
133 | ||
134 | if (my_args.argc < 2) { | |
a9cb0fb8 | 135 | ERROR("Error: no command given (Please see --help output)"); |
9fe16387 | 136 | goto err; |
ea467969 DY |
137 | } |
138 | ||
139 | cmd = my_args.argv[0]; | |
140 | dev_name = my_args.argv[1]; | |
9fe16387 | 141 | |
ea467969 DY |
142 | if (my_args.argc < 3) |
143 | dst_name = dev_name; | |
144 | else | |
145 | dst_name = my_args.argv[2]; | |
146 | ||
80287d7d | 147 | if (strncmp(cmd, "add", strlen(cmd)) == 0) { |
9fe16387 | 148 | if (is_interface(dev_name, 1)) |
ea467969 | 149 | ret = c->attach_interface(c, dev_name, dst_name); |
9fe16387 | 150 | else |
ea467969 | 151 | ret = c->add_device_node(c, dev_name, dst_name); |
ea467969 | 152 | if (ret != true) { |
80287d7d | 153 | ERROR("Failed to add %s to %s", dev_name, c->name); |
9fe16387 | 154 | goto err; |
ea467969 | 155 | } |
80287d7d | 156 | } else if (strncmp(cmd, "del", strlen(cmd)) == 0) { |
9fe16387 | 157 | if (is_interface(dev_name, c->init_pid(c))) |
ea467969 | 158 | ret = c->detach_interface(c, dev_name, dst_name); |
9fe16387 | 159 | else |
ea467969 | 160 | ret = c->remove_device_node(c, dev_name, dst_name); |
ea467969 | 161 | if (ret != true) { |
80287d7d | 162 | ERROR("Failed to del %s from %s", dev_name, c->name); |
9fe16387 | 163 | goto err; |
ea467969 | 164 | } |
ea467969 | 165 | } else { |
a9cb0fb8 | 166 | ERROR("Error: Please use add or del (Please see --help output)"); |
9fe16387 | 167 | goto err; |
ea467969 | 168 | } |
a9cb0fb8 | 169 | |
b52b0595 | 170 | exit(EXIT_SUCCESS); |
a9cb0fb8 | 171 | |
ea467969 | 172 | err: |
9fe16387 | 173 | lxc_container_put(c); |
b52b0595 | 174 | exit(EXIT_FAILURE); |
ea467969 | 175 | } |