]> git.ipfire.org Git - thirdparty/util-linux.git/blame - tests/helpers/test_mkfds.c
tests: (mkfds) add ping and ping6 factories
[thirdparty/util-linux.git] / tests / helpers / test_mkfds.c
CommitLineData
fd81d3a5
MY
1/*
2 * test_lsfd - make various file descriptors
3 *
4 * Written by Masatake YAMATO <yamato@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
bce240a7 20#include <arpa/inet.h>
cb16b318 21#include <ctype.h>
5c265705 22#include <dirent.h>
031ff45c 23#include <errno.h>
d85c66d8 24#include <fcntl.h>
fd81d3a5 25#include <getopt.h>
bce240a7
MY
26#include <linux/if_ether.h>
27#include <linux/if_packet.h>
c5eb81b3 28#include <linux/sockios.h> /* SIOCGSKNS */
bce240a7 29#include <net/if.h>
20d97930
MY
30#include <netinet/in.h>
31#include <netinet/tcp.h>
55529a26 32#include <sched.h>
fd81d3a5
MY
33#include <signal.h>
34#include <stdbool.h>
35#include <stdio.h>
36#include <stdlib.h>
bce240a7 37#include <string.h>
4d51adc5 38#include <sys/inotify.h>
c5eb81b3 39#include <sys/ioctl.h>
bce240a7 40#include <sys/mman.h>
863a6544 41#include <sys/prctl.h>
caa97697 42#include <sys/select.h>
d827da23 43#include <sys/socket.h>
ba8c749f 44#include <sys/syscall.h>
fd81d3a5 45#include <sys/types.h>
d827da23 46#include <sys/un.h>
bce240a7 47#include <sys/user.h>
fd81d3a5
MY
48#include <unistd.h>
49
50#include "c.h"
51#include "nls.h"
13b7739a 52#include "xalloc.h"
fd81d3a5
MY
53
54#define _U_ __attribute__((__unused__))
55
ba8c749f
MY
56static int pidfd_open(pid_t pid, unsigned int flags);
57
fd81d3a5
MY
58static void __attribute__((__noreturn__)) usage(FILE *out, int status)
59{
60 fputs(USAGE_HEADER, out);
13b7739a 61 fprintf(out, _(" %s [options] FACTORY FD... [PARAM=VAL...]\n"), program_invocation_short_name);
fd81d3a5
MY
62
63 fputs(USAGE_OPTIONS, out);
4f3a2a77
MY
64 fputs(_(" -l, --list list available file descriptor factories and exit\n"), out);
65 fputs(_(" -I, --parameters <factory> list parameters the factory takes\n"), out);
66 fputs(_(" -r, --comm <name> rename self\n"), out);
67 fputs(_(" -q, --quiet don't print pid(s)\n"), out);
68 fputs(_(" -c, --dont-pause don't pause after making fd(s)\n"), out);
fd81d3a5
MY
69
70 fputs(USAGE_SEPARATOR, out);
71 fputs(_("Examples:\n"), out);
0dfd6614 72 fprintf(out, _("Using 3, open /etc/group:\n\n $ %s ro-regular-file 3 file=/etc/group\n\n"),
fd81d3a5 73 program_invocation_short_name);
0dfd6614 74 fprintf(out, _("Using 3 and 4, make a pipe:\n\n $ %s pipe-no-fork 3 4\n\n"),
fd81d3a5
MY
75 program_invocation_short_name);
76
77 exit(status);
78}
79
13b7739a
MY
80union value {
81 const char *string;
cb9c4cab 82 long integer;
e2475629 83 bool boolean;
13b7739a
MY
84};
85
86enum ptype {
87 PTYPE_STRING,
cb9c4cab 88 PTYPE_INTEGER,
e2475629 89 PTYPE_BOOLEAN,
13b7739a
MY
90};
91
92struct ptype_class {
93 const char *name;
94
95 /* Covert to a string representation.
96 * A caller must free the returned value with free(3) after using. */
97 char *(*sprint)(const union value *value);
98
99 /* Convert from a string. If ARG is NULL, use DEFV instead.
100 * A caller must free the returned value with the free method
101 * after using. */
102 union value (*read)(const char *arg, const union value *defv);
103
104 /* Free the value returned from the read method. */
105 void (*free)(union value value);
106};
107
108#define ARG_STRING(A) (A.v.string)
cb9c4cab 109#define ARG_INTEGER(A) (A.v.integer)
e2475629 110#define ARG_BOOLEAN(A) (A.v.boolean)
13b7739a
MY
111struct arg {
112 union value v;
113 void (*free)(union value value);
114};
115
116struct parameter {
117 const char *name;
118 const enum ptype type;
119 const char *desc;
120 union value defv; /* Default value */
121};
122
123static char *string_sprint(const union value *value)
124{
125 return xstrdup(value->string);
126}
127
128static union value string_read(const char *arg, const union value *defv)
129{
130 return (union value){ .string = xstrdup(arg?: defv->string) };
131}
132
133static void string_free(union value value)
134{
135 free((void *)value.string);
136}
137
cb9c4cab
MY
138static char *integer_sprint(const union value *value)
139{
140 char *str = NULL;
141 xasprintf(&str, "%ld", value->integer);
142 return str;
143}
144
145static union value integer_read(const char *arg, const union value *defv)
146{
147 char *ep;
148 union value r;
149
150 if (!arg)
151 return *defv;
152
153 errno = 0;
154 r.integer = strtol(arg, &ep, 10);
155 if (errno)
156 err(EXIT_FAILURE, _("fail to make a number from %s"), arg);
157 else if (*ep != '\0')
158 errx(EXIT_FAILURE, _("garbage at the end of number: %s"), arg);
159 return r;
160}
161
162static void integer_free(union value value _U_)
163{
164 /* Do nothing */
165}
166
e2475629
MY
167static char *boolean_sprint(const union value *value)
168{
169 return xstrdup(value->boolean? "true": "false");
170}
171
172static union value boolean_read(const char *arg, const union value *defv)
173{
174 union value r;
175
176 if (!arg)
177 return *defv;
178
179 if (strcasecmp(arg, "true") == 0
180 || strcmp(arg, "1") == 0
181 || strcasecmp(arg, "yes") == 0
182 || strcasecmp(arg, "y") == 0)
183 r.boolean = true;
184 else
185 r.boolean = false;
186 return r;
187}
188
189static void boolean_free(union value value _U_)
190{
191 /* Do nothing */
192}
cb9c4cab 193
13b7739a
MY
194struct ptype_class ptype_classes [] = {
195 [PTYPE_STRING] = {
196 .name = "string",
197 .sprint = string_sprint,
198 .read = string_read,
199 .free = string_free,
200 },
cb9c4cab
MY
201 [PTYPE_INTEGER] = {
202 .name = "integer",
203 .sprint = integer_sprint,
204 .read = integer_read,
205 .free = integer_free,
206 },
e2475629
MY
207 [PTYPE_BOOLEAN] = {
208 .name = "boolean",
209 .sprint = boolean_sprint,
210 .read = boolean_read,
211 .free = boolean_free,
212 },
13b7739a
MY
213};
214
ae9ff1cd
MY
215static struct arg decode_arg(const char *pname,
216 const struct parameter *parameters,
217 int argc, char **argv)
218{
219 char *v = NULL;
220 size_t len = strlen(pname);
221 const struct parameter *p = NULL;
222 struct arg arg;
223
224 while (parameters->name) {
225 if (strcmp(pname, parameters->name) == 0) {
226 p = parameters;
227 break;
228 }
229 parameters++;
230 }
231 if (p == NULL)
232 errx(EXIT_FAILURE, _("no such parameter: %s"), pname);
233
234 for (int i = 0; i < argc; i++) {
235 if (strncmp(pname, argv[i], len) == 0) {
236 v = argv[i] + len;
237 if (*v == '=') {
238 v++;
239 break;
240 } else if (*v == '\0')
241 errx(EXIT_FAILURE,
242 _("no value given for \"%s\" parameter"),
243 pname);
244 else
245 v = NULL;
246 }
247 }
248 arg.v = ptype_classes [p->type].read (v, &p->defv);
249 arg.free = ptype_classes [p->type].free;
250 return arg;
251}
252
253static void free_arg(struct arg *arg)
254{
255 arg->free(arg->v);
256}
257
fd81d3a5
MY
258struct fdesc {
259 int fd;
260 void (*close)(int, void *);
261 void *data;
262};
263
264struct factory {
265 const char *name; /* [-a-zA-Z0-9_]+ */
266 const char *desc;
267 bool priv; /* the root privilege is needed to make fd(s) */
d14e9efd 268#define MAX_N 5
fd81d3a5 269 int N; /* the number of fds this factory makes */
d14e9efd 270 int EX_N; /* fds made optionally */
67aab5a5
MY
271 void *(*make)(const struct factory *, struct fdesc[], int, char **);
272 void (*free)(const struct factory *, void *);
271bc510 273 void (*report)(const struct factory *, void *, FILE *);
13b7739a 274 const struct parameter * params;
fd81d3a5
MY
275};
276
277static void close_fdesc(int fd, void *data _U_)
278{
279 close(fd);
280}
281
67aab5a5
MY
282static void *open_ro_regular_file(const struct factory *factory, struct fdesc fdescs[],
283 int argc, char ** argv)
fd81d3a5 284{
ae9ff1cd 285 struct arg file = decode_arg("file", factory->params, argc, argv);
6d201bcb 286 struct arg offset = decode_arg("offset", factory->params, argc, argv);
fd81d3a5 287
ae9ff1cd 288 int fd = open(ARG_STRING(file), O_RDONLY);
fd81d3a5 289 if (fd < 0)
ae9ff1cd
MY
290 err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(file));
291 free_arg(&file);
fd81d3a5 292
6d201bcb
MY
293 if (ARG_INTEGER(offset) != 0) {
294 if (lseek(fd, (off_t)ARG_INTEGER(offset), SEEK_CUR) < 0) {
295 int e = errno;
296 close(fd);
297 errno = e;
298 err(EXIT_FAILURE, "failed to seek 0 -> %ld", ARG_INTEGER(offset));
299 }
300 }
301 free_arg(&offset);
302
3ebd5939
MY
303 if (fd != fdescs[0].fd) {
304 if (dup2(fd, fdescs[0].fd) < 0) {
305 int e = errno;
306 close(fd);
307 errno = e;
308 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
309 }
fd81d3a5 310 close(fd);
fd81d3a5
MY
311 }
312
313 fdescs[0] = (struct fdesc){
314 .fd = fdescs[0].fd,
315 .close = close_fdesc,
316 .data = NULL
317 };
67aab5a5
MY
318
319 return NULL;
fd81d3a5
MY
320}
321
67aab5a5
MY
322static void *make_pipe(const struct factory *factory, struct fdesc fdescs[],
323 int argc, char ** argv)
fd81d3a5
MY
324{
325 int pd[2];
d85c66d8
MY
326 int nonblock_flags[2] = {0, 0};
327 struct arg nonblock = decode_arg("nonblock", factory->params, argc, argv);
328 if (strlen(ARG_STRING(nonblock)) != 2) {
329 errx(EXIT_FAILURE, "string value for %s has unexpected length: %s",
330 "nonblock", ARG_STRING(nonblock));
331 }
332
9aa68bf4
MY
333 /* Make extra pipe descriptors for making pipe objects connected
334 * with fds more than 2.
335 * See https://github.com/util-linux/util-linux/pull/1622
336 * about the background of the requirement. */
337 struct arg rdup = decode_arg("rdup", factory->params, argc, argv);
338 struct arg wdup = decode_arg("wdup", factory->params, argc, argv);
339 int xpd[2];
340 xpd [0] = ARG_INTEGER(rdup);
341 xpd [1] = ARG_INTEGER(wdup);
342
d85c66d8
MY
343 for (int i = 0; i < 2; i++) {
344 if (ARG_STRING(nonblock)[i] == '-')
345 continue;
346 if ((i == 0 && ARG_STRING(nonblock)[i] == 'r')
347 || (i == 1 && ARG_STRING(nonblock)[i] == 'w'))
348 nonblock_flags[i] = 1;
349 else
350 errx(EXIT_FAILURE, "unexpected value %c for the %s fd of %s",
351 ARG_STRING(nonblock)[i],
352 (i == 0)? "read": "write",
353 "nonblock");
354 }
355 free_arg(&nonblock);
356
fd81d3a5
MY
357 if (pipe(pd) < 0)
358 err(EXIT_FAILURE, "failed to make pipe");
359
d85c66d8
MY
360 for (int i = 0; i < 2; i++) {
361 if (nonblock_flags[i]) {
362 int flags = fcntl(pd[i], F_GETFL);
363 if (fcntl(pd[i], F_SETFL, flags|O_NONBLOCK) < 0) {
364 int e = errno;
365 close(pd[0]);
366 close(pd[1]);
367 errno = e;
368 errx(EXIT_FAILURE, "failed to set NONBLOCK flag to the %s fd",
369 (i == 0)? "read": "write");
370 }
371 }
372 }
373
fd81d3a5 374 for (int i = 0; i < 2; i++) {
3ebd5939
MY
375 if (pd[i] != fdescs[i].fd) {
376 if (dup2(pd[i], fdescs[i].fd) < 0) {
377 int e = errno;
378 close(pd[0]);
379 close(pd[1]);
380 errno = e;
381 err(EXIT_FAILURE, "failed to dup %d -> %d",
382 pd[i], fdescs[i].fd);
383 }
384 close(pd[i]);
fd81d3a5
MY
385 }
386 fdescs[i] = (struct fdesc){
387 .fd = fdescs[i].fd,
388 .close = close_fdesc,
389 .data = NULL
390 };
391 }
9aa68bf4
MY
392
393 /* Make extra pipe descriptors. */
394 for (int i = 0; i < 2; i++) {
395 if (xpd[i] >= 0) {
396 if (dup2(fdescs[i].fd, xpd[i]) < 0) {
397 int e = errno;
398 close(fdescs[0].fd);
399 close(fdescs[1].fd);
400 if (i > 0 && xpd[0] >= 0)
401 close(xpd[0]);
402 errno = e;
403 err(EXIT_FAILURE, "failed to dup %d -> %d",
404 fdescs[i].fd, xpd[i]);
405 }
406 fdescs[i + 2] = (struct fdesc){
407 .fd = xpd[i],
408 .close = close_fdesc,
409 .data = NULL
410 };
411 }
412 }
67aab5a5
MY
413
414 return NULL;
fd81d3a5
MY
415}
416
5c265705
MY
417static void close_dir(int fd, void *data)
418{
419 DIR *dp = data;
420 if (dp)
421 closedir(dp);
422 else
423 close_fdesc(fd, NULL);
424}
425
67aab5a5
MY
426static void *open_directory(const struct factory *factory, struct fdesc fdescs[],
427 int argc, char ** argv)
77c70070 428{
8c670091 429 struct arg dir = decode_arg("dir", factory->params, argc, argv);
5c265705
MY
430 struct arg dentries = decode_arg("dentries", factory->params, argc, argv);
431 DIR *dp = NULL;
77c70070 432
8c670091 433 int fd = open(ARG_STRING(dir), O_RDONLY|O_DIRECTORY);
77c70070 434 if (fd < 0)
8c670091
MY
435 err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(dir));
436 free_arg(&dir);
77c70070 437
3ebd5939
MY
438 if (fd != fdescs[0].fd) {
439 if (dup2(fd, fdescs[0].fd) < 0) {
440 int e = errno;
441 close(fd);
442 errno = e;
443 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
444 }
77c70070 445 close(fd);
77c70070
MY
446 }
447
5c265705
MY
448 if (ARG_INTEGER(dentries) > 0) {
449 dp = fdopendir(fdescs[0].fd);
450 if (dp == NULL) {
451 int e = errno;
452 close(fdescs[0].fd);
453 errno = e;
454 err(EXIT_FAILURE, "failed to make DIR* from fd: %s", ARG_STRING(dir));
455 }
456 for (int i = 0; i < ARG_INTEGER(dentries); i++) {
457 struct dirent *d = readdir(dp);
458 if (!d) {
459 int e = errno;
460 closedir(dp);
461 errno = e;
462 err(EXIT_FAILURE, "failed in readdir(3)");
463 }
464 }
465 }
466 free_arg(&dentries);
467
77c70070
MY
468 fdescs[0] = (struct fdesc){
469 .fd = fdescs[0].fd,
5c265705
MY
470 .close = close_dir,
471 .data = dp
77c70070 472 };
67aab5a5
MY
473
474 return NULL;
77c70070
MY
475}
476
67aab5a5
MY
477static void *open_rw_chrdev(const struct factory *factory, struct fdesc fdescs[],
478 int argc, char ** argv)
7c06963e
MY
479{
480 struct arg chrdev = decode_arg("chrdev", factory->params, argc, argv);
481 int fd = open(ARG_STRING(chrdev), O_RDWR);
482 if (fd < 0)
483 err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(chrdev));
484 free_arg(&chrdev);
485
6a2c79e7
MY
486 if (fd != fdescs[0].fd) {
487 if (dup2(fd, fdescs[0].fd) < 0) {
488 int e = errno;
489 close(fd);
490 errno = e;
491 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
492 }
493 close(fd);
494 }
495
7c06963e 496 fdescs[0] = (struct fdesc){
6a2c79e7 497 .fd = fdescs[0].fd,
7c06963e
MY
498 .close = close_fdesc,
499 .data = NULL
500 };
67aab5a5
MY
501
502 return NULL;
7c06963e
MY
503}
504
67aab5a5
MY
505static void *make_socketpair(const struct factory *factory, struct fdesc fdescs[],
506 int argc, char ** argv)
d827da23
MY
507{
508 int sd[2];
509 struct arg socktype = decode_arg("socktype", factory->params, argc, argv);
510 int isocktype;
511 if (strcmp(ARG_STRING(socktype), "STREAM") == 0)
512 isocktype = SOCK_STREAM;
513 else if (strcmp(ARG_STRING(socktype), "DGRAM") == 0)
514 isocktype = SOCK_DGRAM;
515 else if (strcmp(ARG_STRING(socktype), "SEQPACKET") == 0)
516 isocktype = SOCK_SEQPACKET;
517 else
518 errx(EXIT_FAILURE,
519 "unknown socket type for socketpair(AF_UNIX,...): %s",
520 ARG_STRING(socktype));
521 free_arg(&socktype);
522
523 if (socketpair(AF_UNIX, isocktype, 0, sd) < 0)
524 err(EXIT_FAILURE, "failed to make socket pair");
525
526 for (int i = 0; i < 2; i++) {
3ebd5939
MY
527 if (sd[i] != fdescs[i].fd) {
528 if (dup2(sd[i], fdescs[i].fd) < 0) {
529 int e = errno;
530 close(sd[0]);
531 close(sd[1]);
532 errno = e;
533 err(EXIT_FAILURE, "failed to dup %d -> %d",
534 sd[i], fdescs[i].fd);
535 }
536 close(sd[i]);
d827da23
MY
537 }
538 fdescs[i] = (struct fdesc){
539 .fd = fdescs[i].fd,
540 .close = close_fdesc,
541 .data = NULL
542 };
543 }
67aab5a5
MY
544
545 return NULL;
d827da23
MY
546}
547
67aab5a5
MY
548static void *open_with_opath(const struct factory *factory, struct fdesc fdescs[],
549 int argc, char ** argv)
21c70c29
MY
550{
551 struct arg path = decode_arg("path", factory->params, argc, argv);
552 int fd = open(ARG_STRING(path), O_PATH|O_NOFOLLOW);
553 if (fd < 0)
554 err(EXIT_FAILURE, "failed to open with O_PATH: %s", ARG_STRING(path));
555 free_arg(&path);
556
6a2c79e7
MY
557 if (fd != fdescs[0].fd) {
558 if (dup2(fd, fdescs[0].fd) < 0) {
559 int e = errno;
560 close(fd);
561 errno = e;
562 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
563 }
564 close(fd);
565 }
566
21c70c29 567 fdescs[0] = (struct fdesc){
6a2c79e7 568 .fd = fdescs[0].fd,
21c70c29
MY
569 .close = close_fdesc,
570 .data = NULL
571 };
67aab5a5
MY
572
573 return NULL;
21c70c29
MY
574}
575
67aab5a5 576static void *open_ro_blkdev(const struct factory *factory, struct fdesc fdescs[],
cb16b318
MY
577 int argc, char ** argv)
578{
579 struct arg blkdev = decode_arg("blkdev", factory->params, argc, argv);
580 int fd = open(ARG_STRING(blkdev), O_RDONLY);
581 if (fd < 0)
582 err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(blkdev));
583 free_arg(&blkdev);
584
6a2c79e7
MY
585 if (fd != fdescs[0].fd) {
586 if (dup2(fd, fdescs[0].fd) < 0) {
587 int e = errno;
588 close(fd);
589 errno = e;
590 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
591 }
592 close(fd);
593 }
594
cb16b318 595 fdescs[0] = (struct fdesc){
6a2c79e7 596 .fd = fdescs[0].fd,
cb16b318
MY
597 .close = close_fdesc,
598 .data = NULL,
599 };
67aab5a5
MY
600
601 return NULL;
cb16b318
MY
602}
603
bce240a7
MY
604static int make_packet_socket(int socktype, const char *interface)
605{
606 int sd;
607 struct sockaddr_ll addr;
608
609 sd = socket(AF_PACKET, socktype, htons(ETH_P_ALL));
610 if (sd < 0)
611 err(EXIT_FAILURE, "failed to make a socket with AF_PACKET");
612
613 if (interface == NULL)
614 return sd; /* Just making a socket */
615
616 memset(&addr, 0, sizeof(struct sockaddr_ll));
617 addr.sll_family = AF_PACKET;
618 addr.sll_protocol = ETH_P_ALL;
619 addr.sll_ifindex = if_nametoindex(interface);
620 if (addr.sll_ifindex == 0) {
621 int e = errno;
622 close(sd);
623 errno = e;
624 err(EXIT_FAILURE,
625 "failed to get the interface index for %s", interface);
626 }
627 if (bind(sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll)) < 0) {
628 int e = errno;
629 close(sd);
630 errno = e;
631 err(EXIT_FAILURE,
632 "failed to get the interface index for %s", interface);
633 }
634
635 return sd;
636}
637
638struct munmap_data {
639 void *ptr;
640 size_t len;
641};
642
643static void close_fdesc_after_munmap(int fd, void *data)
644{
645 struct munmap_data *munmap_data = data;
646 munmap(munmap_data->ptr, munmap_data->len);
647 free(data);
648 close(fd);
649}
650
67aab5a5
MY
651static void *make_mmapped_packet_socket(const struct factory *factory, struct fdesc fdescs[],
652 int argc, char ** argv)
bce240a7
MY
653{
654 int sd;
655 struct arg socktype = decode_arg("socktype", factory->params, argc, argv);
656 struct arg interface = decode_arg("interface", factory->params, argc, argv);
657
658 int isocktype;
659 const char *sinterface;
660 struct tpacket_req req;
661 struct munmap_data *munmap_data;
662
663 if (strcmp(ARG_STRING(socktype), "DGRAM") == 0)
664 isocktype = SOCK_DGRAM;
665 else if (strcmp(ARG_STRING(socktype), "RAW") == 0)
666 isocktype = SOCK_RAW;
667 else
668 errx(EXIT_FAILURE,
669 "unknown socket type for socket(AF_PACKET,...): %s",
670 ARG_STRING(socktype));
671 free_arg(&socktype);
672
673 sinterface = ARG_STRING(interface);
674 sd = make_packet_socket(isocktype, sinterface);
675 free_arg(&interface);
676
677 /* Specify the spec of ring buffers.
678 *
679 * ref.
680 * - linux/Documentation/networking/packet_mmap.rst
681 * - https://sites.google.com/site/packetmmap/home
682 */
fbb894b2
KZ
683 req.tp_block_size = getpagesize();
684 req.tp_frame_size = getpagesize();
bce240a7
MY
685 req.tp_block_nr = 1;
686 req.tp_frame_nr = 1;
687 if (setsockopt(sd, SOL_PACKET, PACKET_TX_RING, (char *)&req, sizeof(req)) < 0) {
688 int e = errno;
689 close(sd);
690 errno = e;
691 err(EXIT_FAILURE, "failed to specify a buffer spec to a packet socket");
692 }
693
694 munmap_data = malloc(sizeof (*munmap_data));
695 if (munmap_data == NULL) {
696 close(sd);
697 errx(EXIT_FAILURE, "memory exhausted");
698 }
d244d77b 699 munmap_data->len = (size_t) req.tp_block_size * req.tp_block_nr;
bce240a7
MY
700 munmap_data->ptr = mmap(NULL, munmap_data->len, PROT_WRITE, MAP_SHARED, sd, 0);
701 if (munmap_data->ptr == MAP_FAILED) {
702 int e = errno;
703 close(sd);
704 free(munmap_data);
705 errno = e;
706 err(EXIT_FAILURE, "failed to do mmap a packet socket");
707 }
708
709 if (sd != fdescs[0].fd) {
710 if (dup2(sd, fdescs[0].fd) < 0) {
711 int e = errno;
712 close(sd);
713 munmap(munmap_data->ptr, munmap_data->len);
714 free(munmap_data);
715 errno = e;
716 err(EXIT_FAILURE, "failed to dup %d -> %d", sd, fdescs[0].fd);
717 }
718 close(sd);
719 }
720
721 fdescs[0] = (struct fdesc){
722 .fd = fdescs[0].fd,
723 .close = close_fdesc_after_munmap,
724 .data = munmap_data,
725 };
67aab5a5
MY
726
727 return NULL;
bce240a7
MY
728}
729
67aab5a5
MY
730static void *make_pidfd(const struct factory *factory, struct fdesc fdescs[],
731 int argc, char ** argv)
ba8c749f
MY
732{
733 struct arg target_pid = decode_arg("target-pid", factory->params, argc, argv);
734 pid_t pid = ARG_INTEGER(target_pid);
735
736 int fd = pidfd_open(pid, 0);
737 if (fd < 0)
738 err(EXIT_FAILURE, "failed in pidfd_open(%d)", (int)pid);
739 free_arg(&target_pid);
740
741 if (fd != fdescs[0].fd) {
742 if (dup2(fd, fdescs[0].fd) < 0) {
743 int e = errno;
744 close(fd);
745 errno = e;
746 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
747 }
748 close(fd);
749 }
750
751 fdescs[0] = (struct fdesc){
752 .fd = fdescs[0].fd,
753 .close = close_fdesc,
754 .data = NULL
755 };
67aab5a5
MY
756
757 return NULL;
ba8c749f
MY
758}
759
67aab5a5
MY
760static void *make_inotify_fd(const struct factory *factory _U_, struct fdesc fdescs[],
761 int argc _U_, char ** argv _U_)
4d51adc5
MY
762{
763 int fd = inotify_init();
764 if (fd < 0)
765 err(EXIT_FAILURE, "failed in inotify_init()");
766
767 if (fd != fdescs[0].fd) {
768 if (dup2(fd, fdescs[0].fd) < 0) {
769 int e = errno;
770 close(fd);
771 errno = e;
772 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
773 }
774 close(fd);
775 }
776
777 fdescs[0] = (struct fdesc){
778 .fd = fdescs[0].fd,
779 .close = close_fdesc,
780 .data = NULL
781 };
67aab5a5
MY
782
783 return NULL;
4d51adc5
MY
784}
785
a234bad9
MY
786static void close_unix_socket(int fd, void *data)
787{
788 char *path = data;
789 close(fd);
790 if (path) {
791 unlink(path);
792 free(path);
793 }
794}
795
223063b1
MY
796static void *make_unix_stream_core(const struct factory *factory, struct fdesc fdescs[],
797 int argc, char ** argv, int type, const char *typestr)
a234bad9
MY
798{
799 struct arg path = decode_arg("path", factory->params, argc, argv);
800 const char *spath = ARG_STRING(path);
801
802 struct arg backlog = decode_arg("backlog", factory->params, argc, argv);
803 int ibacklog = ARG_INTEGER(path);
804
805 struct arg abstract = decode_arg("abstract", factory->params, argc, argv);
806 bool babstract = ARG_BOOLEAN(abstract);
807
808 struct arg server_shutdown = decode_arg("server-shutdown", factory->params, argc, argv);
809 int iserver_shutdown = ARG_INTEGER(server_shutdown);
810 struct arg client_shutdown = decode_arg("client-shutdown", factory->params, argc, argv);
811 int iclient_shutdown = ARG_INTEGER(client_shutdown);
812
eca0c148 813 int ssd, csd, asd; /* server, client, and accepted socket descriptors */
a234bad9
MY
814 struct sockaddr_un un;
815 size_t un_len = sizeof(un);
816
817 memset(&un, 0, sizeof(un));
818 un.sun_family = AF_UNIX;
819 if (babstract) {
820 strncpy(un.sun_path + 1, spath, sizeof(un.sun_path) - 1 - 1);
821 size_t pathlen = strlen(spath);
822 if (sizeof(un.sun_path) - 1 > pathlen)
823 un_len = sizeof(un) - sizeof(un.sun_path) + 1 + pathlen;
824 } else
825 strncpy(un.sun_path, spath, sizeof(un.sun_path) - 1 );
826
827 free_arg(&client_shutdown);
828 free_arg(&server_shutdown);
829 free_arg(&abstract);
830 free_arg(&backlog);
831 free_arg(&path);
832
833 if (iserver_shutdown < 0 || iserver_shutdown > 3)
834 errx(EXIT_FAILURE, "the server shudown specification in unexpected range");
835 if (iclient_shutdown < 0 || iclient_shutdown > 3)
836 errx(EXIT_FAILURE, "the client shudown specification in unexpected range");
837
223063b1 838 ssd = socket(AF_UNIX, type, 0);
a234bad9
MY
839 if (ssd < 0)
840 err(EXIT_FAILURE,
223063b1 841 "failed to make a socket with AF_UNIX + SOCK_%s (server side)", typestr);
a234bad9
MY
842 if (ssd != fdescs[0].fd) {
843 if (dup2(ssd, fdescs[0].fd) < 0) {
844 int e = errno;
845 close(ssd);
846 errno = e;
847 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
848 }
849 close(ssd);
850 ssd = fdescs[0].fd;
851 }
852
853 fdescs[0] = (struct fdesc){
854 .fd = fdescs[0].fd,
855 .close = close_unix_socket,
856 .data = NULL,
857 };
858
859 if (!babstract)
860 unlink(un.sun_path);
861 if (bind(ssd, (const struct sockaddr *)&un, un_len) < 0) {
862 int e = errno;
863 close(ssd);
864 errno = e;
865 err(EXIT_FAILURE, "failed to bind a socket for listening");
866 }
867
868 if (!babstract)
869 fdescs[0].data = xstrdup(un.sun_path);
870 if (listen(ssd, ibacklog) < 0) {
871 int e = errno;
872 close_unix_socket(ssd, fdescs[0].data);
873 errno = e;
874 err(EXIT_FAILURE, "failed to listen a socket");
875 }
876
223063b1 877 csd = socket(AF_UNIX, type, 0);
a234bad9
MY
878 if (csd < 0)
879 err(EXIT_FAILURE,
223063b1 880 "failed to make a socket with AF_UNIX + SOCK_%s (client side)", typestr);
a234bad9
MY
881 if (csd != fdescs[1].fd) {
882 if (dup2(csd, fdescs[1].fd) < 0) {
883 int e = errno;
884 close(csd);
885 close_unix_socket(ssd, fdescs[0].data);
886 errno = e;
887 err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd);
888 }
889 close(csd);
890 csd = fdescs[1].fd;
891 }
892
893 fdescs[1] = (struct fdesc){
894 .fd = fdescs[1].fd,
895 .close = close_fdesc,
896 .data = NULL,
897 };
898
899 if (connect(csd, (const struct sockaddr *)&un, un_len) < 0) {
900 int e = errno;
901 close_fdesc(csd, NULL);
902 close_unix_socket(ssd, fdescs[0].data);
903 errno = e;
904 err(EXIT_FAILURE, "failed to connect a socket to the listening socket");
905 }
906
907 if (!babstract)
908 unlink(un.sun_path);
909
910 asd = accept(ssd, NULL, NULL);
911 if (asd < 0) {
912 int e = errno;
913 close_fdesc(csd, NULL);
914 close_unix_socket(ssd, fdescs[0].data);
915 errno = e;
916 err(EXIT_FAILURE, "failed to accept a socket from the listening socket");
917 }
918 if (asd != fdescs[2].fd) {
919 if (dup2(asd, fdescs[2].fd) < 0) {
920 int e = errno;
921 close(asd);
922 close_fdesc(csd, NULL);
923 close_unix_socket(ssd, fdescs[0].data);
924 errno = e;
925 err(EXIT_FAILURE, "failed to dup %d -> %d", asd, fdescs[2].fd);
926 }
927 close(asd);
928 asd = fdescs[2].fd;
929 }
930
931 if (iserver_shutdown & (1 << 0))
932 shutdown(asd, SHUT_RD);
933 if (iserver_shutdown & (1 << 1))
934 shutdown(asd, SHUT_WR);
935 if (iclient_shutdown & (1 << 0))
936 shutdown(csd, SHUT_RD);
937 if (iclient_shutdown & (1 << 1))
938 shutdown(csd, SHUT_WR);
939
940 return NULL;
941}
942
223063b1
MY
943static void *make_unix_stream(const struct factory *factory, struct fdesc fdescs[],
944 int argc, char ** argv)
945{
946 struct arg type = decode_arg("type", factory->params, argc, argv);
947 const char *stype = ARG_STRING(type);
948
949 int typesym;
950 const char *typestr;
951
952 if (strcmp(stype, "stream") == 0) {
953 typesym = SOCK_STREAM;
954 typestr = "STREAM";
955 } else if (strcmp(stype, "seqpacket") == 0) {
956 typesym = SOCK_SEQPACKET;
957 typestr = "SEQPACKET";
958 } else
959 errx(EXIT_FAILURE, _("unknown unix socket type: %s"), stype);
960
961 free_arg(&type);
962
963 return make_unix_stream_core(factory, fdescs, argc, argv, typesym, typestr);
964}
965
2229a4b4
MY
966static void *make_unix_dgram(const struct factory *factory, struct fdesc fdescs[],
967 int argc, char ** argv)
968{
969 struct arg path = decode_arg("path", factory->params, argc, argv);
970 const char *spath = ARG_STRING(path);
971
972 struct arg abstract = decode_arg("abstract", factory->params, argc, argv);
973 bool babstract = ARG_BOOLEAN(abstract);
974
975 int ssd, csd; /* server and client socket descriptors */
976
977 struct sockaddr_un un;
978 size_t un_len = sizeof(un);
979
980 memset(&un, 0, sizeof(un));
981 un.sun_family = AF_UNIX;
982 if (babstract) {
983 strncpy(un.sun_path + 1, spath, sizeof(un.sun_path) - 1 - 1);
984 size_t pathlen = strlen(spath);
985 if (sizeof(un.sun_path) - 1 > pathlen)
986 un_len = sizeof(un) - sizeof(un.sun_path) + 1 + pathlen;
987 } else
988 strncpy(un.sun_path, spath, sizeof(un.sun_path) - 1 );
989
990 free_arg(&abstract);
991 free_arg(&path);
992
993 ssd = socket(AF_UNIX, SOCK_DGRAM, 0);
994 if (ssd < 0)
995 err(EXIT_FAILURE,
996 "failed to make a socket with AF_UNIX + SOCK_DGRAM (server side)");
997 if (ssd != fdescs[0].fd) {
998 if (dup2(ssd, fdescs[0].fd) < 0) {
999 int e = errno;
1000 close(ssd);
1001 errno = e;
1002 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
1003 }
1004 close(ssd);
1005 ssd = fdescs[0].fd;
1006 }
1007
1008 fdescs[0] = (struct fdesc){
1009 .fd = fdescs[0].fd,
1010 .close = close_unix_socket,
1011 .data = NULL,
1012 };
1013
1014 if (!babstract)
1015 unlink(un.sun_path);
1016 if (bind(ssd, (const struct sockaddr *)&un, un_len) < 0) {
1017 int e = errno;
1018 close(ssd);
1019 errno = e;
1020 err(EXIT_FAILURE, "failed to bind a socket for server");
1021 }
1022
1023 if (!babstract)
1024 fdescs[0].data = xstrdup(un.sun_path);
1025 csd = socket(AF_UNIX, SOCK_DGRAM, 0);
1026 if (csd < 0)
1027 err(EXIT_FAILURE,
1028 "failed to make a socket with AF_UNIX + SOCK_DGRAM (client side)");
1029 if (csd != fdescs[1].fd) {
1030 if (dup2(csd, fdescs[1].fd) < 0) {
1031 int e = errno;
1032 close(csd);
1033 close_unix_socket(ssd, fdescs[0].data);
1034 errno = e;
1035 err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd);
1036 }
1037 close(csd);
1038 csd = fdescs[1].fd;
1039 }
1040
1041 fdescs[1] = (struct fdesc){
1042 .fd = fdescs[1].fd,
1043 .close = close_fdesc,
1044 .data = NULL,
1045 };
1046
1047 if (connect(csd, (const struct sockaddr *)&un, un_len) < 0) {
1048 int e = errno;
1049 close_fdesc(csd, NULL);
1050 close_unix_socket(ssd, fdescs[0].data);
1051 errno = e;
1052 err(EXIT_FAILURE, "failed to connect a socket to the server socket");
1053 }
1054
1055 if (!babstract)
1056 unlink(un.sun_path);
1057
1058 return NULL;
1059}
1060
55529a26
MY
1061static void *make_unix_in_new_netns(const struct factory *factory, struct fdesc fdescs[],
1062 int argc, char ** argv)
1063{
1064 struct arg type = decode_arg("type", factory->params, argc, argv);
1065 const char *stype = ARG_STRING(type);
1066
1067 struct arg path = decode_arg("path", factory->params, argc, argv);
1068 const char *spath = ARG_STRING(path);
1069
1070 struct arg abstract = decode_arg("abstract", factory->params, argc, argv);
1071 bool babstract = ARG_BOOLEAN(abstract);
1072
1073 int typesym;
1074 const char *typestr;
1075
1076 struct sockaddr_un un;
1077 size_t un_len = sizeof(un);
1078
1079 int self_netns, tmp_netns, sd;
1080
1081 if (strcmp(stype, "stream") == 0) {
1082 typesym = SOCK_STREAM;
1083 typestr = "STREAM";
1084 } else if (strcmp(stype, "seqpacket") == 0) {
1085 typesym = SOCK_SEQPACKET;
1086 typestr = "SEQPACKET";
1087 } else if (strcmp(stype, "dgram") == 0) {
1088 typesym = SOCK_DGRAM;
1089 typestr = "DGRAM";
1090 } else {
1091 free_arg(&abstract);
1092 free_arg(&path);
1093 free_arg(&type);
1094 errx(EXIT_FAILURE, _("unknown unix socket type: %s"), stype);
1095 }
1096
1097 memset(&un, 0, sizeof(un));
1098 un.sun_family = AF_UNIX;
1099 if (babstract) {
1100 strncpy(un.sun_path + 1, spath, sizeof(un.sun_path) - 1 - 1);
1101 size_t pathlen = strlen(spath);
1102 if (sizeof(un.sun_path) - 1 > pathlen)
1103 un_len = sizeof(un) - sizeof(un.sun_path) + 1 + pathlen;
1104 } else
1105 strncpy(un.sun_path, spath, sizeof(un.sun_path) - 1 );
1106
1107 free_arg(&abstract);
1108 free_arg(&path);
1109 free_arg(&type);
1110
1111 self_netns = open("/proc/self/ns/net", O_RDONLY);
1112 if (self_netns < 0)
1113 err(EXIT_FAILURE, _("failed to open /proc/self/ns/net"));
1114 if (self_netns != fdescs[0].fd) {
1115 if (dup2(self_netns, fdescs[0].fd) < 0) {
1116 int e = errno;
1117 close(self_netns);
1118 errno = e;
1119 err(EXIT_FAILURE, "failed to dup %d -> %d", self_netns, fdescs[0].fd);
1120 }
1121 close(self_netns);
1122 self_netns = fdescs[0].fd;
1123 }
1124
1125 fdescs[0] = (struct fdesc){
1126 .fd = fdescs[0].fd,
1127 .close = close_fdesc,
1128 .data = NULL,
1129 };
1130
1131 if (unshare(CLONE_NEWNET) < 0) {
1132 int e = errno;
1133 close_fdesc(self_netns, NULL);
1134 errno = e;
1135 err(EXIT_FAILURE, "failed in unshare");
1136 }
1137
1138 tmp_netns = open("/proc/self/ns/net", O_RDONLY);
1139 if (tmp_netns < 0) {
1140 int e = errno;
1141 close_fdesc(self_netns, NULL);
1142 errno = e;
1143 err(EXIT_FAILURE, _("failed to open /proc/self/ns/net for the new netns"));
1144 }
1145 if (tmp_netns != fdescs[1].fd) {
1146 if (dup2(tmp_netns, fdescs[1].fd) < 0) {
1147 int e = errno;
1148 close_fdesc(self_netns, NULL);
1149 close(tmp_netns);
1150 errno = e;
1151 err(EXIT_FAILURE, "failed to dup %d -> %d", tmp_netns, fdescs[1].fd);
1152 }
1153 close(tmp_netns);
1154 tmp_netns = fdescs[1].fd;
1155 }
1156
1157 fdescs[1] = (struct fdesc){
1158 .fd = fdescs[1].fd,
1159 .close = close_fdesc,
1160 .data = NULL,
1161 };
1162
1163 sd = socket(AF_UNIX, typesym, 0);
1164 if (sd < 0) {
1165 int e = errno;
1166 close_fdesc(self_netns, NULL);
1167 close_fdesc(tmp_netns, NULL);
1168 errno = e;
1169 err(EXIT_FAILURE,
1170 _("failed to make a socket with AF_UNIX + SOCK_%s"),
1171 typestr);
1172 }
1173
1174 if (sd != fdescs[2].fd) {
1175 if (dup2(sd, fdescs[2].fd) < 0) {
1176 int e = errno;
1177 close_fdesc(self_netns, NULL);
1178 close_fdesc(tmp_netns, NULL);
1179 close(sd);
1180 errno = e;
1181 err(EXIT_FAILURE, "failed to dup %d -> %d", sd, fdescs[2].fd);
1182 }
1183 close(sd);
1184 sd = fdescs[2].fd;
1185 }
1186
1187 fdescs[2] = (struct fdesc){
1188 .fd = fdescs[2].fd,
1189 .close = close_unix_socket,
1190 .data = NULL,
1191 };
1192
1193 if (!babstract)
1194 unlink(un.sun_path);
1195 if (bind(sd, (const struct sockaddr *)&un, un_len) < 0) {
1196 int e = errno;
1197 close_fdesc(self_netns, NULL);
1198 close_fdesc(tmp_netns, NULL);
1199 close_unix_socket(sd, NULL);
1200 errno = e;
1201 err(EXIT_FAILURE, "failed to bind a socket");
1202 }
1203
1204 if (!babstract)
1205 fdescs[2].data = xstrdup(un.sun_path);
1206
1207 if (typesym != SOCK_DGRAM) {
1208 if (listen(sd, 1) < 0) {
1209 int e = errno;
1210 close_fdesc(self_netns, NULL);
1211 close_fdesc(tmp_netns, NULL);
1212 close_unix_socket(sd, fdescs[2].data);
1213 errno = e;
1214 err(EXIT_FAILURE, "failed to listen a socket");
1215 }
1216 }
1217
1218 if (setns(self_netns, CLONE_NEWNET) < 0) {
1219 int e = errno;
1220 close_fdesc(self_netns, NULL);
1221 close_fdesc(tmp_netns, NULL);
1222 close_unix_socket(sd, fdescs[2].data);
1223 errno = e;
1224 err(EXIT_FAILURE, "failed to swich back to the original net namespace");
1225 }
1226
1227 return NULL;
1228}
1229
ca517a11
MY
1230static void *make_tcp_common(const struct factory *factory, struct fdesc fdescs[],
1231 int argc, char ** argv,
1232 int family,
1233 void (*init_addr)(struct sockaddr *, unsigned short),
1234 size_t addr_size,
1235 struct sockaddr * sin, struct sockaddr * cin)
20d97930
MY
1236{
1237 struct arg server_port = decode_arg("server-port", factory->params, argc, argv);
1238 unsigned short iserver_port = (unsigned short)ARG_INTEGER(server_port);
1239 struct arg client_port = decode_arg("client-port", factory->params, argc, argv);
1240 unsigned short iclient_port = (unsigned short)ARG_INTEGER(client_port);
1241
20d97930
MY
1242 int ssd, csd, asd;
1243
1244 const int y = 1;
1245
1246 free_arg(&server_port);
1247 free_arg(&client_port);
1248
ca517a11 1249 ssd = socket(family, SOCK_STREAM, 0);
20d97930
MY
1250 if (ssd < 0)
1251 err(EXIT_FAILURE,
1252 _("failed to make a tcp socket for listening"));
1253
1254 if (setsockopt(ssd, SOL_SOCKET,
1255 SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) {
1256 int e = errno;
1257 close(ssd);
1258 errno = e;
1259 err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)");
1260 }
1261
1262 if (ssd != fdescs[0].fd) {
1263 if (dup2(ssd, fdescs[0].fd) < 0) {
1264 int e = errno;
1265 close(ssd);
1266 errno = e;
1267 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
1268 }
1269 close(ssd);
1270 ssd = fdescs[0].fd;
1271 }
1272
ca517a11
MY
1273 init_addr(sin, iserver_port);
1274 if (bind(ssd, sin, addr_size) < 0) {
20d97930
MY
1275 int e = errno;
1276 close(ssd);
1277 errno = e;
1278 err(EXIT_FAILURE, "failed to bind a listening socket");
1279 }
1280
1281 if (listen(ssd, 1) < 0) {
1282 int e = errno;
1283 close(ssd);
1284 errno = e;
1285 err(EXIT_FAILURE, "failed to listen a socket");
1286 }
1287
ca517a11 1288 csd = socket(family, SOCK_STREAM, 0);
20d97930
MY
1289 if (csd < 0) {
1290 int e = errno;
1291 close(ssd);
1292 errno = e;
1293 err(EXIT_FAILURE,
1294 _("failed to make a tcp client socket"));
1295 }
1296
1297 if (setsockopt(csd, SOL_SOCKET,
1298 SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) {
1299 int e = errno;
1300 close(ssd);
1301 close(csd);
1302 errno = e;
1303 err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)");
1304 }
1305
1306 if (csd != fdescs[1].fd) {
1307 if (dup2(csd, fdescs[1].fd) < 0) {
1308 int e = errno;
1309 close(ssd);
1310 close(csd);
1311 errno = e;
1312 err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd);
1313 }
1314 close(csd);
1315 csd = fdescs[1].fd;
1316 }
1317
ca517a11
MY
1318 init_addr(cin, iclient_port);
1319 if (bind(csd, cin, addr_size) < 0) {
20d97930
MY
1320 int e = errno;
1321 close(ssd);
1322 close(csd);
1323 errno = e;
1324 err(EXIT_FAILURE, "failed to bind a client socket");
1325 }
1326
ca517a11 1327 if (connect(csd, sin, addr_size) < 0) {
20d97930
MY
1328 int e = errno;
1329 close(ssd);
1330 close(csd);
1331 errno = e;
d8c6094f 1332 err(EXIT_FAILURE, "failed to connect a client socket to the server socket");
20d97930
MY
1333 }
1334
1335 asd = accept(ssd, NULL, NULL);
1336 if (asd < 0) {
1337 int e = errno;
1338 close(ssd);
1339 close(csd);
1340 errno = e;
1341 err(EXIT_FAILURE, "failed to accept a socket from the listening socket");
1342 }
1343 if (asd != fdescs[2].fd) {
1344 if (dup2(asd, fdescs[2].fd) < 0) {
1345 int e = errno;
1346 close(ssd);
1347 close(csd);
1348 errno = e;
1349 err(EXIT_FAILURE, "failed to dup %d -> %d", asd, fdescs[2].fd);
1350 }
1351 close(asd);
1352 asd = fdescs[2].fd;
1353 }
1354
1355 fdescs[0] = (struct fdesc) {
1356 .fd = fdescs[0].fd,
1357 .close = close_fdesc,
1358 .data = NULL,
1359 };
1360 fdescs[1] = (struct fdesc) {
1361 .fd = fdescs[1].fd,
1362 .close = close_fdesc,
1363 .data = NULL,
1364 };
1365 fdescs[2] = (struct fdesc) {
1366 .fd = fdescs[2].fd,
1367 .close = close_fdesc,
1368 .data = NULL,
1369 };
1370
1371 return NULL;
1372}
1373
ca517a11
MY
1374static void tcp_init_addr(struct sockaddr *addr, unsigned short port)
1375{
1376 struct sockaddr_in *in = (struct sockaddr_in *)addr;
1377 memset(in, 0, sizeof(*in));
1378 in->sin_family = AF_INET;
1379 in->sin_port = htons(port);
1380 in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1381}
1382
1383static void *make_tcp(const struct factory *factory, struct fdesc fdescs[],
1384 int argc, char ** argv)
1385{
1386 struct sockaddr_in sin, cin;
1387 return make_tcp_common(factory, fdescs, argc, argv,
1388 AF_INET,
1389 tcp_init_addr, sizeof(sin),
1390 (struct sockaddr *)&sin, (struct sockaddr *)&cin);
1391}
1392
e568c794
MY
1393static void *make_udp_common(const struct factory *factory, struct fdesc fdescs[],
1394 int argc, char ** argv,
1395 int family,
1396 void (*init_addr)(struct sockaddr *, unsigned short),
1397 size_t addr_size,
1398 struct sockaddr * sin, struct sockaddr * cin)
abefebd7 1399{
6c9e370e
MY
1400 struct arg lite = decode_arg("lite", factory->params, argc, argv);
1401 bool blite = ARG_BOOLEAN(lite);
1402
abefebd7
MY
1403 struct arg server_port = decode_arg("server-port", factory->params, argc, argv);
1404 unsigned short iserver_port = (unsigned short)ARG_INTEGER(server_port);
1405 struct arg client_port = decode_arg("client-port", factory->params, argc, argv);
1406 unsigned short iclient_port = (unsigned short)ARG_INTEGER(client_port);
1407
1408 struct arg server_do_bind = decode_arg("server-do-bind", factory->params, argc, argv);
1409 bool bserver_do_bind = ARG_BOOLEAN(server_do_bind);
1410 struct arg client_do_bind = decode_arg("client-do-bind", factory->params, argc, argv);
1411 bool bclient_do_bind = ARG_BOOLEAN(client_do_bind);
1412 struct arg client_do_connect = decode_arg("client-do-connect", factory->params, argc, argv);
1413 bool bclient_do_connect = ARG_BOOLEAN(client_do_connect);
1414
abefebd7
MY
1415 int ssd, csd;
1416
1417 const int y = 1;
1418
1419 free_arg(&client_do_connect);
1420 free_arg(&client_do_bind);
1421 free_arg(&server_do_bind);
1422 free_arg(&server_port);
1423 free_arg(&client_port);
6c9e370e 1424 free_arg(&lite);
abefebd7 1425
6c9e370e 1426 ssd = socket(family, SOCK_DGRAM, blite? IPPROTO_UDPLITE: 0);
abefebd7
MY
1427 if (ssd < 0)
1428 err(EXIT_FAILURE,
1429 _("failed to make a udp socket for server"));
1430
1431 if (setsockopt(ssd, SOL_SOCKET,
1432 SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) {
1433 int e = errno;
1434 close(ssd);
1435 errno = e;
1436 err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)");
1437 }
1438
1439 if (ssd != fdescs[0].fd) {
1440 if (dup2(ssd, fdescs[0].fd) < 0) {
1441 int e = errno;
1442 close(ssd);
1443 errno = e;
1444 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
1445 }
1446 close(ssd);
1447 ssd = fdescs[0].fd;
1448 }
1449
e568c794 1450 init_addr(sin, iserver_port);
abefebd7 1451 if (bserver_do_bind) {
e568c794 1452 if (bind(ssd, sin, addr_size) < 0) {
abefebd7
MY
1453 int e = errno;
1454 close(ssd);
1455 errno = e;
d8c6094f 1456 err(EXIT_FAILURE, "failed to bind a server socket");
abefebd7
MY
1457 }
1458 }
1459
6c9e370e 1460 csd = socket(family, SOCK_DGRAM, blite? IPPROTO_UDPLITE: 0);
abefebd7
MY
1461 if (csd < 0) {
1462 int e = errno;
1463 close(ssd);
1464 errno = e;
1465 err(EXIT_FAILURE,
1466 _("failed to make a udp client socket"));
1467 }
1468
1469 if (setsockopt(csd, SOL_SOCKET,
1470 SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) {
1471 int e = errno;
1472 close(ssd);
1473 close(csd);
1474 errno = e;
1475 err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)");
1476 }
1477
1478 if (csd != fdescs[1].fd) {
1479 if (dup2(csd, fdescs[1].fd) < 0) {
1480 int e = errno;
1481 close(ssd);
1482 close(csd);
1483 errno = e;
1484 err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd);
1485 }
1486 close(csd);
1487 csd = fdescs[1].fd;
1488 }
1489
1490 if (bclient_do_bind) {
e568c794
MY
1491 init_addr(cin, iclient_port);
1492 if (bind(csd, cin, addr_size) < 0) {
abefebd7
MY
1493 int e = errno;
1494 close(ssd);
1495 close(csd);
1496 errno = e;
1497 err(EXIT_FAILURE, "failed to bind a client socket");
1498 }
1499 }
1500
1501 if (bclient_do_connect) {
e568c794 1502 if (connect(csd, sin, addr_size) < 0) {
abefebd7
MY
1503 int e = errno;
1504 close(ssd);
1505 close(csd);
1506 errno = e;
d8c6094f 1507 err(EXIT_FAILURE, "failed to connect a client socket to the server socket");
abefebd7
MY
1508 }
1509 }
1510
1511 fdescs[0] = (struct fdesc) {
1512 .fd = fdescs[0].fd,
1513 .close = close_fdesc,
1514 .data = NULL,
1515 };
1516 fdescs[1] = (struct fdesc) {
1517 .fd = fdescs[1].fd,
1518 .close = close_fdesc,
1519 .data = NULL,
1520 };
1521
1522 return NULL;
1523}
1524
e568c794
MY
1525static void *make_udp(const struct factory *factory, struct fdesc fdescs[],
1526 int argc, char ** argv)
1527{
1528 struct sockaddr_in sin, cin;
1529 return make_udp_common(factory, fdescs, argc, argv,
1530 AF_INET,
1531 tcp_init_addr, sizeof(sin),
1532 (struct sockaddr *)&sin, (struct sockaddr *)&cin);
1533}
1534
0e07fc2d
MY
1535static void *make_raw_common(const struct factory *factory, struct fdesc fdescs[],
1536 int argc, char ** argv,
1537 int family,
1538 void (*init_addr)(struct sockaddr *, bool),
1539 size_t addr_size,
1540 struct sockaddr * sin)
0188afb3
MY
1541{
1542 struct arg protocol = decode_arg("protocol", factory->params, argc, argv);
1543 int iprotocol = ARG_INTEGER(protocol);
1544 int ssd;
0188afb3
MY
1545
1546 free_arg(&protocol);
1547
0e07fc2d 1548 ssd = socket(family, SOCK_RAW, iprotocol);
0188afb3
MY
1549 if (ssd < 0)
1550 err(EXIT_FAILURE,
1551 _("failed to make a udp socket for server"));
1552
1553 if (ssd != fdescs[0].fd) {
1554 if (dup2(ssd, fdescs[0].fd) < 0) {
1555 int e = errno;
1556 close(ssd);
1557 errno = e;
1558 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
1559 }
1560 close(ssd);
1561 ssd = fdescs[0].fd;
1562 }
1563
0e07fc2d
MY
1564 init_addr(sin, false);
1565 if (bind(ssd, sin, addr_size) < 0) {
0188afb3
MY
1566 int e = errno;
1567 close(ssd);
1568 errno = e;
1569 err(EXIT_FAILURE, "failed in bind(2)");
1570 }
1571
0e07fc2d
MY
1572 init_addr(sin, true);
1573 if (connect(ssd, sin, addr_size) < 0) {
0188afb3
MY
1574 int e = errno;
1575 close(ssd);
1576 errno = e;
1577 err(EXIT_FAILURE, "failed in connect(2)");
1578 }
1579
1580 fdescs[0] = (struct fdesc) {
1581 .fd = fdescs[0].fd,
1582 .close = close_fdesc,
1583 .data = NULL,
1584 };
1585
1586 return NULL;
1587}
1588
0e07fc2d
MY
1589static void raw_init_addr(struct sockaddr * addr, bool remote_addr)
1590{
1591 struct sockaddr_in *in = (struct sockaddr_in *)addr;
1592 memset(in, 0, sizeof(*in));
1593 in->sin_family = AF_INET;
1594 in->sin_addr.s_addr = htonl(INADDR_LOOPBACK + (remote_addr? 1: 0));
1595}
1596
1597static void *make_raw(const struct factory *factory, struct fdesc fdescs[],
1598 int argc, char ** argv)
1599{
1600 struct sockaddr_in sin;
1601 return make_raw_common(factory, fdescs, argc, argv,
1602 AF_INET,
1603 raw_init_addr, sizeof(sin),
1604 (struct sockaddr *)&sin);
1605}
1606
00a97611
MY
1607static void *make_ping_common(const struct factory *factory, struct fdesc fdescs[],
1608 int argc, char ** argv,
1609 int family, int protocol,
1610 void (*init_addr)(struct sockaddr *, unsigned short),
1611 size_t addr_size,
1612 struct sockaddr *sin)
1613{
1614 struct arg connect_ = decode_arg("connect", factory->params, argc, argv);
1615 bool bconnect = ARG_BOOLEAN(connect_);
1616
1617 struct arg bind_ = decode_arg("bind", factory->params, argc, argv);
1618 bool bbind = ARG_BOOLEAN(bind_);
1619
1620 struct arg id = decode_arg("id", factory->params, argc, argv);
1621 unsigned short iid = (unsigned short)ARG_INTEGER(id);
1622
1623 int sd;
1624
1625 free_arg(&id);
1626 free_arg(&bind_);
1627 free_arg(&connect_);
1628
1629 sd = socket(family, SOCK_DGRAM, protocol);
1630 if (sd < 0)
1631 err(EXIT_FAILURE,
1632 _("failed to make an icmp socket"));
1633
1634 if (sd != fdescs[0].fd) {
1635 if (dup2(sd, fdescs[0].fd) < 0) {
1636 int e = errno;
1637 close(sd);
1638 errno = e;
1639 err(EXIT_FAILURE, "failed to dup %d -> %d", sd, fdescs[0].fd);
1640 }
1641 close(sd);
1642 sd = fdescs[0].fd;
1643 }
1644
1645 if (bbind) {
1646 init_addr(sin, iid);
1647 if (bind(sd, sin, addr_size) < 0) {
1648 int e = errno;
1649 close(sd);
1650 errno = e;
1651 err(EXIT_FAILURE, "failed in bind(2)");
1652 }
1653 }
1654
1655 if (bconnect) {
1656 init_addr(sin, 0);
1657 if (connect(sd, sin, addr_size) < 0) {
1658 int e = errno;
1659 close(sd);
1660 errno = e;
1661 err(EXIT_FAILURE, "failed in connect(2)");
1662 }
1663 }
1664
1665 fdescs[0] = (struct fdesc) {
1666 .fd = fdescs[0].fd,
1667 .close = close_fdesc,
1668 .data = NULL,
1669 };
1670
1671 return NULL;
1672}
1673
1674static void ping_init_addr(struct sockaddr *addr, unsigned short id)
1675{
1676 struct sockaddr_in *in = (struct sockaddr_in *)addr;
1677 memset(in, 0, sizeof(*in));
1678 in->sin_family = AF_INET;
1679 in->sin_port = htons(id);
1680 in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1681}
1682
1683static void *make_ping(const struct factory *factory, struct fdesc fdescs[],
1684 int argc, char ** argv)
1685{
1686 struct sockaddr_in in;
1687 return make_ping_common(factory, fdescs, argc, argv,
1688 AF_INET, IPPROTO_ICMP,
1689 ping_init_addr,
1690 sizeof(in),
1691 (struct sockaddr *)&in);
1692}
1693
ca517a11
MY
1694static void tcp6_init_addr(struct sockaddr *addr, unsigned short port)
1695{
1696 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
1697 memset(in6, 0, sizeof(*in6));
1698 in6->sin6_family = AF_INET6;
1699 in6->sin6_flowinfo = 0;
1700 in6->sin6_port = htons(port);
1701 in6->sin6_addr = in6addr_loopback;
1702}
1703
1704static void *make_tcp6(const struct factory *factory, struct fdesc fdescs[],
1705 int argc, char ** argv)
1706{
1707 struct sockaddr_in6 sin, cin;
1708 return make_tcp_common(factory, fdescs, argc, argv,
1709 AF_INET6,
1710 tcp6_init_addr, sizeof(sin),
1711 (struct sockaddr *)&sin, (struct sockaddr *)&cin);
1712}
1713
e568c794
MY
1714static void *make_udp6(const struct factory *factory, struct fdesc fdescs[],
1715 int argc, char ** argv)
1716{
1717 struct sockaddr_in6 sin, cin;
1718 return make_udp_common(factory, fdescs, argc, argv,
1719 AF_INET6,
1720 tcp6_init_addr, sizeof(sin),
1721 (struct sockaddr *)&sin, (struct sockaddr *)&cin);
1722}
1723
0e07fc2d
MY
1724static void raw6_init_addr(struct sockaddr *addr, bool remote_addr)
1725{
1726 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
1727 memset(in6, 0, sizeof(*in6));
1728 in6->sin6_family = AF_INET6;
1729 in6->sin6_flowinfo = 0;
1730
1731 if (remote_addr) {
1732 /* ::ffff:127.0.0.1 */
1733 in6->sin6_addr.s6_addr16[5] = 0xffff;
1734 in6->sin6_addr.s6_addr32[3] = htonl(INADDR_LOOPBACK);
1735 } else
1736 in6->sin6_addr = in6addr_loopback;
1737}
1738
1739static void *make_raw6(const struct factory *factory, struct fdesc fdescs[],
1740 int argc, char ** argv)
1741{
1742 struct sockaddr_in6 sin;
1743 return make_raw_common(factory, fdescs, argc, argv,
1744 AF_INET6,
1745 raw6_init_addr, sizeof(sin),
1746 (struct sockaddr *)&sin);
1747}
1748
00a97611
MY
1749static void ping6_init_addr(struct sockaddr *addr, unsigned short id)
1750{
1751 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
1752 memset(in6, 0, sizeof(*in6));
1753 in6->sin6_family = AF_INET6;
1754 in6->sin6_port = htons(id);
1755 in6->sin6_addr = in6addr_loopback;
1756}
1757
1758static void *make_ping6(const struct factory *factory, struct fdesc fdescs[],
1759 int argc, char ** argv)
1760{
1761 struct sockaddr_in6 in6;
1762 return make_ping_common(factory, fdescs, argc, argv,
1763 AF_INET6, IPPROTO_ICMPV6,
1764 ping6_init_addr,
1765 sizeof(in6),
1766 (struct sockaddr *)&in6);
1767}
0e07fc2d 1768
c5eb81b3
MY
1769static void *make_netns(const struct factory *factory _U_, struct fdesc fdescs[],
1770 int argc _U_, char ** argv _U_)
1771{
1772 int sd = socket(AF_UNIX, SOCK_STREAM, 0);
1773 if (sd < 0)
1774 err(EXIT_FAILURE, "failed in socket()");
1775
1776 int ns = ioctl(sd, SIOCGSKNS);
1777 if (ns < 0)
1778 err(EXIT_FAILURE, "failed in ioctl(SIOCGSKNS)");
1779 close(sd);
1780
1781 if (ns != fdescs[0].fd) {
1782 if (dup2(ns, fdescs[0].fd) < 0) {
1783 int e = errno;
1784 close(ns);
1785 errno = e;
1786 err(EXIT_FAILURE, "failed to dup %d -> %d", ns, fdescs[0].fd);
1787 }
1788 close(ns);
1789 }
1790
1791 fdescs[0] = (struct fdesc){
1792 .fd = fdescs[0].fd,
1793 .close = close_fdesc,
1794 .data = NULL
1795 };
1796
1797 return NULL;
1798}
1799
ae9ff1cd 1800#define PARAM_END { .name = NULL, }
9557ed44 1801static const struct factory factories[] = {
fd81d3a5
MY
1802 {
1803 .name = "ro-regular-file",
ae9ff1cd 1804 .desc = "read-only regular file",
fd81d3a5
MY
1805 .priv = false,
1806 .N = 1,
d14e9efd 1807 .EX_N = 0,
fd81d3a5 1808 .make = open_ro_regular_file,
ae9ff1cd
MY
1809 .params = (struct parameter []) {
1810 {
1811 .name = "file",
1812 .type = PTYPE_STRING,
1813 .desc = "file to be opened",
1814 .defv.string = "/etc/passwd",
1815 },
6d201bcb
MY
1816 {
1817 .name = "offset",
1818 .type = PTYPE_INTEGER,
1819 .desc = "seek bytes after open with SEEK_CUR",
1820 .defv.integer = 0,
1821 },
ae9ff1cd
MY
1822 PARAM_END
1823 },
fd81d3a5
MY
1824 },
1825 {
1826 .name = "pipe-no-fork",
1827 .desc = "making pair of fds with pipe(2)",
1828 .priv = false,
1829 .N = 2,
9aa68bf4 1830 .EX_N = 2,
fd81d3a5 1831 .make = make_pipe,
d85c66d8
MY
1832 .params = (struct parameter []) {
1833 {
1834 .name = "nonblock",
1835 .type = PTYPE_STRING,
1836 .desc = "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")",
1837 .defv.string = "--",
1838 },
9aa68bf4
MY
1839 {
1840 .name = "rdup",
1841 .type = PTYPE_INTEGER,
1842 .desc = "file descriptor for duplicating the pipe input",
1843 .defv.integer = -1,
1844 },
1845 {
1846 .name = "wdup",
1847 .type = PTYPE_INTEGER,
1848 .desc = "file descriptor for duplicating the pipe output",
1849 .defv.integer = -1,
1850 },
d85c66d8
MY
1851 PARAM_END
1852 },
fd81d3a5 1853 },
77c70070
MY
1854 {
1855 .name = "directory",
8c670091 1856 .desc = "directory",
77c70070
MY
1857 .priv = false,
1858 .N = 1,
d14e9efd 1859 .EX_N = 0,
8c670091
MY
1860 .make = open_directory,
1861 .params = (struct parameter []) {
1862 {
1863 .name = "dir",
1864 .type = PTYPE_STRING,
1865 .desc = "directory to be opened",
1866 .defv.string = "/",
1867 },
5c265705
MY
1868 {
1869 .name = "dentries",
1870 .type = PTYPE_INTEGER,
1871 .desc = "read the number of dentries after open with readdir(3)",
1872 .defv.integer = 0,
1873 },
8c670091
MY
1874 PARAM_END
1875 },
77c70070 1876 },
7c06963e
MY
1877 {
1878 .name = "rw-character-device",
1879 .desc = "character device with O_RDWR flag",
1880 .priv = false,
1881 .N = 1,
d14e9efd 1882 .EX_N = 0,
7c06963e
MY
1883 .make = open_rw_chrdev,
1884 .params = (struct parameter []) {
1885 {
1886 .name = "chrdev",
1887 .type = PTYPE_STRING,
1888 .desc = "character device node to be opened",
1889 .defv.string = "/dev/zero",
1890 },
1891 PARAM_END
1892 },
1893 },
d827da23
MY
1894 {
1895 .name = "socketpair",
1896 .desc = "AF_UNIX socket pair created with socketpair(2)",
1897 .priv = false,
1898 .N = 2,
d14e9efd 1899 .EX_N = 0,
d827da23
MY
1900 .make = make_socketpair,
1901 .params = (struct parameter []) {
1902 {
1903 .name = "socktype",
1904 .type = PTYPE_STRING,
1905 .desc = "STREAM, DGRAM, or SEQPACKET",
1906 .defv.string = "STREAM",
1907 },
1908 PARAM_END
1909 },
1910 },
21c70c29
MY
1911 {
1912 .name = "symlink",
1913 .desc = "symbolic link itself opened with O_PATH",
1914 .priv = false,
1915 .N = 1,
d14e9efd 1916 .EX_N = 0,
21c70c29
MY
1917 .make = open_with_opath,
1918 .params = (struct parameter []) {
1919 {
1920 .name = "path",
1921 .type = PTYPE_STRING,
1922 .desc = "path to a symbolic link",
1923 .defv.string = "/dev/stdin",
1924 },
1925 PARAM_END
1926 },
1927 },
cb16b318
MY
1928 {
1929 .name = "ro-block-device",
1930 .desc = "block device with O_RDONLY flag",
1931 .priv = true,
1932 .N = 1,
d14e9efd 1933 .EX_N = 0,
cb16b318
MY
1934 .make = open_ro_blkdev,
1935 .params = (struct parameter []) {
1936 {
1937 .name = "blkdev",
1938 .type = PTYPE_STRING,
1939 .desc = "block device node to be opened",
1940 .defv.string = "/dev/nullb0",
1941 },
1942 PARAM_END
1943 },
1944 },
bce240a7
MY
1945 {
1946 .name = "mapped-packet-socket",
1947 .desc = "mmap'ed AF_PACKET socket",
1948 .priv = true,
1949 .N = 1,
1950 .EX_N = 0,
bce240a7
MY
1951 .make = make_mmapped_packet_socket,
1952 .params = (struct parameter []) {
1953 {
1954 .name = "socktype",
1955 .type = PTYPE_STRING,
1956 .desc = "DGRAM or RAW",
1957 .defv.string = "RAW",
1958 },
1959 {
1960 .name = "interface",
1961 .type = PTYPE_STRING,
1962 .desc = "a name of network interface like eth0 or lo",
1963 .defv.string = "lo",
1964 },
1965 PARAM_END
1966 },
1967 },
ba8c749f 1968 {
ba8c749f
MY
1969 .name = "pidfd",
1970 .desc = "pidfd returned from pidfd_open(2)",
1971 .priv = false,
1972 .N = 1,
1973 .EX_N = 0,
ba8c749f
MY
1974 .make = make_pidfd,
1975 .params = (struct parameter []) {
1976 {
1977 .name = "target-pid",
1978 .type = PTYPE_INTEGER,
1979 .desc = "the pid of the target process",
1980 .defv.integer = 1,
1981 },
1982 PARAM_END
1983 },
1984 },
4d51adc5
MY
1985 {
1986 .name = "inotify",
1987 .desc = "inotify fd returned from inotify_init(2)",
1988 .priv = false,
1989 .N = 1,
1990 .EX_N = 0,
4d51adc5
MY
1991 .make = make_inotify_fd,
1992 .params = (struct parameter []) {
1993 PARAM_END
1994 },
1995 },
a234bad9
MY
1996 {
1997 .name = "unix-stream",
1998 .desc = "AF_UNIX+SOCK_STREAM sockets",
1999 .priv = false,
2000 .N = 3,
2001 .EX_N = 0,
2002 .make = make_unix_stream,
2003 .params = (struct parameter []) {
2004 {
2005 .name = "path",
2006 .type = PTYPE_STRING,
2007 .desc = "path for listening-socket bound to",
2008 .defv.string = "/tmp/test_mkfds-unix-stream",
2009 },
2010 {
2011 .name = "backlog",
2012 .type = PTYPE_INTEGER,
2013 .desc = "backlog passed to listen(2)",
2014 .defv.integer = 5,
2015 },
2016 {
2017 .name = "abstract",
2018 .type = PTYPE_BOOLEAN,
2019 .desc = "use PATH as an abstract socket address",
2020 .defv.boolean = false,
2021 },
2022 {
2023 .name = "server-shutdown",
2024 .type = PTYPE_INTEGER,
2025 .desc = "shutdown the accepted socket; 1: R, 2: W, 3: RW",
2026 .defv.integer = 0,
2027 },
2028 {
2029 .name = "client-shutdown",
2030 .type = PTYPE_INTEGER,
2031 .desc = "shutdown the client socket; 1: R, 2: W, 3: RW",
2032 .defv.integer = 0,
2033 },
223063b1
MY
2034 {
2035 .name = "type",
2036 .type = PTYPE_STRING,
2037 .desc = "stream or seqpacket",
2038 .defv.string = "stream",
2039 },
a234bad9
MY
2040 PARAM_END
2041 },
2042 },
2229a4b4
MY
2043 {
2044 .name = "unix-dgram",
2045 .desc = "AF_UNIX+SOCK_DGRAM sockets",
2046 .priv = false,
2047 .N = 2,
2048 .EX_N = 0,
2049 .make = make_unix_dgram,
2050 .params = (struct parameter []) {
2051 {
2052 .name = "path",
2053 .type = PTYPE_STRING,
2054 .desc = "path for unix non-stream bound to",
2055 .defv.string = "/tmp/test_mkfds-unix-dgram",
2056 },
2057 {
2058 .name = "abstract",
2059 .type = PTYPE_BOOLEAN,
2060 .desc = "use PATH as an abstract socket address",
2061 .defv.boolean = false,
2062 },
2063 PARAM_END
2064 },
2065 },
55529a26
MY
2066 {
2067 .name = "unix-in-netns",
2068 .desc = "make a unix socket in a new network namespace",
2069 .priv = true,
2070 .N = 3,
2071 .EX_N = 0,
2072 .make = make_unix_in_new_netns,
2073 .params = (struct parameter []) {
2074 {
2075 .name = "type",
2076 .type = PTYPE_STRING,
2077 .desc = "dgram, stream, or seqpacket",
2078 .defv.string = "stream",
2079 },
2080 {
2081 .name = "path",
2082 .type = PTYPE_STRING,
2083 .desc = "path for unix non-stream bound to",
2084 .defv.string = "/tmp/test_mkfds-unix-in-netns",
2085 },
2086 {
2087 .name = "abstract",
2088 .type = PTYPE_BOOLEAN,
2089 .desc = "use PATH as an abstract socket address",
2090 .defv.boolean = false,
2091 },
2092 PARAM_END
2093 },
2094 },
20d97930
MY
2095 {
2096 .name = "tcp",
2097 .desc = "AF_INET+SOCK_STREAM sockets",
2098 .priv = false,
2099 .N = 3,
2100 .EX_N = 0,
2101 .make = make_tcp,
2102 .params = (struct parameter []) {
2103 {
2104 .name = "server-port",
2105 .type = PTYPE_INTEGER,
2106 .desc = "TCP port the server may listen",
2107 .defv.integer = 12345,
2108 },
2109 {
2110 .name = "client-port",
2111 .type = PTYPE_INTEGER,
2112 .desc = "TCP port the client may bind",
2113 .defv.integer = 23456,
2114 },
2115 PARAM_END
2116 }
2117 },
abefebd7
MY
2118 {
2119 .name = "udp",
2120 .desc = "AF_INET+SOCK_DGRAM sockets",
2121 .priv = false,
2122 .N = 2,
2123 .EX_N = 0,
2124 .make = make_udp,
2125 .params = (struct parameter []) {
6c9e370e
MY
2126 {
2127 .name = "lite",
2128 .type = PTYPE_BOOLEAN,
2129 .desc = "Use UDPLITE instead of UDP",
2130 .defv.boolean = false,
2131 },
abefebd7
MY
2132 {
2133 .name = "server-port",
2134 .type = PTYPE_INTEGER,
8971afef 2135 .desc = "UDP port the server may listen",
abefebd7
MY
2136 .defv.integer = 12345,
2137 },
2138 {
2139 .name = "client-port",
2140 .type = PTYPE_INTEGER,
8971afef 2141 .desc = "UDP port the client may bind",
abefebd7
MY
2142 .defv.integer = 23456,
2143 },
2144 {
2145 .name = "server-do-bind",
2146 .type = PTYPE_BOOLEAN,
2147 .desc = "call bind with the server socket",
2148 .defv.boolean = true,
2149 },
2150 {
2151 .name = "client-do-bind",
2152 .type = PTYPE_BOOLEAN,
2153 .desc = "call bind with the client socket",
2154 .defv.boolean = true,
2155 },
2156 {
2157 .name = "client-do-connect",
2158 .type = PTYPE_BOOLEAN,
2159 .desc = "call connect with the client socket",
2160 .defv.boolean = true,
2161 },
2162 PARAM_END
2163 }
c5eb81b3 2164 },
0188afb3
MY
2165 {
2166 .name = "raw",
2167 .desc = "AF_INET+SOCK_RAW sockets",
2168 .priv = true,
2169 .N = 1,
2170 .EX_N = 0,
2171 .make = make_raw,
2172 .params = (struct parameter []) {
2173 {
2174 .name = "protocol",
2175 .type = PTYPE_INTEGER,
2176 .desc = "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
2177 .defv.integer = IPPROTO_IPIP,
2178 },
2179 PARAM_END
2180 }
2181
2182 },
00a97611
MY
2183 {
2184 .name = "ping",
2185 .desc = "AF_INET+SOCK_DGRAM+IPPROTO_ICMP sockets",
2186 .priv = false,
2187 .N = 1,
2188 .EX_N = 0,
2189 .make = make_ping,
2190 .params = (struct parameter []) {
2191 {
2192 .name = "connect",
2193 .type = PTYPE_BOOLEAN,
2194 .desc = "call connect(2) with the socket",
2195 .defv.boolean = true,
2196 },
2197 {
2198 .name = "bind",
2199 .type = PTYPE_BOOLEAN,
2200 .desc = "call bind(2) with the socket",
2201 .defv.boolean = true,
2202 },
2203 {
2204 .name = "id",
2205 .type = PTYPE_INTEGER,
2206 .desc = "ICMP echo request id",
2207 .defv.integer = 0,
2208 },
2209 PARAM_END
2210 }
2211 },
ca517a11
MY
2212 {
2213 .name = "tcp6",
2214 .desc = "AF_INET6+SOCK_STREAM sockets",
2215 .priv = false,
2216 .N = 3,
2217 .EX_N = 0,
2218 .make = make_tcp6,
2219 .params = (struct parameter []) {
2220 {
2221 .name = "server-port",
2222 .type = PTYPE_INTEGER,
2223 .desc = "TCP port the server may listen",
2224 .defv.integer = 12345,
2225 },
2226 {
2227 .name = "client-port",
2228 .type = PTYPE_INTEGER,
2229 .desc = "TCP port the client may bind",
2230 .defv.integer = 23456,
2231 },
2232 PARAM_END
2233 }
2234 },
e568c794
MY
2235 {
2236 .name = "udp6",
2237 .desc = "AF_INET6+SOCK_DGRAM sockets",
2238 .priv = false,
2239 .N = 2,
2240 .EX_N = 0,
2241 .make = make_udp6,
2242 .params = (struct parameter []) {
6c9e370e
MY
2243 {
2244 .name = "lite",
2245 .type = PTYPE_BOOLEAN,
2246 .desc = "Use UDPLITE instead of UDP",
2247 .defv.boolean = false,
2248 },
e568c794
MY
2249 {
2250 .name = "server-port",
2251 .type = PTYPE_INTEGER,
2252 .desc = "UDP port the server may listen",
2253 .defv.integer = 12345,
2254 },
2255 {
2256 .name = "client-port",
2257 .type = PTYPE_INTEGER,
2258 .desc = "UDP port the client may bind",
2259 .defv.integer = 23456,
2260 },
2261 {
2262 .name = "server-do-bind",
2263 .type = PTYPE_BOOLEAN,
2264 .desc = "call bind with the server socket",
2265 .defv.boolean = true,
2266 },
2267 {
2268 .name = "client-do-bind",
2269 .type = PTYPE_BOOLEAN,
2270 .desc = "call bind with the client socket",
2271 .defv.boolean = true,
2272 },
2273 {
2274 .name = "client-do-connect",
2275 .type = PTYPE_BOOLEAN,
2276 .desc = "call connect with the client socket",
2277 .defv.boolean = true,
2278 },
2279 PARAM_END
2280 }
2281 },
0e07fc2d
MY
2282 {
2283 .name = "raw6",
2284 .desc = "AF_INET6+SOCK_RAW sockets",
2285 .priv = true,
2286 .N = 1,
2287 .EX_N = 0,
2288 .make = make_raw6,
2289 .params = (struct parameter []) {
2290 {
2291 .name = "protocol",
2292 .type = PTYPE_INTEGER,
2293 .desc = "protocol passed to socket(AF_INET6, SOCK_RAW, protocol)",
2294 .defv.integer = IPPROTO_IPIP,
2295 },
2296 PARAM_END
2297 }
2298
2299 },
00a97611
MY
2300 {
2301 .name = "ping6",
2302 .desc = "AF_INET6+SOCK_DGRAM+IPPROTO_ICMPV6 sockets",
2303 .priv = false,
2304 .N = 1,
2305 .EX_N = 0,
2306 .make = make_ping6,
2307 .params = (struct parameter []) {
2308 {
2309 .name = "connect",
2310 .type = PTYPE_BOOLEAN,
2311 .desc = "call connect(2) with the socket",
2312 .defv.boolean = true,
2313 },
2314 {
2315 .name = "bind",
2316 .type = PTYPE_BOOLEAN,
2317 .desc = "call bind(2) with the socket",
2318 .defv.boolean = true,
2319 },
2320 {
2321 .name = "id",
2322 .type = PTYPE_INTEGER,
2323 .desc = "ICMP echo request id",
2324 .defv.integer = 0,
2325 },
2326 PARAM_END
2327 }
2328 },
c5eb81b3
MY
2329 {
2330 .name = "netns",
2331 .desc = "open a file specifying a netns",
2332 .priv = true,
2333 .N = 1,
2334 .EX_N = 0,
2335 .make = make_netns,
2336 .params = (struct parameter []) {
2337 PARAM_END
2338 }
2339 },
fd81d3a5
MY
2340};
2341
13b7739a
MY
2342static int count_parameters(const struct factory *factory)
2343{
2344
2345 const struct parameter *p = factory->params;
2346 if (!p)
2347 return 0;
2348 while (p->name)
2349 p++;
2350 return p - factory->params;
2351}
2352
9557ed44 2353static void print_factory(const struct factory *factory)
fd81d3a5 2354{
95ac0ff9 2355 printf("%-20s %4s %5d %6d %s\n",
fd81d3a5
MY
2356 factory->name,
2357 factory->priv? "yes": "no",
2358 factory->N,
13b7739a 2359 count_parameters(factory),
fd81d3a5
MY
2360 factory->desc);
2361}
2362
2363static void list_factories(void)
2364{
95ac0ff9 2365 printf("%-20s PRIV COUNT NPARAM DESCRIPTION\n", "FACTORY");
fd81d3a5
MY
2366 for (size_t i = 0; i < ARRAY_SIZE(factories); i++)
2367 print_factory(factories + i);
2368}
2369
9557ed44 2370static const struct factory *find_factory(const char *name)
fd81d3a5
MY
2371{
2372 for (size_t i = 0; i < ARRAY_SIZE(factories); i++)
2373 if (strcmp(factories[i].name, name) == 0)
2374 return factories + i;
2375 return NULL;
2376}
2377
13b7739a
MY
2378static void list_parameters(const char *factory_name)
2379{
2380 const struct factory *factory = find_factory(factory_name);
2381 const char *fmt = "%-15s %-8s %15s %s\n";
2382
2383 if (!factory)
2384 errx(EXIT_FAILURE, _("no such factory: %s"), factory_name);
2385
2386 if (!factory->params)
2387 return;
2388
2389 printf(fmt, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION");
2390 for (const struct parameter *p = factory->params; p->name != NULL; p++) {
2391 char *defv = ptype_classes[p->type].sprint(&p->defv);
2392 printf(fmt, p->name, ptype_classes[p->type].name, defv, p->desc);
2393 free(defv);
2394 }
2395}
2396
863a6544
MY
2397static void rename_self(const char *comm)
2398{
2399 if (prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0) < 0)
2400 err(EXIT_FAILURE, _("failed to rename self via prctl: %s"), comm);
2401}
2402
fd81d3a5
MY
2403static void do_nothing(int signum _U_)
2404{
2405}
2406
ba8c749f
MY
2407#ifdef __NR_pidfd_open
2408
2409static int
2410pidfd_open(pid_t pid, unsigned int flags)
2411{
2412 return syscall(__NR_pidfd_open, pid, flags);
2413}
2414#else
2415static int
2416pidfd_open(pid_t pid _U_, unsigned int flags _U_)
2417{
2418 errno = ENOSYS;
2419 return -1;
2420}
2421#endif
2422
caa97697
MY
2423static void wait_event(void)
2424{
2425 fd_set readfds;
2426 sigset_t sigset;
2427 int n = 0;
2428
2429 FD_ZERO(&readfds);
2430 /* Monitor the standard input only when the process
2431 * is in foreground. */
2432 if (tcgetpgrp(STDIN_FILENO) == getpgrp()) {
2433 n = 1;
2434 FD_SET(0, &readfds);
2435 }
2436
2437 sigemptyset(&sigset);
2438
2439 if (pselect(n, &readfds, NULL, NULL, NULL, &sigset) < 0
2440 && errno != EINTR)
2441 errx(EXIT_FAILURE, _("failed in pselect"));
2442}
2443
fd81d3a5
MY
2444int main(int argc, char **argv)
2445{
2446 int c;
9557ed44 2447 const struct factory *factory;
fd81d3a5
MY
2448 struct fdesc fdescs[MAX_N];
2449 bool quiet = false;
2450 bool cont = false;
67aab5a5 2451 void *data;
fd81d3a5 2452
fd81d3a5
MY
2453 static const struct option longopts[] = {
2454 { "list", no_argument, NULL, 'l' },
13b7739a 2455 { "parameters", required_argument, NULL, 'I' },
863a6544 2456 { "comm", required_argument, NULL, 'r' },
fd81d3a5
MY
2457 { "quiet", no_argument, NULL, 'q' },
2458 { "dont-puase", no_argument, NULL, 'c' },
2459 { "help", no_argument, NULL, 'h' },
3e244bab 2460 { NULL, 0, NULL, 0 },
fd81d3a5
MY
2461 };
2462
863a6544 2463 while ((c = getopt_long(argc, argv, "lhqcI:r:", longopts, NULL)) != -1) {
fd81d3a5
MY
2464 switch (c) {
2465 case 'h':
2466 usage(stdout, EXIT_SUCCESS);
2467 case 'l':
2468 list_factories();
2469 exit(EXIT_SUCCESS);
13b7739a
MY
2470 case 'I':
2471 list_parameters(optarg);
2472 exit(EXIT_SUCCESS);
fd81d3a5
MY
2473 case 'q':
2474 quiet = true;
2475 break;
2476 case 'c':
2477 cont = true;
2478 break;
863a6544
MY
2479 case 'r':
2480 rename_self(optarg);
2481 break;
fd81d3a5
MY
2482 default:
2483 usage(stderr, EXIT_FAILURE);
2484 }
2485 }
2486
fd81d3a5
MY
2487 if (optind == argc)
2488 errx(EXIT_FAILURE, _("no file descriptor specification given"));
2489
2490 factory = find_factory(argv[optind]);
2491 if (!factory)
2492 errx(EXIT_FAILURE, _("no such factory: %s"), argv[optind]);
d14e9efd 2493 assert(factory->N + factory->EX_N < MAX_N);
fd81d3a5
MY
2494 optind++;
2495
2496 if ((optind + factory->N) > argc)
2497 errx(EXIT_FAILURE, _("not enough file descriptors given for %s"),
2498 factory->name);
d14e9efd 2499
811ad38e
MY
2500 if (factory->priv && getuid() != 0)
2501 errx(EXIT_FAILURE, "%s factory requires root privilege", factory->name);
2502
01f7300b 2503 for (int i = 0; i < MAX_N; i++) {
d14e9efd 2504 fdescs[i].fd = -1;
01f7300b
MY
2505 fdescs[i].close = NULL;
2506 }
d14e9efd 2507
fd81d3a5
MY
2508 for (int i = 0; i < factory->N; i++) {
2509 char *str = argv[optind + i];
2510 long fd;
adf7af0e 2511 char *ep;
fd81d3a5 2512
adf7af0e
MY
2513 errno = 0;
2514 fd = strtol(str, &ep, 10);
fd81d3a5
MY
2515 if (errno)
2516 err(EXIT_FAILURE, "failed to convert fd number: %s", str);
adf7af0e
MY
2517 if (ep == str)
2518 errx(EXIT_FAILURE, "failed to convert fd number: %s", str);
2519 if (*ep != '\0')
2520 errx(EXIT_FAILURE, _("garbage at the end of number: %s"), str);
fd81d3a5
MY
2521 if (fd < 0)
2522 errx(EXIT_FAILURE, "fd number should not be negative: %s", str);
2523 if (fd < 3)
2524 errx(EXIT_FAILURE, "fd 0, 1, 2 are reserved: %s", str);
2525 fdescs[i].fd = fd;
2526 }
2527 optind += factory->N;
2528
67aab5a5 2529 data = factory->make(factory, fdescs, argc - optind, argv + optind);
fd81d3a5
MY
2530
2531 signal(SIGCONT, do_nothing);
2532
2533 if (!quiet) {
b5eb0333 2534 printf("%d", getpid());
fd81d3a5 2535 putchar('\n');
271bc510
MY
2536 if (factory->report)
2537 factory->report(factory, data, stdout);
fd81d3a5
MY
2538 fflush(stdout);
2539 }
2540
2541 if (!cont)
caa97697 2542 wait_event();
fd81d3a5 2543
d14e9efd 2544 for (int i = 0; i < factory->N + factory->EX_N; i++)
01f7300b 2545 if (fdescs[i].fd >= 0 && fdescs[i].close)
d14e9efd 2546 fdescs[i].close(fdescs[i].fd, fdescs[i].data);
fd81d3a5 2547
67aab5a5
MY
2548 if (factory->free)
2549 factory->free (factory, data);
2550
fd81d3a5
MY
2551 exit(EXIT_SUCCESS);
2552}