]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipnetns.c
da019d76202294acba5dbfb42ac9462b1f4738f6
[mirror_iproute2.git] / ip / ipnetns.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #define _ATFILE_SOURCE
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <sys/wait.h>
6 #include <sys/inotify.h>
7 #include <sys/mount.h>
8 #include <sys/syscall.h>
9 #include <stdio.h>
10 #include <string.h>
11 #ifdef HAVE_LIBBSD
12 #include <bsd/string.h>
13 #endif
14 #include <sched.h>
15 #include <fcntl.h>
16 #include <dirent.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <ctype.h>
20 #include <linux/limits.h>
21
22 #include <linux/net_namespace.h>
23
24 #include "utils.h"
25 #include "list.h"
26 #include "ip_common.h"
27 #include "namespace.h"
28 #include "json_print.h"
29
30 static int usage(void)
31 {
32 fprintf(stderr, "Usage: ip netns list\n");
33 fprintf(stderr, " ip netns add NAME\n");
34 fprintf(stderr, " ip netns set NAME NETNSID\n");
35 fprintf(stderr, " ip [-all] netns delete [NAME]\n");
36 fprintf(stderr, " ip netns identify [PID]\n");
37 fprintf(stderr, " ip netns pids NAME\n");
38 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
39 fprintf(stderr, " ip netns monitor\n");
40 fprintf(stderr, " ip netns list-id\n");
41 exit(-1);
42 }
43
44 /* This socket is used to get nsid */
45 static struct rtnl_handle rtnsh = { .fd = -1 };
46
47 static int have_rtnl_getnsid = -1;
48
49 static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
50 struct nlmsghdr *n, void *arg)
51 {
52 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
53
54 if (n->nlmsg_type == NLMSG_ERROR &&
55 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
56 have_rtnl_getnsid = 0;
57 else
58 have_rtnl_getnsid = 1;
59 return -1;
60 }
61
62 static int ipnetns_have_nsid(void)
63 {
64 struct {
65 struct nlmsghdr n;
66 struct rtgenmsg g;
67 char buf[1024];
68 } req = {
69 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
70 .n.nlmsg_flags = NLM_F_REQUEST,
71 .n.nlmsg_type = RTM_GETNSID,
72 .g.rtgen_family = AF_UNSPEC,
73 };
74 int fd;
75
76 if (have_rtnl_getnsid < 0) {
77 fd = open("/proc/self/ns/net", O_RDONLY);
78 if (fd < 0) {
79 have_rtnl_getnsid = 0;
80 return 0;
81 }
82
83 addattr32(&req.n, 1024, NETNSA_FD, fd);
84
85 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
86 perror("request send failed");
87 exit(1);
88 }
89 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
90 close(fd);
91 }
92
93 return have_rtnl_getnsid;
94 }
95
96 int get_netnsid_from_name(const char *name)
97 {
98 struct {
99 struct nlmsghdr n;
100 struct rtgenmsg g;
101 char buf[1024];
102 } req = {
103 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
104 .n.nlmsg_flags = NLM_F_REQUEST,
105 .n.nlmsg_type = RTM_GETNSID,
106 .g.rtgen_family = AF_UNSPEC,
107 };
108 struct nlmsghdr *answer;
109 struct rtattr *tb[NETNSA_MAX + 1];
110 struct rtgenmsg *rthdr;
111 int len, fd;
112
113 netns_nsid_socket_init();
114
115 fd = netns_get_fd(name);
116 if (fd < 0)
117 return fd;
118
119 addattr32(&req.n, 1024, NETNSA_FD, fd);
120 if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
121 close(fd);
122 return -2;
123 }
124 close(fd);
125
126 /* Validate message and parse attributes */
127 if (answer->nlmsg_type == NLMSG_ERROR)
128 goto err_out;
129
130 rthdr = NLMSG_DATA(answer);
131 len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
132 if (len < 0)
133 goto err_out;
134
135 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
136
137 if (tb[NETNSA_NSID]) {
138 free(answer);
139 return rta_getattr_u32(tb[NETNSA_NSID]);
140 }
141
142 err_out:
143 free(answer);
144 return -1;
145 }
146
147 struct nsid_cache {
148 struct hlist_node nsid_hash;
149 struct hlist_node name_hash;
150 int nsid;
151 char name[0];
152 };
153
154 #define NSIDMAP_SIZE 128
155 #define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
156 #define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
157
158 static struct hlist_head nsid_head[NSIDMAP_SIZE];
159 static struct hlist_head name_head[NSIDMAP_SIZE];
160
161 static struct nsid_cache *netns_map_get_by_nsid(int nsid)
162 {
163 uint32_t h = NSID_HASH_NSID(nsid);
164 struct hlist_node *n;
165
166 hlist_for_each(n, &nsid_head[h]) {
167 struct nsid_cache *c = container_of(n, struct nsid_cache,
168 nsid_hash);
169 if (c->nsid == nsid)
170 return c;
171 }
172
173 return NULL;
174 }
175
176 char *get_name_from_nsid(int nsid)
177 {
178 struct nsid_cache *c;
179
180 netns_nsid_socket_init();
181 netns_map_init();
182
183 c = netns_map_get_by_nsid(nsid);
184 if (c)
185 return c->name;
186
187 return NULL;
188 }
189
190 static int netns_map_add(int nsid, const char *name)
191 {
192 struct nsid_cache *c;
193 uint32_t h;
194
195 if (netns_map_get_by_nsid(nsid) != NULL)
196 return -EEXIST;
197
198 c = malloc(sizeof(*c) + strlen(name) + 1);
199 if (c == NULL) {
200 perror("malloc");
201 return -ENOMEM;
202 }
203 c->nsid = nsid;
204 strcpy(c->name, name);
205
206 h = NSID_HASH_NSID(nsid);
207 hlist_add_head(&c->nsid_hash, &nsid_head[h]);
208
209 h = NSID_HASH_NAME(name);
210 hlist_add_head(&c->name_hash, &name_head[h]);
211
212 return 0;
213 }
214
215 static void netns_map_del(struct nsid_cache *c)
216 {
217 hlist_del(&c->name_hash);
218 hlist_del(&c->nsid_hash);
219 free(c);
220 }
221
222 void netns_nsid_socket_init(void)
223 {
224 if (rtnsh.fd > -1 || !ipnetns_have_nsid())
225 return;
226
227 if (rtnl_open(&rtnsh, 0) < 0) {
228 fprintf(stderr, "Cannot open rtnetlink\n");
229 exit(1);
230 }
231
232 }
233
234 void netns_map_init(void)
235 {
236 static int initialized;
237 struct dirent *entry;
238 DIR *dir;
239 int nsid;
240
241 if (initialized || !ipnetns_have_nsid())
242 return;
243
244 dir = opendir(NETNS_RUN_DIR);
245 if (!dir)
246 return;
247
248 while ((entry = readdir(dir)) != NULL) {
249 if (strcmp(entry->d_name, ".") == 0)
250 continue;
251 if (strcmp(entry->d_name, "..") == 0)
252 continue;
253 nsid = get_netnsid_from_name(entry->d_name);
254
255 if (nsid >= 0)
256 netns_map_add(nsid, entry->d_name);
257 }
258 closedir(dir);
259 initialized = 1;
260 }
261
262 static int netns_get_name(int nsid, char *name)
263 {
264 struct dirent *entry;
265 DIR *dir;
266 int id;
267
268 dir = opendir(NETNS_RUN_DIR);
269 if (!dir)
270 return -ENOENT;
271
272 while ((entry = readdir(dir)) != NULL) {
273 if (strcmp(entry->d_name, ".") == 0)
274 continue;
275 if (strcmp(entry->d_name, "..") == 0)
276 continue;
277 id = get_netnsid_from_name(entry->d_name);
278
279 if (nsid == id) {
280 strcpy(name, entry->d_name);
281 closedir(dir);
282 return 0;
283 }
284 }
285 closedir(dir);
286 return -ENOENT;
287 }
288
289 int print_nsid(struct nlmsghdr *n, void *arg)
290 {
291 struct rtgenmsg *rthdr = NLMSG_DATA(n);
292 struct rtattr *tb[NETNSA_MAX+1];
293 int len = n->nlmsg_len;
294 FILE *fp = (FILE *)arg;
295 struct nsid_cache *c;
296 char name[NAME_MAX];
297 int nsid;
298
299 if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
300 return 0;
301
302 len -= NLMSG_SPACE(sizeof(*rthdr));
303 if (len < 0) {
304 fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
305 __func__);
306 return -1;
307 }
308
309 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
310 if (tb[NETNSA_NSID] == NULL) {
311 fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
312 return -1;
313 }
314
315 open_json_object(NULL);
316 if (n->nlmsg_type == RTM_DELNSID)
317 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
318
319 nsid = rta_getattr_u32(tb[NETNSA_NSID]);
320 print_uint(PRINT_ANY, "nsid", "nsid %u ", nsid);
321
322 c = netns_map_get_by_nsid(nsid);
323 if (c != NULL) {
324 print_string(PRINT_ANY, "name",
325 "(iproute2 netns name: %s)", c->name);
326 netns_map_del(c);
327 }
328
329 /* During 'ip monitor nsid', no chance to have new nsid in cache. */
330 if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
331 if (netns_get_name(nsid, name) == 0) {
332 print_string(PRINT_ANY, "name",
333 "(iproute2 netns name: %s)", name);
334 netns_map_add(nsid, name);
335 }
336
337 print_string(PRINT_FP, NULL, "\n", NULL);
338 close_json_object();
339 fflush(fp);
340 return 0;
341 }
342
343 static int netns_list_id(int argc, char **argv)
344 {
345 if (!ipnetns_have_nsid()) {
346 fprintf(stderr,
347 "RTM_GETNSID is not supported by the kernel.\n");
348 return -ENOTSUP;
349 }
350
351 if (rtnl_nsiddump_req(&rth, AF_UNSPEC) < 0) {
352 perror("Cannot send dump request");
353 exit(1);
354 }
355
356 new_json_obj(json);
357 if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
358 delete_json_obj();
359 fprintf(stderr, "Dump terminated\n");
360 exit(1);
361 }
362 delete_json_obj();
363 return 0;
364 }
365
366 static int netns_list(int argc, char **argv)
367 {
368 struct dirent *entry;
369 DIR *dir;
370 int id;
371
372 dir = opendir(NETNS_RUN_DIR);
373 if (!dir)
374 return 0;
375
376 new_json_obj(json);
377 while ((entry = readdir(dir)) != NULL) {
378 if (strcmp(entry->d_name, ".") == 0)
379 continue;
380 if (strcmp(entry->d_name, "..") == 0)
381 continue;
382
383 open_json_object(NULL);
384 print_string(PRINT_ANY, "name",
385 "%s", entry->d_name);
386 if (ipnetns_have_nsid()) {
387 id = get_netnsid_from_name(entry->d_name);
388 if (id >= 0)
389 print_uint(PRINT_ANY, "id",
390 " (id: %d)", id);
391 }
392 print_string(PRINT_FP, NULL, "\n", NULL);
393 close_json_object();
394 }
395 closedir(dir);
396 delete_json_obj();
397 return 0;
398 }
399
400 static int on_netns_exec(char *nsname, void *arg)
401 {
402 char **argv = arg;
403
404 cmd_exec(argv[1], argv + 1, true);
405 return 0;
406 }
407
408 static int netns_exec(int argc, char **argv)
409 {
410 /* Setup the proper environment for apps that are not netns
411 * aware, and execute a program in that environment.
412 */
413 const char *cmd;
414
415 if (argc < 1 && !do_all) {
416 fprintf(stderr, "No netns name specified\n");
417 return -1;
418 }
419 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
420 fprintf(stderr, "No command specified\n");
421 return -1;
422 }
423
424 if (do_all)
425 return do_each_netns(on_netns_exec, --argv, 1);
426
427 if (netns_switch(argv[0]))
428 return -1;
429
430 /* we just changed namespaces. clear any vrf association
431 * with prior namespace before exec'ing command
432 */
433 vrf_reset();
434
435 /* ip must return the status of the child,
436 * but do_cmd() will add a minus to this,
437 * so let's add another one here to cancel it.
438 */
439 cmd = argv[1];
440 return -cmd_exec(cmd, argv + 1, !!batch_mode);
441 }
442
443 static int is_pid(const char *str)
444 {
445 int ch;
446
447 for (; (ch = *str); str++) {
448 if (!isdigit(ch))
449 return 0;
450 }
451 return 1;
452 }
453
454 static int netns_pids(int argc, char **argv)
455 {
456 const char *name;
457 char net_path[PATH_MAX];
458 int netns;
459 struct stat netst;
460 DIR *dir;
461 struct dirent *entry;
462
463 if (argc < 1) {
464 fprintf(stderr, "No netns name specified\n");
465 return -1;
466 }
467 if (argc > 1) {
468 fprintf(stderr, "extra arguments specified\n");
469 return -1;
470 }
471
472 name = argv[0];
473 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
474 netns = open(net_path, O_RDONLY);
475 if (netns < 0) {
476 fprintf(stderr, "Cannot open network namespace: %s\n",
477 strerror(errno));
478 return -1;
479 }
480 if (fstat(netns, &netst) < 0) {
481 fprintf(stderr, "Stat of netns failed: %s\n",
482 strerror(errno));
483 return -1;
484 }
485 dir = opendir("/proc/");
486 if (!dir) {
487 fprintf(stderr, "Open of /proc failed: %s\n",
488 strerror(errno));
489 return -1;
490 }
491 while ((entry = readdir(dir))) {
492 char pid_net_path[PATH_MAX];
493 struct stat st;
494
495 if (!is_pid(entry->d_name))
496 continue;
497 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
498 entry->d_name);
499 if (stat(pid_net_path, &st) != 0)
500 continue;
501 if ((st.st_dev == netst.st_dev) &&
502 (st.st_ino == netst.st_ino)) {
503 printf("%s\n", entry->d_name);
504 }
505 }
506 closedir(dir);
507 return 0;
508
509 }
510
511 int netns_identify_pid(const char *pidstr, char *name, int len)
512 {
513 char net_path[PATH_MAX];
514 int netns;
515 struct stat netst;
516 DIR *dir;
517 struct dirent *entry;
518
519 name[0] = '\0';
520
521 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
522 netns = open(net_path, O_RDONLY);
523 if (netns < 0) {
524 fprintf(stderr, "Cannot open network namespace: %s\n",
525 strerror(errno));
526 return -1;
527 }
528 if (fstat(netns, &netst) < 0) {
529 fprintf(stderr, "Stat of netns failed: %s\n",
530 strerror(errno));
531 return -1;
532 }
533 dir = opendir(NETNS_RUN_DIR);
534 if (!dir) {
535 /* Succeed treat a missing directory as an empty directory */
536 if (errno == ENOENT)
537 return 0;
538
539 fprintf(stderr, "Failed to open directory %s:%s\n",
540 NETNS_RUN_DIR, strerror(errno));
541 return -1;
542 }
543
544 while ((entry = readdir(dir))) {
545 char name_path[PATH_MAX];
546 struct stat st;
547
548 if (strcmp(entry->d_name, ".") == 0)
549 continue;
550 if (strcmp(entry->d_name, "..") == 0)
551 continue;
552
553 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
554 entry->d_name);
555
556 if (stat(name_path, &st) != 0)
557 continue;
558
559 if ((st.st_dev == netst.st_dev) &&
560 (st.st_ino == netst.st_ino)) {
561 strlcpy(name, entry->d_name, len);
562 }
563 }
564 closedir(dir);
565 return 0;
566
567 }
568
569 static int netns_identify(int argc, char **argv)
570 {
571 const char *pidstr;
572 char name[256];
573 int rc;
574
575 if (argc < 1) {
576 pidstr = "self";
577 } else if (argc > 1) {
578 fprintf(stderr, "extra arguments specified\n");
579 return -1;
580 } else {
581 pidstr = argv[0];
582 if (!is_pid(pidstr)) {
583 fprintf(stderr, "Specified string '%s' is not a pid\n",
584 pidstr);
585 return -1;
586 }
587 }
588
589 rc = netns_identify_pid(pidstr, name, sizeof(name));
590 if (!rc)
591 printf("%s\n", name);
592
593 return rc;
594 }
595
596 static int on_netns_del(char *nsname, void *arg)
597 {
598 char netns_path[PATH_MAX];
599
600 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
601 umount2(netns_path, MNT_DETACH);
602 if (unlink(netns_path) < 0) {
603 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
604 netns_path, strerror(errno));
605 return -1;
606 }
607 return 0;
608 }
609
610 static int netns_delete(int argc, char **argv)
611 {
612 if (argc < 1 && !do_all) {
613 fprintf(stderr, "No netns name specified\n");
614 return -1;
615 }
616
617 if (do_all)
618 return netns_foreach(on_netns_del, NULL);
619
620 return on_netns_del(argv[0], NULL);
621 }
622
623 static int create_netns_dir(void)
624 {
625 /* Create the base netns directory if it doesn't exist */
626 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
627 if (errno != EEXIST) {
628 fprintf(stderr, "mkdir %s failed: %s\n",
629 NETNS_RUN_DIR, strerror(errno));
630 return -1;
631 }
632 }
633
634 return 0;
635 }
636
637 static int netns_add(int argc, char **argv)
638 {
639 /* This function creates a new network namespace and
640 * a new mount namespace and bind them into a well known
641 * location in the filesystem based on the name provided.
642 *
643 * The mount namespace is created so that any necessary
644 * userspace tweaks like remounting /sys, or bind mounting
645 * a new /etc/resolv.conf can be shared between uers.
646 */
647 char netns_path[PATH_MAX];
648 const char *name;
649 int fd;
650 int made_netns_run_dir_mount = 0;
651
652 if (argc < 1) {
653 fprintf(stderr, "No netns name specified\n");
654 return -1;
655 }
656 name = argv[0];
657
658 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
659
660 if (create_netns_dir())
661 return -1;
662
663 /* Make it possible for network namespace mounts to propagate between
664 * mount namespaces. This makes it likely that a unmounting a network
665 * namespace file in one namespace will unmount the network namespace
666 * file in all namespaces allowing the network namespace to be freed
667 * sooner.
668 */
669 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
670 /* Fail unless we need to make the mount point */
671 if (errno != EINVAL || made_netns_run_dir_mount) {
672 fprintf(stderr, "mount --make-shared %s failed: %s\n",
673 NETNS_RUN_DIR, strerror(errno));
674 return -1;
675 }
676
677 /* Upgrade NETNS_RUN_DIR to a mount point */
678 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
679 fprintf(stderr, "mount --bind %s %s failed: %s\n",
680 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
681 return -1;
682 }
683 made_netns_run_dir_mount = 1;
684 }
685
686 /* Create the filesystem state */
687 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
688 if (fd < 0) {
689 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
690 netns_path, strerror(errno));
691 return -1;
692 }
693 close(fd);
694 if (unshare(CLONE_NEWNET) < 0) {
695 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
696 name, strerror(errno));
697 goto out_delete;
698 }
699
700 /* Bind the netns last so I can watch for it */
701 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
702 fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
703 netns_path, strerror(errno));
704 goto out_delete;
705 }
706 return 0;
707 out_delete:
708 netns_delete(argc, argv);
709 return -1;
710 }
711
712 int set_netnsid_from_name(const char *name, int nsid)
713 {
714 struct {
715 struct nlmsghdr n;
716 struct rtgenmsg g;
717 char buf[1024];
718 } req = {
719 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
720 .n.nlmsg_flags = NLM_F_REQUEST,
721 .n.nlmsg_type = RTM_NEWNSID,
722 .g.rtgen_family = AF_UNSPEC,
723 };
724 int fd, err = 0;
725
726 netns_nsid_socket_init();
727
728 fd = netns_get_fd(name);
729 if (fd < 0)
730 return fd;
731
732 addattr32(&req.n, 1024, NETNSA_FD, fd);
733 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
734 if (rtnl_talk(&rth, &req.n, NULL) < 0)
735 err = -2;
736
737 close(fd);
738 return err;
739 }
740
741 static int netns_set(int argc, char **argv)
742 {
743 char netns_path[PATH_MAX];
744 const char *name;
745 unsigned int nsid;
746 int netns;
747
748 if (argc < 1) {
749 fprintf(stderr, "No netns name specified\n");
750 return -1;
751 }
752 if (argc < 2) {
753 fprintf(stderr, "No nsid specified\n");
754 return -1;
755 }
756 name = argv[0];
757 /* If a negative nsid is specified the kernel will select the nsid. */
758 if (strcmp(argv[1], "auto") == 0)
759 nsid = -1;
760 else if (get_unsigned(&nsid, argv[1], 0))
761 invarg("Invalid \"netnsid\" value\n", argv[1]);
762
763 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
764 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
765 if (netns < 0) {
766 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
767 name, strerror(errno));
768 return -1;
769 }
770
771 return set_netnsid_from_name(name, nsid);
772 }
773
774 static int netns_monitor(int argc, char **argv)
775 {
776 char buf[4096];
777 struct inotify_event *event;
778 int fd;
779
780 fd = inotify_init();
781 if (fd < 0) {
782 fprintf(stderr, "inotify_init failed: %s\n",
783 strerror(errno));
784 return -1;
785 }
786
787 if (create_netns_dir())
788 return -1;
789
790 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
791 fprintf(stderr, "inotify_add_watch failed: %s\n",
792 strerror(errno));
793 return -1;
794 }
795 for (;;) {
796 ssize_t len = read(fd, buf, sizeof(buf));
797
798 if (len < 0) {
799 fprintf(stderr, "read failed: %s\n",
800 strerror(errno));
801 return -1;
802 }
803 for (event = (struct inotify_event *)buf;
804 (char *)event < &buf[len];
805 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
806 if (event->mask & IN_CREATE)
807 printf("add %s\n", event->name);
808 if (event->mask & IN_DELETE)
809 printf("delete %s\n", event->name);
810 }
811 }
812 return 0;
813 }
814
815 static int invalid_name(const char *name)
816 {
817 return !*name || strlen(name) > NAME_MAX ||
818 strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..");
819 }
820
821 int do_netns(int argc, char **argv)
822 {
823 netns_nsid_socket_init();
824
825 if (argc < 1) {
826 netns_map_init();
827 return netns_list(0, NULL);
828 }
829
830 if (argc > 1 && invalid_name(argv[1])) {
831 fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]);
832 exit(-1);
833 }
834
835 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
836 (matches(*argv, "lst") == 0)) {
837 netns_map_init();
838 return netns_list(argc-1, argv+1);
839 }
840
841 if ((matches(*argv, "list-id") == 0)) {
842 netns_map_init();
843 return netns_list_id(argc-1, argv+1);
844 }
845
846 if (matches(*argv, "help") == 0)
847 return usage();
848
849 if (matches(*argv, "add") == 0)
850 return netns_add(argc-1, argv+1);
851
852 if (matches(*argv, "set") == 0)
853 return netns_set(argc-1, argv+1);
854
855 if (matches(*argv, "delete") == 0)
856 return netns_delete(argc-1, argv+1);
857
858 if (matches(*argv, "identify") == 0)
859 return netns_identify(argc-1, argv+1);
860
861 if (matches(*argv, "pids") == 0)
862 return netns_pids(argc-1, argv+1);
863
864 if (matches(*argv, "exec") == 0)
865 return netns_exec(argc-1, argv+1);
866
867 if (matches(*argv, "monitor") == 0)
868 return netns_monitor(argc-1, argv+1);
869
870 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
871 exit(-1);
872 }