]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/tools/lxc_device.c
tree-wide: fix lxc header inclusion
[mirror_lxc.git] / src / lxc / tools / lxc_device.c
CommitLineData
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 21lxc_log_define(lxc_device, lxc);
22
23static bool is_interface(const char *dev_name, pid_t pid);
24
ea467969
DY
25static const struct option my_longopts[] = {
26 LXC_COMMON_OPTIONS
27};
28
29static struct lxc_arguments my_args = {
9fe16387 30 .progname = "lxc-device",
31 .help = "\
ea467969
DY
32--name=NAME -- add|del DEV\n\
33\n\
34lxc-device attach or detach DEV to or from container.\n\
35\n\
36Options :\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 46static 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
83int 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 172err:
9fe16387 173 lxc_container_put(c);
b52b0595 174 exit(EXIT_FAILURE);
ea467969 175}