]>
Commit | Line | Data |
---|---|---|
ea467969 DY |
1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * Authors: | |
5 | * Dongsheng Yang <yangds.fnst@cn.fujitsu.com> | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
23500ef5 CB |
21 | |
22 | #define _GNU_SOURCE | |
23 | #include <libgen.h> | |
24 | #include <limits.h> | |
ea467969 | 25 | #include <stdio.h> |
23500ef5 | 26 | #include <string.h> |
ea467969 DY |
27 | #include <unistd.h> |
28 | #include <sys/types.h> | |
ea467969 DY |
29 | |
30 | #include <lxc/lxccontainer.h> | |
31 | ||
ea467969 | 32 | #include "arguments.h" |
b1e44ed1 | 33 | #include "../../include/netns_ifaddrs.h" |
a9cb0fb8 | 34 | #include "log.h" |
35 | #include "utils.h" | |
36 | ||
9fe16387 | 37 | lxc_log_define(lxc_device, lxc); |
38 | ||
39 | static bool is_interface(const char *dev_name, pid_t pid); | |
40 | ||
ea467969 DY |
41 | static const struct option my_longopts[] = { |
42 | LXC_COMMON_OPTIONS | |
43 | }; | |
44 | ||
45 | static struct lxc_arguments my_args = { | |
9fe16387 | 46 | .progname = "lxc-device", |
47 | .help = "\ | |
ea467969 DY |
48 | --name=NAME -- add|del DEV\n\ |
49 | \n\ | |
50 | lxc-device attach or detach DEV to or from container.\n\ | |
51 | \n\ | |
52 | Options :\n\ | |
50b737a3 WB |
53 | -n, --name=NAME NAME of the container\n\ |
54 | --rcfile=FILE Load configuration file FILE\n", | |
9fe16387 | 55 | .options = my_longopts, |
56 | .parser = NULL, | |
57 | .checker = NULL, | |
58 | .log_priority = "ERROR", | |
59 | .log_file = "none", | |
ea467969 DY |
60 | }; |
61 | ||
a9cb0fb8 | 62 | static bool is_interface(const char *dev_name, pid_t pid) |
ea467969 DY |
63 | { |
64 | pid_t p = fork(); | |
ea467969 | 65 | if (p < 0) { |
80287d7d | 66 | ERROR("Failed to fork task"); |
f0c6ee28 | 67 | exit(EXIT_FAILURE); |
ea467969 DY |
68 | } |
69 | ||
70 | if (p == 0) { | |
b1e44ed1 | 71 | struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; |
ea467969 DY |
72 | |
73 | if (!switch_to_ns(pid, "net")) { | |
80287d7d | 74 | ERROR("Failed to enter netns of container"); |
a9cb0fb8 | 75 | _exit(-1); |
ea467969 DY |
76 | } |
77 | ||
78 | /* Grab the list of interfaces */ | |
b1e44ed1 | 79 | if (netns_getifaddrs(&interfaceArray, -1, &(bool){false})) { |
a9cb0fb8 | 80 | ERROR("Failed to get interfaces list"); |
81 | _exit(-1); | |
ea467969 DY |
82 | } |
83 | ||
84 | /* Iterate through the interfaces */ | |
85 | for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) { | |
80287d7d | 86 | if (strncmp(tempIfAddr->ifa_name, dev_name, strlen(tempIfAddr->ifa_name)) == 0) |
a9cb0fb8 | 87 | _exit(EXIT_SUCCESS); |
ea467969 | 88 | } |
a9cb0fb8 | 89 | |
90 | _exit(EXIT_FAILURE); | |
ea467969 DY |
91 | } |
92 | ||
a9cb0fb8 | 93 | if (wait_for_pid(p) == 0) |
ea467969 | 94 | return true; |
a9cb0fb8 | 95 | |
ea467969 DY |
96 | return false; |
97 | } | |
98 | ||
99 | int main(int argc, char *argv[]) | |
100 | { | |
101 | struct lxc_container *c; | |
73b910a3 | 102 | struct lxc_log log; |
ea467969 | 103 | char *cmd, *dev_name, *dst_name; |
30a5e436 | 104 | bool ret = false; |
ea467969 DY |
105 | |
106 | if (geteuid() != 0) { | |
a9cb0fb8 | 107 | ERROR("%s must be run as root", argv[0]); |
b52b0595 | 108 | exit(EXIT_FAILURE); |
ea467969 DY |
109 | } |
110 | ||
111 | if (lxc_arguments_parse(&my_args, argc, argv)) | |
9fe16387 | 112 | exit(EXIT_FAILURE); |
ea467969 | 113 | |
9fe16387 | 114 | log.name = my_args.name; |
115 | log.file = my_args.log_file; | |
116 | log.level = my_args.log_priority; | |
117 | log.prefix = my_args.progname; | |
118 | log.quiet = my_args.quiet; | |
119 | log.lxcpath = my_args.lxcpath[0]; | |
120 | ||
121 | if (lxc_log_init(&log)) | |
122 | exit(EXIT_FAILURE); | |
ea467969 DY |
123 | |
124 | c = lxc_container_new(my_args.name, my_args.lxcpath[0]); | |
125 | if (!c) { | |
a9cb0fb8 | 126 | ERROR("%s doesn't exist", my_args.name); |
9fe16387 | 127 | exit(EXIT_FAILURE); |
ea467969 DY |
128 | } |
129 | ||
50b737a3 WB |
130 | if (my_args.rcfile) { |
131 | c->clear_config(c); | |
a9cb0fb8 | 132 | |
50b737a3 | 133 | if (!c->load_config(c, my_args.rcfile)) { |
a9cb0fb8 | 134 | ERROR("Failed to load rcfile"); |
9fe16387 | 135 | goto err; |
50b737a3 | 136 | } |
a9cb0fb8 | 137 | |
6118210e WB |
138 | c->configfile = strdup(my_args.rcfile); |
139 | if (!c->configfile) { | |
a9cb0fb8 | 140 | ERROR("Out of memory setting new config filename"); |
9fe16387 | 141 | goto err; |
6118210e | 142 | } |
50b737a3 WB |
143 | } |
144 | ||
ea467969 | 145 | if (!c->is_running(c)) { |
80287d7d | 146 | ERROR("Container %s is not running", c->name); |
9fe16387 | 147 | goto err; |
ea467969 DY |
148 | } |
149 | ||
150 | if (my_args.argc < 2) { | |
a9cb0fb8 | 151 | ERROR("Error: no command given (Please see --help output)"); |
9fe16387 | 152 | goto err; |
ea467969 DY |
153 | } |
154 | ||
155 | cmd = my_args.argv[0]; | |
156 | dev_name = my_args.argv[1]; | |
9fe16387 | 157 | |
ea467969 DY |
158 | if (my_args.argc < 3) |
159 | dst_name = dev_name; | |
160 | else | |
161 | dst_name = my_args.argv[2]; | |
162 | ||
80287d7d | 163 | if (strncmp(cmd, "add", strlen(cmd)) == 0) { |
9fe16387 | 164 | if (is_interface(dev_name, 1)) |
ea467969 | 165 | ret = c->attach_interface(c, dev_name, dst_name); |
9fe16387 | 166 | else |
ea467969 | 167 | ret = c->add_device_node(c, dev_name, dst_name); |
ea467969 | 168 | if (ret != true) { |
80287d7d | 169 | ERROR("Failed to add %s to %s", dev_name, c->name); |
9fe16387 | 170 | goto err; |
ea467969 | 171 | } |
80287d7d | 172 | } else if (strncmp(cmd, "del", strlen(cmd)) == 0) { |
9fe16387 | 173 | if (is_interface(dev_name, c->init_pid(c))) |
ea467969 | 174 | ret = c->detach_interface(c, dev_name, dst_name); |
9fe16387 | 175 | else |
ea467969 | 176 | ret = c->remove_device_node(c, dev_name, dst_name); |
ea467969 | 177 | if (ret != true) { |
80287d7d | 178 | ERROR("Failed to del %s from %s", dev_name, c->name); |
9fe16387 | 179 | goto err; |
ea467969 | 180 | } |
ea467969 | 181 | } else { |
a9cb0fb8 | 182 | ERROR("Error: Please use add or del (Please see --help output)"); |
9fe16387 | 183 | goto err; |
ea467969 | 184 | } |
a9cb0fb8 | 185 | |
b52b0595 | 186 | exit(EXIT_SUCCESS); |
a9cb0fb8 | 187 | |
ea467969 | 188 | err: |
9fe16387 | 189 | lxc_container_put(c); |
b52b0595 | 190 | exit(EXIT_FAILURE); |
ea467969 | 191 | } |