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