2 * test_mkfds - make various file descriptors
4 * Written by Masatake YAMATO <yamato@redhat.com>
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.
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.
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.
22 #include "test_mkfds.h"
23 #include "exitcodes.h"
25 #include <arpa/inet.h>
32 #include <linux/bpf.h>
33 #include <linux/if_ether.h>
34 #include <linux/if_packet.h>
35 #include <linux/if_tun.h>
36 #include <linux/netlink.h>
37 #include <linux/sock_diag.h>
38 # include <linux/unix_diag.h> /* for UNIX domain sockets */
39 #include <linux/sockios.h> /* SIOCGSKNS */
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
51 #include <sys/epoll.h>
52 #include <sys/eventfd.h>
53 #include <sys/inotify.h>
54 #include <sys/ioctl.h>
56 #include <sys/prctl.h>
57 #include <sys/select.h>
58 #include <sys/signalfd.h>
59 #include <sys/socket.h>
62 #include <sys/syscall.h>
63 #include <sys/timerfd.h>
64 #include <sys/types.h>
72 #define EXIT_ENOPROTOOPT 19
73 #define EXIT_EPROTONOSUPPORT 20
74 #define EXIT_EACCES 21
75 #define EXIT_ENOENT 22
77 #define _U_ __attribute__((__unused__))
79 static int pidfd_open(pid_t pid
, unsigned int flags
);
80 static void do_nothing(int signum _U_
);
82 static void __attribute__((__noreturn__
)) usage(FILE *out
, int status
)
84 fputs("\nUsage:\n", out
);
85 fprintf(out
, " %s [options] FACTORY FD... [PARAM=VAL...]\n", program_invocation_short_name
);
87 fputs("\nOptions:\n", out
);
88 fputs(" -a, --is-available <factory> exit 0 if the factory is available\n", out
);
89 fputs(" -l, --list list available file descriptor factories and exit\n", out
);
90 fputs(" -I, --parameters <factory> list parameters the factory takes\n", out
);
91 fputs(" -r, --comm <name> rename self\n", out
);
92 fputs(" -q, --quiet don't print pid(s)\n", out
);
93 fputs(" -X, --dont-monitor-stdin don't monitor stdin when pausing\n", out
);
94 fputs(" -c, --dont-pause don't pause after making fd(s)\n", out
);
95 fputs(" -w, --wait-with <multiplexer> use MULTIPLEXER for waiting events\n", out
);
96 fputs(" -W, --multiplexers list multiplexers\n", out
);
99 fputs("Examples:\n", out
);
100 fprintf(out
, "Using 3, open /etc/group:\n\n $ %s ro-regular-file 3 file=/etc/group\n\n",
101 program_invocation_short_name
);
102 fprintf(out
, "Using 3 and 4, make a pipe:\n\n $ %s pipe-no-fork 3 4\n\n",
103 program_invocation_short_name
);
111 unsigned long uinteger
;
125 /* Covert to a string representation.
126 * A caller must free the returned value with free(3) after using. */
127 char *(*sprint
)(const union value
*value
);
129 /* Convert from a string. If ARG is NULL, use DEFV instead.
130 * A caller must free the returned value with the free method
132 union value (*read
)(const char *arg
, const union value
*defv
);
134 /* Free the value returned from the read method. */
135 void (*free
)(union value value
);
138 #define ARG_STRING(A) (A.v.string)
139 #define ARG_INTEGER(A) (A.v.integer)
140 #define ARG_UINTEGER(A) (A.v.uinteger)
141 #define ARG_BOOLEAN(A) (A.v.boolean)
144 void (*free
)(union value value
);
149 const enum ptype type
;
151 union value defv
; /* Default value */
154 static char *string_sprint(const union value
*value
)
156 return xstrdup(value
->string
);
159 static union value
string_read(const char *arg
, const union value
*defv
)
161 return (union value
){ .string
= xstrdup(arg
?: defv
->string
) };
164 static void string_free(union value value
)
166 free((void *)value
.string
);
169 static char *integer_sprint(const union value
*value
)
172 xasprintf(&str
, "%ld", value
->integer
);
176 static union value
integer_read(const char *arg
, const union value
*defv
)
185 r
.integer
= strtol(arg
, &ep
, 10);
187 err(EXIT_FAILURE
, "fail to make a number from %s", arg
);
188 else if (*ep
!= '\0')
189 errx(EXIT_FAILURE
, "garbage at the end of number: %s", arg
);
193 static void integer_free(union value value _U_
)
198 static char *uinteger_sprint(const union value
*value
)
201 xasprintf(&str
, "%lu", value
->uinteger
);
205 static union value
uinteger_read(const char *arg
, const union value
*defv
)
214 r
.uinteger
= strtoul(arg
, &ep
, 10);
216 err(EXIT_FAILURE
, "fail to make a number from %s", arg
);
217 else if (*ep
!= '\0')
218 errx(EXIT_FAILURE
, "garbage at the end of number: %s", arg
);
222 static void uinteger_free(union value value _U_
)
227 static char *boolean_sprint(const union value
*value
)
229 return xstrdup(value
->boolean
? "true": "false");
232 static union value
boolean_read(const char *arg
, const union value
*defv
)
239 if (strcasecmp(arg
, "true") == 0
240 || strcmp(arg
, "1") == 0
241 || strcasecmp(arg
, "yes") == 0
242 || strcasecmp(arg
, "y") == 0)
249 static void boolean_free(union value value _U_
)
254 struct ptype_class ptype_classes
[] = {
257 .sprint
= string_sprint
,
263 .sprint
= integer_sprint
,
264 .read
= integer_read
,
265 .free
= integer_free
,
269 .sprint
= uinteger_sprint
,
270 .read
= uinteger_read
,
271 .free
= uinteger_free
,
275 .sprint
= boolean_sprint
,
276 .read
= boolean_read
,
277 .free
= boolean_free
,
281 static struct arg
decode_arg(const char *pname
,
282 const struct parameter
*parameters
,
283 int argc
, char **argv
)
286 size_t len
= strlen(pname
);
287 const struct parameter
*p
= NULL
;
290 while (parameters
->name
) {
291 if (strcmp(pname
, parameters
->name
) == 0) {
298 errx(EXIT_FAILURE
, "no such parameter: %s", pname
);
300 for (int i
= 0; i
< argc
; i
++) {
301 if (strncmp(pname
, argv
[i
], len
) == 0) {
306 } else if (*v
== '\0')
308 "no value given for \"%s\" parameter",
314 arg
.v
= ptype_classes
[p
->type
].read(v
, &p
->defv
);
315 arg
.free
= ptype_classes
[p
->type
].free
;
319 static void free_arg(struct arg
*arg
)
325 const char *name
; /* [-a-zA-Z0-9_]+ */
327 bool priv
; /* the root privilege is needed to make fd(s) */
329 int N
; /* the number of fds this factory makes */
330 int EX_N
; /* fds made optionally */
331 int EX_R
; /* the number of extra words printed to stdout. */
332 void *(*make
)(const struct factory
*, struct fdesc
[], int, char **);
333 void (*free
)(const struct factory
*, void *);
334 void (*report
)(const struct factory
*, int, void *, FILE *);
335 const struct parameter
* params
;
338 static void close_fdesc(int fd
, void *data _U_
)
343 volatile ssize_t unused_result_ok
;
344 static void abort_with_child_death_message(int signum _U_
)
346 const char msg
[] = "the child process exits unexpectedly";
347 unused_result_ok
= write(2, msg
, sizeof(msg
));
351 static void *open_ro_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
352 int argc
, char ** argv
)
354 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
355 struct arg offset
= decode_arg("offset", factory
->params
, argc
, argv
);
356 struct arg lease_r
= decode_arg("read-lease", factory
->params
, argc
, argv
);
358 int fd
= open(ARG_STRING(file
), O_RDONLY
);
360 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(file
));
363 if (ARG_INTEGER(offset
) != 0) {
364 if (lseek(fd
, (off_t
)ARG_INTEGER(offset
), SEEK_CUR
) < 0) {
368 err(EXIT_FAILURE
, "failed to seek 0 -> %ld", ARG_INTEGER(offset
));
373 if (ARG_BOOLEAN(lease_r
)) {
374 if (fcntl(fd
, F_SETLEASE
, F_RDLCK
) < 0) {
378 err(EXIT_FAILURE
, "failed to take out a read lease");
383 if (fd
!= fdescs
[0].fd
) {
384 if (dup2(fd
, fdescs
[0].fd
) < 0) {
388 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
393 fdescs
[0] = (struct fdesc
){
395 .close
= close_fdesc
,
402 static void unlink_and_close_fdesc(int fd
, void *data
)
410 typedef void (*lockFn
)(int fd
, const char *fname
, int dupfd
);
412 static void lock_fn_none(int fd _U_
, const char *fname _U_
, int dupfd _U_
)
417 static void lock_fn_flock_sh(int fd
, const char *fname
, int dupfd
)
419 if (flock(fd
, LOCK_SH
) < 0) {
426 err(EXIT_FAILURE
, "failed to lock");
430 static void lock_fn_flock_ex(int fd
, const char *fname
, int dupfd
)
432 if (flock(fd
, LOCK_EX
) < 0) {
439 err(EXIT_FAILURE
, "failed to lock");
443 static void lock_fn_posix_r_(int fd
, const char *fname
, int dupfd
)
447 .l_whence
= SEEK_SET
,
451 if (fcntl(fd
, F_SETLK
, &r
) < 0) {
458 err(EXIT_FAILURE
, "failed to lock");
462 static void lock_fn_posix__w(int fd
, const char *fname
, int dupfd
)
466 .l_whence
= SEEK_SET
,
470 if (fcntl(fd
, F_SETLK
, &w
) < 0) {
477 err(EXIT_FAILURE
, "failed to lock");
481 static void lock_fn_posix_rw(int fd
, const char *fname
, int dupfd
)
485 .l_whence
= SEEK_SET
,
491 .l_whence
= SEEK_SET
,
495 if (fcntl(fd
, F_SETLK
, &r
) < 0) {
502 err(EXIT_FAILURE
, "failed to lock(read)");
504 if (fcntl(fd
, F_SETLK
, &w
) < 0) {
511 err(EXIT_FAILURE
, "failed to lock(write)");
516 static void lock_fn_ofd_r_(int fd
, const char *fname
, int dupfd
)
520 .l_whence
= SEEK_SET
,
525 if (fcntl(fd
, F_OFD_SETLK
, &r
) < 0) {
532 err(EXIT_FAILURE
, "failed to lock");
536 static void lock_fn_ofd__w(int fd
, const char *fname
, int dupfd
)
540 .l_whence
= SEEK_SET
,
545 if (fcntl(fd
, F_OFD_SETLK
, &w
) < 0) {
552 err(EXIT_FAILURE
, "failed to lock");
556 static void lock_fn_ofd_rw(int fd
, const char *fname
, int dupfd
)
560 .l_whence
= SEEK_SET
,
567 .l_whence
= SEEK_SET
,
572 if (fcntl(fd
, F_OFD_SETLK
, &r
) < 0) {
579 err(EXIT_FAILURE
, "failed to lock(read)");
581 if (fcntl(fd
, F_OFD_SETLK
, &w
) < 0) {
588 err(EXIT_FAILURE
, "failed to lock(write)");
591 #endif /* F_OFD_SETLK */
593 static void lock_fn_lease_w(int fd
, const char *fname
, int dupfd
)
595 if (fcntl(fd
, F_SETLEASE
, F_WRLCK
) < 0) {
602 err(EXIT_FAILURE
, "failed to take out a write lease");
607 static void *make_w_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
608 int argc
, char ** argv
)
612 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
613 char *fname
= xstrdup(ARG_STRING(file
));
615 struct arg
delete = decode_arg("delete", factory
->params
, argc
, argv
);
616 bool bDelete
= ARG_BOOLEAN(delete);
618 struct arg write_bytes
= decode_arg("write-bytes", factory
->params
, argc
, argv
);
619 int iWrite_bytes
= ARG_INTEGER(write_bytes
);
621 struct arg readable
= decode_arg("readable", factory
->params
, argc
, argv
);
622 bool bReadable
= ARG_BOOLEAN(readable
);
624 struct arg lock
= decode_arg("lock", factory
->params
, argc
, argv
);
625 const char *sLock
= ARG_STRING(lock
);
628 struct arg dupfd
= decode_arg("dupfd", factory
->params
, argc
, argv
);
629 int iDupfd
= ARG_INTEGER(dupfd
);
633 if (iWrite_bytes
< 0)
634 errx(EXIT_FAILURE
, "write-bytes must be a positive number or zero.");
636 if (strcmp(sLock
, "none") == 0)
637 lock_fn
= lock_fn_none
;
638 else if (strcmp(sLock
, "flock-sh") == 0)
639 lock_fn
= lock_fn_flock_sh
;
640 else if (strcmp(sLock
, "flock-ex") == 0)
641 lock_fn
= lock_fn_flock_ex
;
642 else if (strcmp(sLock
, "posix-r-") == 0) {
644 if (iWrite_bytes
< 1)
646 lock_fn
= lock_fn_posix_r_
;
647 } else if (strcmp(sLock
, "posix--w") == 0) {
648 if (iWrite_bytes
< 1)
650 lock_fn
= lock_fn_posix__w
;
651 } else if (strcmp(sLock
, "posix-rw") == 0) {
653 if (iWrite_bytes
< 3)
655 lock_fn
= lock_fn_posix_rw
;
657 } else if (strcmp(sLock
, "ofd-r-") == 0) {
659 if (iWrite_bytes
< 1)
661 lock_fn
= lock_fn_ofd_r_
;
662 } else if (strcmp(sLock
, "ofd--w") == 0) {
663 if (iWrite_bytes
< 1)
665 lock_fn
= lock_fn_ofd__w
;
666 } else if (strcmp(sLock
, "ofd-rw") == 0) {
668 if (iWrite_bytes
< 3)
670 lock_fn
= lock_fn_ofd_rw
;
672 } else if (strcmp(sLock
, "ofd-r-") == 0
673 || strcmp(sLock
, "ofd--w") == 0
674 || strcmp(sLock
, "ofd-rw") == 0) {
675 errx(EXIT_ENOSYS
, "no availability for ofd lock");
676 #endif /* F_OFD_SETLK */
677 } else if (strcmp(sLock
, "lease-w") == 0)
678 lock_fn
= lock_fn_lease_w
;
680 errx(EXIT_FAILURE
, "unexpected value for lock parameter: %s", sLock
);
685 free_arg(&write_bytes
);
689 fd
= open(fname
, O_CREAT
|O_EXCL
|(bReadable
? O_RDWR
: O_WRONLY
), S_IWUSR
);
691 err(EXIT_FAILURE
, "failed to make: %s", fname
);
693 if (fd
!= fdescs
[0].fd
) {
694 if (dup2(fd
, fdescs
[0].fd
) < 0) {
700 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
707 if (unlink(fname
) < 0) {
711 err(EXIT_FAILURE
, "failed to unlink %s", fname
);
717 for (int i
= 0; i
< iWrite_bytes
; i
++) {
718 if (write(fd
, "z", 1) != 1) {
724 err(EXIT_FAILURE
, "failed to write");
729 if (dup2(fd
, iDupfd
) < 0) {
735 err(EXIT_FAILURE
, "failed in dup2");
737 data
= xmalloc(sizeof(iDupfd
));
738 *((int *)data
) = iDupfd
;
741 lock_fn(fd
, fname
, iDupfd
);
743 fdescs
[0] = (struct fdesc
){
745 .close
= bDelete
? close_fdesc
: unlink_and_close_fdesc
,
752 static void free_after_closing_duplicated_fd(const struct factory
* factory _U_
, void *data
)
761 static void *make_pipe(const struct factory
*factory
, struct fdesc fdescs
[],
762 int argc
, char ** argv
)
765 int nonblock_flags
[2] = {0, 0};
766 struct arg nonblock
= decode_arg("nonblock", factory
->params
, argc
, argv
);
767 if (strlen(ARG_STRING(nonblock
)) != 2) {
768 errx(EXIT_FAILURE
, "string value for %s has unexpected length: %s",
769 "nonblock", ARG_STRING(nonblock
));
772 /* Make extra pipe descriptors for making pipe objects connected
773 * with fds more than 2.
774 * See https://github.com/util-linux/util-linux/pull/1622
775 * about the background of the requirement. */
776 struct arg rdup
= decode_arg("rdup", factory
->params
, argc
, argv
);
777 struct arg wdup
= decode_arg("wdup", factory
->params
, argc
, argv
);
779 xpd
[0] = ARG_INTEGER(rdup
);
780 xpd
[1] = ARG_INTEGER(wdup
);
782 for (int i
= 0; i
< 2; i
++) {
783 if (ARG_STRING(nonblock
)[i
] == '-')
785 if ((i
== 0 && ARG_STRING(nonblock
)[i
] == 'r')
786 || (i
== 1 && ARG_STRING(nonblock
)[i
] == 'w'))
787 nonblock_flags
[i
] = 1;
789 errx(EXIT_FAILURE
, "unexpected value %c for the %s fd of %s",
790 ARG_STRING(nonblock
)[i
],
791 (i
== 0)? "read": "write",
797 err(EXIT_FAILURE
, "failed to make pipe");
799 for (int i
= 0; i
< 2; i
++) {
800 if (nonblock_flags
[i
]) {
801 int flags
= fcntl(pd
[i
], F_GETFL
);
802 if (fcntl(pd
[i
], F_SETFL
, flags
|O_NONBLOCK
) < 0) {
807 errx(EXIT_FAILURE
, "failed to set NONBLOCK flag to the %s fd",
808 (i
== 0)? "read": "write");
813 for (int i
= 0; i
< 2; i
++) {
814 if (pd
[i
] != fdescs
[i
].fd
) {
815 if (dup2(pd
[i
], fdescs
[i
].fd
) < 0) {
820 err(EXIT_FAILURE
, "failed to dup %d -> %d",
821 pd
[i
], fdescs
[i
].fd
);
825 fdescs
[i
] = (struct fdesc
){
827 .close
= close_fdesc
,
832 /* Make extra pipe descriptors. */
833 for (int i
= 0; i
< 2; i
++) {
835 if (dup2(fdescs
[i
].fd
, xpd
[i
]) < 0) {
839 if (i
> 0 && xpd
[0] >= 0)
842 err(EXIT_FAILURE
, "failed to dup %d -> %d",
843 fdescs
[i
].fd
, xpd
[i
]);
845 fdescs
[i
+ 2] = (struct fdesc
){
847 .close
= close_fdesc
,
856 static void close_dir(int fd
, void *data
)
862 close_fdesc(fd
, NULL
);
865 static void *open_directory(const struct factory
*factory
, struct fdesc fdescs
[],
866 int argc
, char ** argv
)
868 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
869 struct arg dentries
= decode_arg("dentries", factory
->params
, argc
, argv
);
872 int fd
= open(ARG_STRING(dir
), O_RDONLY
|O_DIRECTORY
);
874 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(dir
));
877 if (fd
!= fdescs
[0].fd
) {
878 if (dup2(fd
, fdescs
[0].fd
) < 0) {
882 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
887 if (ARG_INTEGER(dentries
) > 0) {
888 dp
= fdopendir(fdescs
[0].fd
);
893 err(EXIT_FAILURE
, "failed to make DIR* from fd: %s", ARG_STRING(dir
));
895 for (int i
= 0; i
< ARG_INTEGER(dentries
); i
++) {
896 struct dirent
*d
= readdir(dp
);
901 err(EXIT_FAILURE
, "failed in readdir(3)");
907 fdescs
[0] = (struct fdesc
){
916 static void *open_rw_chrdev(const struct factory
*factory
, struct fdesc fdescs
[],
917 int argc
, char ** argv
)
919 struct arg chrdev
= decode_arg("chrdev", factory
->params
, argc
, argv
);
920 int fd
= open(ARG_STRING(chrdev
), O_RDWR
);
922 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(chrdev
));
925 if (fd
!= fdescs
[0].fd
) {
926 if (dup2(fd
, fdescs
[0].fd
) < 0) {
930 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
935 fdescs
[0] = (struct fdesc
){
937 .close
= close_fdesc
,
944 static void *make_socketpair(const struct factory
*factory
, struct fdesc fdescs
[],
945 int argc
, char ** argv
)
948 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
950 struct arg halfclose
= decode_arg("halfclose", factory
->params
, argc
, argv
);
953 bhalfclose
= ARG_BOOLEAN(halfclose
);
954 free_arg(&halfclose
);
956 if (strcmp(ARG_STRING(socktype
), "STREAM") == 0)
957 isocktype
= SOCK_STREAM
;
958 else if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
959 isocktype
= SOCK_DGRAM
;
960 else if (strcmp(ARG_STRING(socktype
), "SEQPACKET") == 0)
961 isocktype
= SOCK_SEQPACKET
;
964 "unknown socket type for socketpair(AF_UNIX,...): %s",
965 ARG_STRING(socktype
));
968 if (socketpair(AF_UNIX
, isocktype
, 0, sd
) < 0)
969 err(EXIT_FAILURE
, "failed to make socket pair");
972 if (shutdown(sd
[0], SHUT_RD
) < 0)
974 "failed to shutdown the read end of the 1st socket");
975 if (shutdown(sd
[1], SHUT_WR
) < 0)
977 "failed to shutdown the write end of the 2nd socket");
980 for (int i
= 0; i
< 2; i
++) {
981 if (sd
[i
] != fdescs
[i
].fd
) {
982 if (dup2(sd
[i
], fdescs
[i
].fd
) < 0) {
987 err(EXIT_FAILURE
, "failed to dup %d -> %d",
988 sd
[i
], fdescs
[i
].fd
);
992 fdescs
[i
] = (struct fdesc
){
994 .close
= close_fdesc
,
1002 static void *open_with_opath(const struct factory
*factory
, struct fdesc fdescs
[],
1003 int argc
, char ** argv
)
1005 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1006 int fd
= open(ARG_STRING(path
), O_PATH
|O_NOFOLLOW
);
1008 err(EXIT_FAILURE
, "failed to open with O_PATH: %s", ARG_STRING(path
));
1011 if (fd
!= fdescs
[0].fd
) {
1012 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1016 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1021 fdescs
[0] = (struct fdesc
){
1023 .close
= close_fdesc
,
1030 static void *open_ro_blkdev(const struct factory
*factory
, struct fdesc fdescs
[],
1031 int argc
, char ** argv
)
1033 struct arg blkdev
= decode_arg("blkdev", factory
->params
, argc
, argv
);
1034 int fd
= open(ARG_STRING(blkdev
), O_RDONLY
);
1036 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(blkdev
));
1039 if (fd
!= fdescs
[0].fd
) {
1040 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1044 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1049 fdescs
[0] = (struct fdesc
){
1051 .close
= close_fdesc
,
1058 static int make_packet_socket(int socktype
, const char *interface
)
1061 struct sockaddr_ll addr
;
1063 sd
= socket(AF_PACKET
, socktype
, htons(ETH_P_ALL
));
1065 err(EXIT_FAILURE
, "failed to make a socket with AF_PACKET");
1067 if (interface
== NULL
)
1068 return sd
; /* Just making a socket */
1070 memset(&addr
, 0, sizeof(struct sockaddr_ll
));
1071 addr
.sll_family
= AF_PACKET
;
1072 addr
.sll_ifindex
= if_nametoindex(interface
);
1073 if (addr
.sll_ifindex
== 0) {
1078 "failed to get the interface index for %s", interface
);
1080 if (bind(sd
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_ll
)) < 0) {
1085 "failed to get the interface index for %s", interface
);
1091 struct munmap_data
{
1096 static void close_fdesc_after_munmap(int fd
, void *data
)
1098 struct munmap_data
*munmap_data
= data
;
1099 munmap(munmap_data
->ptr
, munmap_data
->len
);
1104 static void *make_mmapped_packet_socket(const struct factory
*factory
, struct fdesc fdescs
[],
1105 int argc
, char ** argv
)
1108 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
1109 struct arg interface
= decode_arg("interface", factory
->params
, argc
, argv
);
1112 const char *sinterface
;
1113 struct tpacket_req req
;
1114 struct munmap_data
*munmap_data
;
1116 if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
1117 isocktype
= SOCK_DGRAM
;
1118 else if (strcmp(ARG_STRING(socktype
), "RAW") == 0)
1119 isocktype
= SOCK_RAW
;
1122 "unknown socket type for socket(AF_PACKET,...): %s",
1123 ARG_STRING(socktype
));
1124 free_arg(&socktype
);
1126 sinterface
= ARG_STRING(interface
);
1127 sd
= make_packet_socket(isocktype
, sinterface
);
1128 free_arg(&interface
);
1130 /* Specify the spec of ring buffers.
1133 * - linux/Documentation/networking/packet_mmap.rst
1134 * - https://sites.google.com/site/packetmmap/home
1136 req
.tp_block_size
= getpagesize();
1137 req
.tp_frame_size
= getpagesize();
1138 req
.tp_block_nr
= 1;
1139 req
.tp_frame_nr
= 1;
1140 if (setsockopt(sd
, SOL_PACKET
, PACKET_TX_RING
, (char *)&req
, sizeof(req
)) < 0) {
1144 err((errno
== ENOPROTOOPT
? EXIT_ENOPROTOOPT
: EXIT_FAILURE
),
1145 "failed to specify a buffer spec to a packet socket");
1148 munmap_data
= xmalloc(sizeof(*munmap_data
));
1149 munmap_data
->len
= (size_t) req
.tp_block_size
* req
.tp_block_nr
;
1150 munmap_data
->ptr
= mmap(NULL
, munmap_data
->len
, PROT_WRITE
, MAP_SHARED
, sd
, 0);
1151 if (munmap_data
->ptr
== MAP_FAILED
) {
1156 err(EXIT_FAILURE
, "failed to do mmap a packet socket");
1159 if (sd
!= fdescs
[0].fd
) {
1160 if (dup2(sd
, fdescs
[0].fd
) < 0) {
1163 munmap(munmap_data
->ptr
, munmap_data
->len
);
1166 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
1171 fdescs
[0] = (struct fdesc
){
1173 .close
= close_fdesc_after_munmap
,
1174 .data
= munmap_data
,
1180 static void *make_pidfd(const struct factory
*factory
, struct fdesc fdescs
[],
1181 int argc
, char ** argv
)
1183 struct arg target_pid
= decode_arg("target-pid", factory
->params
, argc
, argv
);
1184 pid_t pid
= ARG_INTEGER(target_pid
);
1186 int fd
= pidfd_open(pid
, 0);
1188 err_nosys(EXIT_FAILURE
, "failed in pidfd_open(%d)", (int)pid
);
1189 free_arg(&target_pid
);
1191 if (fd
!= fdescs
[0].fd
) {
1192 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1196 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1201 fdescs
[0] = (struct fdesc
){
1203 .close
= close_fdesc
,
1210 static void *make_inotify_fd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
1211 int argc _U_
, char ** argv _U_
)
1213 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
1214 const char *sdir
= ARG_STRING(dir
);
1215 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
1216 const char *sfile
= ARG_STRING(file
);
1218 int fd
= inotify_init();
1220 err(EXIT_FAILURE
, "failed in inotify_init()");
1222 if (inotify_add_watch(fd
, sdir
, IN_DELETE
) < 0) {
1226 err(EXIT_FAILURE
, "failed in inotify_add_watch(\"%s\")", sdir
);
1230 if (inotify_add_watch(fd
, sfile
, IN_DELETE
) < 0) {
1234 err(EXIT_FAILURE
, "failed in inotify_add_watch(\"%s\")", sfile
);
1238 if (fd
!= fdescs
[0].fd
) {
1239 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1243 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1248 fdescs
[0] = (struct fdesc
){
1250 .close
= close_fdesc
,
1257 static void close_unix_socket(int fd
, void *data
)
1267 static void *make_unix_stream_core(const struct factory
*factory
, struct fdesc fdescs
[],
1268 int argc
, char ** argv
, int type
, const char *typestr
)
1270 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1271 const char *spath
= ARG_STRING(path
);
1273 struct arg backlog
= decode_arg("backlog", factory
->params
, argc
, argv
);
1274 int ibacklog
= ARG_INTEGER(path
);
1276 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1277 bool babstract
= ARG_BOOLEAN(abstract
);
1279 struct arg server_shutdown
= decode_arg("server-shutdown", factory
->params
, argc
, argv
);
1280 int iserver_shutdown
= ARG_INTEGER(server_shutdown
);
1281 struct arg client_shutdown
= decode_arg("client-shutdown", factory
->params
, argc
, argv
);
1282 int iclient_shutdown
= ARG_INTEGER(client_shutdown
);
1284 int ssd
, csd
, asd
; /* server, client, and accepted socket descriptors */
1285 struct sockaddr_un un
;
1286 size_t un_len
= sizeof(un
);
1288 memset(&un
, 0, sizeof(un
));
1289 un
.sun_family
= AF_UNIX
;
1291 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1292 size_t pathlen
= strlen(spath
);
1293 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1294 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1296 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1298 free_arg(&client_shutdown
);
1299 free_arg(&server_shutdown
);
1300 free_arg(&abstract
);
1304 if (iserver_shutdown
< 0 || iserver_shutdown
> 3)
1305 errx(EXIT_FAILURE
, "the server shudown specification in unexpected range");
1306 if (iclient_shutdown
< 0 || iclient_shutdown
> 3)
1307 errx(EXIT_FAILURE
, "the client shudown specification in unexpected range");
1309 ssd
= socket(AF_UNIX
, type
, 0);
1312 "failed to make a socket with AF_UNIX + SOCK_%s (server side)", typestr
);
1313 if (ssd
!= fdescs
[0].fd
) {
1314 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1318 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1324 fdescs
[0] = (struct fdesc
){
1326 .close
= close_unix_socket
,
1331 unlink(un
.sun_path
);
1332 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1336 err(EXIT_FAILURE
, "failed to bind a socket for listening");
1340 fdescs
[0].data
= xstrdup(un
.sun_path
);
1341 if (listen(ssd
, ibacklog
) < 0) {
1343 close_unix_socket(ssd
, fdescs
[0].data
);
1345 err(EXIT_FAILURE
, "failed to listen a socket");
1348 csd
= socket(AF_UNIX
, type
, 0);
1351 "failed to make a socket with AF_UNIX + SOCK_%s (client side)", typestr
);
1352 if (csd
!= fdescs
[1].fd
) {
1353 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1356 close_unix_socket(ssd
, fdescs
[0].data
);
1358 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1364 fdescs
[1] = (struct fdesc
){
1366 .close
= close_fdesc
,
1370 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1372 close_fdesc(csd
, NULL
);
1373 close_unix_socket(ssd
, fdescs
[0].data
);
1375 err(EXIT_FAILURE
, "failed to connect a socket to the listening socket");
1379 unlink(un
.sun_path
);
1381 asd
= accept(ssd
, NULL
, NULL
);
1384 close_fdesc(csd
, NULL
);
1385 close_unix_socket(ssd
, fdescs
[0].data
);
1387 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1389 if (asd
!= fdescs
[2].fd
) {
1390 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1393 close_fdesc(csd
, NULL
);
1394 close_unix_socket(ssd
, fdescs
[0].data
);
1396 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1402 if (iserver_shutdown
& (1 << 0))
1403 shutdown(asd
, SHUT_RD
);
1404 if (iserver_shutdown
& (1 << 1))
1405 shutdown(asd
, SHUT_WR
);
1406 if (iclient_shutdown
& (1 << 0))
1407 shutdown(csd
, SHUT_RD
);
1408 if (iclient_shutdown
& (1 << 1))
1409 shutdown(csd
, SHUT_WR
);
1414 static void *make_unix_stream(const struct factory
*factory
, struct fdesc fdescs
[],
1415 int argc
, char ** argv
)
1417 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1418 const char *stype
= ARG_STRING(type
);
1421 const char *typestr
;
1423 if (strcmp(stype
, "stream") == 0) {
1424 typesym
= SOCK_STREAM
;
1426 } else if (strcmp(stype
, "seqpacket") == 0) {
1427 typesym
= SOCK_SEQPACKET
;
1428 typestr
= "SEQPACKET";
1430 errx(EXIT_FAILURE
, "unknown unix socket type: %s", stype
);
1434 return make_unix_stream_core(factory
, fdescs
, argc
, argv
, typesym
, typestr
);
1437 static void *make_unix_dgram(const struct factory
*factory
, struct fdesc fdescs
[],
1438 int argc
, char ** argv
)
1440 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1441 const char *spath
= ARG_STRING(path
);
1443 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1444 bool babstract
= ARG_BOOLEAN(abstract
);
1446 int ssd
, csd
; /* server and client socket descriptors */
1448 struct sockaddr_un un
;
1449 size_t un_len
= sizeof(un
);
1451 memset(&un
, 0, sizeof(un
));
1452 un
.sun_family
= AF_UNIX
;
1454 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1455 size_t pathlen
= strlen(spath
);
1456 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1457 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1459 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1461 free_arg(&abstract
);
1464 ssd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1467 "failed to make a socket with AF_UNIX + SOCK_DGRAM (server side)");
1468 if (ssd
!= fdescs
[0].fd
) {
1469 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1473 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1479 fdescs
[0] = (struct fdesc
){
1481 .close
= close_unix_socket
,
1486 unlink(un
.sun_path
);
1487 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1491 err(EXIT_FAILURE
, "failed to bind a socket for server");
1495 fdescs
[0].data
= xstrdup(un
.sun_path
);
1496 csd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1499 "failed to make a socket with AF_UNIX + SOCK_DGRAM (client side)");
1500 if (csd
!= fdescs
[1].fd
) {
1501 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1504 close_unix_socket(ssd
, fdescs
[0].data
);
1506 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1512 fdescs
[1] = (struct fdesc
){
1514 .close
= close_fdesc
,
1518 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1520 close_fdesc(csd
, NULL
);
1521 close_unix_socket(ssd
, fdescs
[0].data
);
1523 err(EXIT_FAILURE
, "failed to connect a socket to the server socket");
1527 unlink(un
.sun_path
);
1532 static void *make_unix_in_new_netns(const struct factory
*factory
, struct fdesc fdescs
[],
1533 int argc
, char ** argv
)
1535 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1536 const char *stype
= ARG_STRING(type
);
1538 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1539 const char *spath
= ARG_STRING(path
);
1541 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1542 bool babstract
= ARG_BOOLEAN(abstract
);
1545 const char *typestr
;
1547 struct sockaddr_un un
;
1548 size_t un_len
= sizeof(un
);
1550 int self_netns
, tmp_netns
, sd
;
1552 if (strcmp(stype
, "stream") == 0) {
1553 typesym
= SOCK_STREAM
;
1555 } else if (strcmp(stype
, "seqpacket") == 0) {
1556 typesym
= SOCK_SEQPACKET
;
1557 typestr
= "SEQPACKET";
1558 } else if (strcmp(stype
, "dgram") == 0) {
1559 typesym
= SOCK_DGRAM
;
1562 free_arg(&abstract
);
1565 errx(EXIT_FAILURE
, "unknown unix socket type: %s", stype
);
1568 memset(&un
, 0, sizeof(un
));
1569 un
.sun_family
= AF_UNIX
;
1571 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1572 size_t pathlen
= strlen(spath
);
1573 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1574 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1576 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1578 free_arg(&abstract
);
1582 self_netns
= open("/proc/self/ns/net", O_RDONLY
);
1584 err(EXIT_FAILURE
, "failed to open /proc/self/ns/net");
1585 if (self_netns
!= fdescs
[0].fd
) {
1586 if (dup2(self_netns
, fdescs
[0].fd
) < 0) {
1590 err(EXIT_FAILURE
, "failed to dup %d -> %d", self_netns
, fdescs
[0].fd
);
1593 self_netns
= fdescs
[0].fd
;
1596 fdescs
[0] = (struct fdesc
){
1598 .close
= close_fdesc
,
1602 if (unshare(CLONE_NEWNET
) < 0) {
1604 close_fdesc(self_netns
, NULL
);
1606 err((errno
== EPERM
? EXIT_EPERM
: EXIT_FAILURE
),
1607 "failed in unshare");
1610 tmp_netns
= open("/proc/self/ns/net", O_RDONLY
);
1611 if (tmp_netns
< 0) {
1613 close_fdesc(self_netns
, NULL
);
1615 err(EXIT_FAILURE
, "failed to open /proc/self/ns/net for the new netns");
1617 if (tmp_netns
!= fdescs
[1].fd
) {
1618 if (dup2(tmp_netns
, fdescs
[1].fd
) < 0) {
1620 close_fdesc(self_netns
, NULL
);
1623 err(EXIT_FAILURE
, "failed to dup %d -> %d", tmp_netns
, fdescs
[1].fd
);
1626 tmp_netns
= fdescs
[1].fd
;
1629 fdescs
[1] = (struct fdesc
){
1631 .close
= close_fdesc
,
1635 sd
= socket(AF_UNIX
, typesym
, 0);
1638 close_fdesc(self_netns
, NULL
);
1639 close_fdesc(tmp_netns
, NULL
);
1642 "failed to make a socket with AF_UNIX + SOCK_%s",
1646 if (sd
!= fdescs
[2].fd
) {
1647 if (dup2(sd
, fdescs
[2].fd
) < 0) {
1649 close_fdesc(self_netns
, NULL
);
1650 close_fdesc(tmp_netns
, NULL
);
1653 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[2].fd
);
1659 fdescs
[2] = (struct fdesc
){
1661 .close
= close_unix_socket
,
1666 unlink(un
.sun_path
);
1667 if (bind(sd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1669 close_fdesc(self_netns
, NULL
);
1670 close_fdesc(tmp_netns
, NULL
);
1671 close_unix_socket(sd
, NULL
);
1673 err(EXIT_FAILURE
, "failed to bind a socket");
1677 fdescs
[2].data
= xstrdup(un
.sun_path
);
1679 if (typesym
!= SOCK_DGRAM
) {
1680 if (listen(sd
, 1) < 0) {
1682 close_fdesc(self_netns
, NULL
);
1683 close_fdesc(tmp_netns
, NULL
);
1684 close_unix_socket(sd
, fdescs
[2].data
);
1686 err(EXIT_FAILURE
, "failed to listen a socket");
1690 if (setns(self_netns
, CLONE_NEWNET
) < 0) {
1692 close_fdesc(self_netns
, NULL
);
1693 close_fdesc(tmp_netns
, NULL
);
1694 close_unix_socket(sd
, fdescs
[2].data
);
1696 err(EXIT_FAILURE
, "failed to swich back to the original net namespace");
1702 static void *make_tcp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1703 int argc
, char ** argv
,
1705 void (*init_addr
)(struct sockaddr
*, unsigned short),
1707 struct sockaddr
* sin
, struct sockaddr
* cin
)
1709 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1710 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1711 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1712 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1718 free_arg(&server_port
);
1719 free_arg(&client_port
);
1721 ssd
= socket(family
, SOCK_STREAM
, 0);
1724 "failed to make a tcp socket for listening");
1726 if (setsockopt(ssd
, SOL_SOCKET
,
1727 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1731 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1734 if (ssd
!= fdescs
[0].fd
) {
1735 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1739 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1745 init_addr(sin
, iserver_port
);
1746 if (bind(ssd
, sin
, addr_size
) < 0) {
1750 err(EXIT_FAILURE
, "failed to bind a listening socket");
1753 if (listen(ssd
, 1) < 0) {
1757 err(EXIT_FAILURE
, "failed to listen a socket");
1760 csd
= socket(family
, SOCK_STREAM
, 0);
1766 "failed to make a tcp client socket");
1769 if (setsockopt(csd
, SOL_SOCKET
,
1770 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1775 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1778 if (csd
!= fdescs
[1].fd
) {
1779 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1784 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1790 init_addr(cin
, iclient_port
);
1791 if (bind(csd
, cin
, addr_size
) < 0) {
1796 err(EXIT_FAILURE
, "failed to bind a client socket");
1799 if (connect(csd
, sin
, addr_size
) < 0) {
1804 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1807 asd
= accept(ssd
, NULL
, NULL
);
1813 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1815 if (asd
!= fdescs
[2].fd
) {
1816 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1821 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1827 fdescs
[0] = (struct fdesc
) {
1829 .close
= close_fdesc
,
1832 fdescs
[1] = (struct fdesc
) {
1834 .close
= close_fdesc
,
1837 fdescs
[2] = (struct fdesc
) {
1839 .close
= close_fdesc
,
1846 static void tcp_init_addr(struct sockaddr
*addr
, unsigned short port
)
1848 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
1849 memset(in
, 0, sizeof(*in
));
1850 in
->sin_family
= AF_INET
;
1851 in
->sin_port
= htons(port
);
1852 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1855 static void *make_tcp(const struct factory
*factory
, struct fdesc fdescs
[],
1856 int argc
, char ** argv
)
1858 struct sockaddr_in sin
, cin
;
1859 return make_tcp_common(factory
, fdescs
, argc
, argv
,
1861 tcp_init_addr
, sizeof(sin
),
1862 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1865 static void *make_udp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1866 int argc
, char ** argv
,
1868 void (*init_addr
)(struct sockaddr
*, unsigned short),
1870 struct sockaddr
* sin
, struct sockaddr
* cin
)
1872 struct arg lite
= decode_arg("lite", factory
->params
, argc
, argv
);
1873 bool blite
= ARG_BOOLEAN(lite
);
1875 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1876 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1877 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1878 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1880 struct arg server_do_bind
= decode_arg("server-do-bind", factory
->params
, argc
, argv
);
1881 bool bserver_do_bind
= ARG_BOOLEAN(server_do_bind
);
1882 struct arg client_do_bind
= decode_arg("client-do-bind", factory
->params
, argc
, argv
);
1883 bool bclient_do_bind
= ARG_BOOLEAN(client_do_bind
);
1884 struct arg client_do_connect
= decode_arg("client-do-connect", factory
->params
, argc
, argv
);
1885 bool bclient_do_connect
= ARG_BOOLEAN(client_do_connect
);
1891 free_arg(&client_do_connect
);
1892 free_arg(&client_do_bind
);
1893 free_arg(&server_do_bind
);
1894 free_arg(&server_port
);
1895 free_arg(&client_port
);
1898 ssd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1901 "failed to make a udp socket for server");
1903 if (setsockopt(ssd
, SOL_SOCKET
,
1904 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1908 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1911 if (ssd
!= fdescs
[0].fd
) {
1912 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1916 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1922 init_addr(sin
, iserver_port
);
1923 if (bserver_do_bind
) {
1924 if (bind(ssd
, sin
, addr_size
) < 0) {
1928 err(EXIT_FAILURE
, "failed to bind a server socket");
1932 csd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1938 "failed to make a udp client socket");
1941 if (setsockopt(csd
, SOL_SOCKET
,
1942 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1947 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1950 if (csd
!= fdescs
[1].fd
) {
1951 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1956 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1962 if (bclient_do_bind
) {
1963 init_addr(cin
, iclient_port
);
1964 if (bind(csd
, cin
, addr_size
) < 0) {
1969 err(EXIT_FAILURE
, "failed to bind a client socket");
1973 if (bclient_do_connect
) {
1974 if (connect(csd
, sin
, addr_size
) < 0) {
1979 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1983 fdescs
[0] = (struct fdesc
) {
1985 .close
= close_fdesc
,
1988 fdescs
[1] = (struct fdesc
) {
1990 .close
= close_fdesc
,
1997 static void *make_udp(const struct factory
*factory
, struct fdesc fdescs
[],
1998 int argc
, char ** argv
)
2000 struct sockaddr_in sin
, cin
;
2001 return make_udp_common(factory
, fdescs
, argc
, argv
,
2003 tcp_init_addr
, sizeof(sin
),
2004 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2007 static void *make_raw_common(const struct factory
*factory
, struct fdesc fdescs
[],
2008 int argc
, char ** argv
,
2010 void (*init_addr
)(struct sockaddr
*, bool),
2012 struct sockaddr
* sin
)
2014 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
2015 int iprotocol
= ARG_INTEGER(protocol
);
2018 free_arg(&protocol
);
2020 ssd
= socket(family
, SOCK_RAW
, iprotocol
);
2023 "failed to make a udp socket for server");
2025 if (ssd
!= fdescs
[0].fd
) {
2026 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
2030 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
2036 init_addr(sin
, false);
2037 if (bind(ssd
, sin
, addr_size
) < 0) {
2041 err(EXIT_FAILURE
, "failed in bind(2)");
2044 init_addr(sin
, true);
2045 if (connect(ssd
, sin
, addr_size
) < 0) {
2049 err(EXIT_FAILURE
, "failed in connect(2)");
2052 fdescs
[0] = (struct fdesc
) {
2054 .close
= close_fdesc
,
2061 static void raw_init_addr(struct sockaddr
* addr
, bool remote_addr
)
2063 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
2064 memset(in
, 0, sizeof(*in
));
2065 in
->sin_family
= AF_INET
;
2066 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
+ (remote_addr
? 1: 0));
2069 static void *make_raw(const struct factory
*factory
, struct fdesc fdescs
[],
2070 int argc
, char ** argv
)
2072 struct sockaddr_in sin
;
2073 return make_raw_common(factory
, fdescs
, argc
, argv
,
2075 raw_init_addr
, sizeof(sin
),
2076 (struct sockaddr
*)&sin
);
2079 static void *make_ping_common(const struct factory
*factory
, struct fdesc fdescs
[],
2080 int argc
, char ** argv
,
2081 int family
, int protocol
,
2082 void (*init_addr
)(struct sockaddr
*, unsigned short),
2084 struct sockaddr
*sin
)
2086 struct arg connect_
= decode_arg("connect", factory
->params
, argc
, argv
);
2087 bool bconnect
= ARG_BOOLEAN(connect_
);
2089 struct arg bind_
= decode_arg("bind", factory
->params
, argc
, argv
);
2090 bool bbind
= ARG_BOOLEAN(bind_
);
2092 struct arg id
= decode_arg("id", factory
->params
, argc
, argv
);
2093 unsigned short iid
= (unsigned short)ARG_INTEGER(id
);
2099 free_arg(&connect_
);
2101 sd
= socket(family
, SOCK_DGRAM
, protocol
);
2103 err((errno
== EACCES
? EXIT_EACCES
: EXIT_FAILURE
),
2104 "failed to make an icmp socket");
2106 if (sd
!= fdescs
[0].fd
) {
2107 if (dup2(sd
, fdescs
[0].fd
) < 0) {
2111 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
2118 init_addr(sin
, iid
);
2119 if (bind(sd
, sin
, addr_size
) < 0) {
2123 err((errno
== EACCES
? EXIT_EACCES
: EXIT_FAILURE
),
2124 "failed in bind(2)");
2130 if (connect(sd
, sin
, addr_size
) < 0) {
2134 err(EXIT_FAILURE
, "failed in connect(2)");
2138 fdescs
[0] = (struct fdesc
) {
2140 .close
= close_fdesc
,
2147 static void ping_init_addr(struct sockaddr
*addr
, unsigned short id
)
2149 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
2150 memset(in
, 0, sizeof(*in
));
2151 in
->sin_family
= AF_INET
;
2152 in
->sin_port
= htons(id
);
2153 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2156 static void *make_ping(const struct factory
*factory
, struct fdesc fdescs
[],
2157 int argc
, char ** argv
)
2159 struct sockaddr_in in
;
2160 return make_ping_common(factory
, fdescs
, argc
, argv
,
2161 AF_INET
, IPPROTO_ICMP
,
2164 (struct sockaddr
*)&in
);
2167 static void tcp6_init_addr(struct sockaddr
*addr
, unsigned short port
)
2169 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2170 memset(in6
, 0, sizeof(*in6
));
2171 in6
->sin6_family
= AF_INET6
;
2172 in6
->sin6_flowinfo
= 0;
2173 in6
->sin6_port
= htons(port
);
2174 in6
->sin6_addr
= in6addr_loopback
;
2177 static void *make_tcp6(const struct factory
*factory
, struct fdesc fdescs
[],
2178 int argc
, char ** argv
)
2180 struct sockaddr_in6 sin
, cin
;
2181 return make_tcp_common(factory
, fdescs
, argc
, argv
,
2183 tcp6_init_addr
, sizeof(sin
),
2184 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2187 static void *make_udp6(const struct factory
*factory
, struct fdesc fdescs
[],
2188 int argc
, char ** argv
)
2190 struct sockaddr_in6 sin
, cin
;
2191 return make_udp_common(factory
, fdescs
, argc
, argv
,
2193 tcp6_init_addr
, sizeof(sin
),
2194 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2197 static void raw6_init_addr(struct sockaddr
*addr
, bool remote_addr
)
2199 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2200 memset(in6
, 0, sizeof(*in6
));
2201 in6
->sin6_family
= AF_INET6
;
2202 in6
->sin6_flowinfo
= 0;
2205 /* ::ffff:127.0.0.1 */
2206 in6
->sin6_addr
.s6_addr16
[5] = 0xffff;
2207 in6
->sin6_addr
.s6_addr32
[3] = htonl(INADDR_LOOPBACK
);
2209 in6
->sin6_addr
= in6addr_loopback
;
2212 static void *make_raw6(const struct factory
*factory
, struct fdesc fdescs
[],
2213 int argc
, char ** argv
)
2215 struct sockaddr_in6 sin
;
2216 return make_raw_common(factory
, fdescs
, argc
, argv
,
2218 raw6_init_addr
, sizeof(sin
),
2219 (struct sockaddr
*)&sin
);
2222 static void ping6_init_addr(struct sockaddr
*addr
, unsigned short id
)
2224 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2225 memset(in6
, 0, sizeof(*in6
));
2226 in6
->sin6_family
= AF_INET6
;
2227 in6
->sin6_port
= htons(id
);
2228 in6
->sin6_addr
= in6addr_loopback
;
2231 static void *make_ping6(const struct factory
*factory
, struct fdesc fdescs
[],
2232 int argc
, char ** argv
)
2234 struct sockaddr_in6 in6
;
2235 return make_ping_common(factory
, fdescs
, argc
, argv
,
2236 AF_INET6
, IPPROTO_ICMPV6
,
2239 (struct sockaddr
*)&in6
);
2243 static void *make_netns(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2244 int argc _U_
, char ** argv _U_
)
2246 int sd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
2248 err(EXIT_FAILURE
, "failed in socket()");
2250 int ns
= ioctl(sd
, SIOCGSKNS
);
2252 err_nosys(EXIT_FAILURE
, "failed in ioctl(SIOCGSKNS)");
2255 if (ns
!= fdescs
[0].fd
) {
2256 if (dup2(ns
, fdescs
[0].fd
) < 0) {
2260 err(EXIT_FAILURE
, "failed to dup %d -> %d", ns
, fdescs
[0].fd
);
2265 fdescs
[0] = (struct fdesc
){
2267 .close
= close_fdesc
,
2273 #endif /* SIOCGSKNS */
2275 static void *make_netlink(const struct factory
*factory
, struct fdesc fdescs
[],
2276 int argc
, char ** argv
)
2278 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
2279 int iprotocol
= ARG_INTEGER(protocol
);
2280 struct arg groups
= decode_arg("groups", factory
->params
, argc
, argv
);
2281 unsigned int ugroups
= ARG_UINTEGER(groups
);
2284 free_arg(&protocol
);
2286 sd
= socket(AF_NETLINK
, SOCK_RAW
, iprotocol
);
2288 err((errno
== EPROTONOSUPPORT
)? EXIT_EPROTONOSUPPORT
: EXIT_FAILURE
,
2289 "failed in socket()");
2291 if (sd
!= fdescs
[0].fd
) {
2292 if (dup2(sd
, fdescs
[0].fd
) < 0) {
2296 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
2302 struct sockaddr_nl nl
;
2303 memset(&nl
, 0, sizeof(nl
));
2304 nl
.nl_family
= AF_NETLINK
;
2305 nl
.nl_groups
= ugroups
;
2306 if (bind(sd
, (struct sockaddr
*)&nl
, sizeof(nl
)) < 0) {
2310 err(EXIT_FAILURE
, "failed in bind(2)");
2313 fdescs
[0] = (struct fdesc
){
2315 .close
= close_fdesc
,
2322 static void *make_eventfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2323 int argc _U_
, char ** argv _U_
)
2326 pid_t
*pid
= xcalloc(1, sizeof(*pid
));
2328 if (fdescs
[0].fd
== fdescs
[1].fd
)
2329 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2333 err(EXIT_FAILURE
, "failed in eventfd(2)");
2335 if (fd
!= fdescs
[0].fd
) {
2336 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2340 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2345 fdescs
[0] = (struct fdesc
){
2347 .close
= close_fdesc
,
2351 if (dup2(fdescs
[0].fd
, fdescs
[1].fd
) < 0) {
2353 close(fdescs
[0].fd
);
2355 err(EXIT_FAILURE
, "failed to dup %d -> %d", fdescs
[0].fd
, fdescs
[1].fd
);
2358 signal(SIGCHLD
, abort_with_child_death_message
);
2362 close(fdescs
[0].fd
);
2363 close(fdescs
[1].fd
);
2365 err(EXIT_FAILURE
, "failed in fork()");
2366 } else if (*pid
== 0) {
2370 close(fdescs
[0].fd
);
2372 signal(SIGCONT
, do_nothing
);
2373 /* Notify the parent that I'm ready. */
2374 if (write(fdescs
[1].fd
, &v
, sizeof(v
)) != sizeof(v
)) {
2375 close(fdescs
[1].fd
);
2377 "failed in write() to notify the readiness to the prent");
2379 /* Wait till the parent lets me go. */
2382 close(fdescs
[1].fd
);
2387 /* The child owns fdescs[1]. */
2388 close(fdescs
[1].fd
);
2391 /* Wait till the child is ready. */
2392 if (read(fdescs
[0].fd
, &v
, sizeof(uint64_t)) != sizeof(v
)) {
2394 close(fdescs
[0].fd
);
2396 "failed in read() the readiness notification from the child");
2398 signal(SIGCHLD
, SIG_DFL
);
2404 static void report_eventfd(const struct factory
*factory _U_
,
2405 int nth
, void *data
, FILE *fp
)
2408 pid_t
*child
= data
;
2409 fprintf(fp
, "%d", *child
);
2413 static void free_eventfd(const struct factory
* factory _U_
, void *data
)
2415 pid_t child
= *(pid_t
*)data
;
2420 kill(child
, SIGCONT
);
2421 if (waitpid(child
, &wstatus
, 0) < 0)
2422 err(EXIT_FAILURE
, "failed in waitpid()");
2424 if (WIFEXITED(wstatus
)) {
2425 int s
= WEXITSTATUS(wstatus
);
2427 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2428 } else if (WIFSIGNALED(wstatus
)) {
2429 int s
= WTERMSIG(wstatus
);
2430 if (WTERMSIG(wstatus
) != 0)
2431 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2435 struct mqueue_data
{
2441 static void mqueue_data_free(struct mqueue_data
*data
)
2444 mq_unlink(data
->path
);
2445 free((void *)data
->path
);
2449 static void report_mqueue(const struct factory
*factory _U_
,
2450 int nth
, void *data
, FILE *fp
)
2453 fprintf(fp
, "%d", ((struct mqueue_data
*)data
)->pid
);
2457 static void close_mqueue(int fd
, void *data _U_
)
2462 static void free_mqueue(const struct factory
* factory _U_
, void *data
)
2464 struct mqueue_data
*mqueue_data
= data
;
2465 pid_t child
= mqueue_data
->pid
;
2468 mqueue_data_free(mqueue_data
);
2470 kill(child
, SIGCONT
);
2471 if (waitpid(child
, &wstatus
, 0) < 0)
2472 err(EXIT_FAILURE
, "failed in waitpid()");
2474 if (WIFEXITED(wstatus
)) {
2475 int s
= WEXITSTATUS(wstatus
);
2477 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2478 } else if (WIFSIGNALED(wstatus
)) {
2479 int s
= WTERMSIG(wstatus
);
2480 if (WTERMSIG(wstatus
) != 0)
2481 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2485 static void *make_mqueue(const struct factory
*factory
, struct fdesc fdescs
[],
2486 int argc
, char ** argv
)
2488 struct mqueue_data
*mqueue_data
;
2489 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
2490 const char *spath
= ARG_STRING(path
);
2492 struct mq_attr attr
= {
2499 if (spath
[0] != '/')
2500 errx(EXIT_FAILURE
, "the path for mqueue must start with '/': %s", spath
);
2502 if (spath
[0] == '\0')
2503 err(EXIT_FAILURE
, "the path should not be empty");
2505 if (fdescs
[0].fd
== fdescs
[1].fd
)
2506 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2508 mqueue_data
= xmalloc(sizeof(*mqueue_data
));
2509 mqueue_data
->pid
= 0;
2510 mqueue_data
->path
= xstrdup(spath
);
2511 mqueue_data
->created
= false;
2515 fd
= mq_open(mqueue_data
->path
, O_CREAT
|O_EXCL
| O_RDONLY
, S_IRUSR
| S_IWUSR
, &attr
);
2517 mqueue_data_free(mqueue_data
);
2518 err(EXIT_FAILURE
, "failed in mq_open(3) for reading");
2521 mqueue_data
->created
= true;
2522 if (fd
!= fdescs
[0].fd
) {
2523 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2526 mqueue_data_free(mqueue_data
);
2528 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2533 fdescs
[0] = (struct fdesc
){
2535 .close
= close_mqueue
,
2539 fd
= mq_open(mqueue_data
->path
, O_WRONLY
, S_IRUSR
| S_IWUSR
, NULL
);
2542 mq_close(fdescs
[0].fd
);
2543 mqueue_data_free(mqueue_data
);
2545 err(EXIT_FAILURE
, "failed in mq_open(3) for writing");
2548 if (fd
!= fdescs
[1].fd
) {
2549 if (dup2(fd
, fdescs
[1].fd
) < 0) {
2552 mq_close(fdescs
[0].fd
);
2554 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[1].fd
);
2558 fdescs
[1] = (struct fdesc
){
2560 .close
= close_mqueue
,
2564 signal(SIGCHLD
, abort_with_child_death_message
);
2565 mqueue_data
->pid
= fork();
2566 if (mqueue_data
->pid
< -1) {
2568 mq_close(fdescs
[0].fd
);
2569 mq_close(fdescs
[1].fd
);
2570 mqueue_data_free(mqueue_data
);
2572 err(EXIT_FAILURE
, "failed in fork()");
2573 } else if (mqueue_data
->pid
== 0) {
2574 mqueue_data
->created
= false;
2575 mqueue_data_free(mqueue_data
);
2576 mq_close(fdescs
[0].fd
);
2578 signal(SIGCONT
, do_nothing
);
2579 /* Notify the parent that I'm ready. */
2580 if (mq_send(fdescs
[1].fd
, "", 0, 0) < 0)
2582 "failed in mq_send() to notify the readiness to the prent");
2583 /* Wait till the parent lets me go. */
2586 mq_close(fdescs
[1].fd
);
2591 /* The child owns fdescs[1]. */
2592 mq_close(fdescs
[1].fd
);
2595 /* Wait till the child is ready. */
2596 if (mq_receive(fdescs
[0].fd
, &c
, 1, NULL
) < 0) {
2597 mq_close(fdescs
[0].fd
);
2598 mqueue_data_free(mqueue_data
);
2600 "failed in mq_receive() the readiness notification from the child");
2602 signal(SIGCHLD
, SIG_DFL
);
2607 struct sysvshm_data
{
2612 static void *make_sysvshm(const struct factory
*factory _U_
, struct fdesc fdescs
[] _U_
,
2613 int argc _U_
, char ** argv _U_
)
2615 size_t pagesize
= getpagesize();
2616 struct sysvshm_data
*sysvshm_data
;
2617 int id
= shmget(IPC_PRIVATE
, pagesize
, IPC_CREAT
| 0600);
2621 err(EXIT_FAILURE
, "failed to do shmget(.., %zu, ...)",
2624 start
= shmat(id
, NULL
, SHM_RDONLY
);
2625 if (start
== (void *) -1) {
2627 shmctl(id
, IPC_RMID
, NULL
);
2629 err(EXIT_FAILURE
, "failed to do shmat(%d,...)", id
);
2632 sysvshm_data
= xmalloc(sizeof(*sysvshm_data
));
2633 sysvshm_data
->addr
= start
;
2634 sysvshm_data
->id
= id
;
2635 return sysvshm_data
;
2638 static void free_sysvshm(const struct factory
*factory _U_
, void *data
)
2640 struct sysvshm_data
*sysvshm_data
= data
;
2642 shmdt(sysvshm_data
->addr
);
2643 shmctl(sysvshm_data
->id
, IPC_RMID
, NULL
);
2646 static void *make_eventpoll(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2647 int argc _U_
, char ** argv _U_
)
2656 .file
= "DUMMY, DONT'USE THIS"
2658 .file
= "/dev/random",
2662 .file
= "/dev/random",
2668 efd
= epoll_create(1);
2670 err(EXIT_FAILURE
, "failed in epoll_create(2)");
2671 if (efd
!= fdescs
[0].fd
) {
2672 if (dup2(efd
, fdescs
[0].fd
) < 0) {
2676 err(EXIT_FAILURE
, "failed to dup %d -> %d", efd
, fdescs
[0].fd
);
2681 fdescs
[0] = (struct fdesc
){
2683 .close
= close_fdesc
,
2687 for (size_t i
= 1; i
< ARRAY_SIZE(specs
); i
++) {
2688 int fd
= open(specs
[i
].file
, specs
[i
].flag
);
2692 for (size_t j
= i
- 1; j
> 0; j
--)
2693 close(fdescs
[j
].fd
);
2695 err(EXIT_FAILURE
, "failed in open(\"%s\",...)",
2698 if (fd
!= fdescs
[i
].fd
) {
2699 if (dup2(fd
, fdescs
[i
].fd
) < 0) {
2702 for (size_t j
= i
- 1; j
> 0; j
--)
2703 close(fdescs
[j
].fd
);
2706 err(EXIT_FAILURE
, "failed to dup %d -> %d",
2711 fdescs
[i
] = (struct fdesc
) {
2713 .close
= close_fdesc
,
2716 if (epoll_ctl(efd
, EPOLL_CTL_ADD
, fdescs
[i
].fd
,
2717 &(struct epoll_event
) {
2718 .events
= specs
[i
].events
,
2719 .data
= {.ptr
= NULL
,}
2723 for (size_t j
= i
; j
> 0; j
--)
2724 close(fdescs
[j
].fd
);
2727 "failed to add fd %d to the eventpoll fd with epoll_ctl",
2735 static bool decode_clockid(const char *sclockid
, clockid_t
*clockid
)
2737 if (sclockid
== NULL
)
2739 if (sclockid
[0] == '\0')
2742 if (strcmp(sclockid
, "realtime") == 0)
2743 *clockid
= CLOCK_REALTIME
;
2744 else if (strcmp(sclockid
, "monotonic") == 0)
2745 *clockid
= CLOCK_MONOTONIC
;
2746 else if (strcmp(sclockid
, "boottime") == 0)
2747 *clockid
= CLOCK_BOOTTIME
;
2748 else if (strcmp(sclockid
, "realtime-alarm") == 0)
2749 *clockid
= CLOCK_REALTIME_ALARM
;
2750 else if (strcmp(sclockid
, "boottime-alarm") == 0)
2751 *clockid
= CLOCK_BOOTTIME_ALARM
;
2757 static void *make_timerfd(const struct factory
*factory
, struct fdesc fdescs
[],
2758 int argc
, char ** argv
)
2761 struct timespec now
;
2762 struct itimerspec tspec
;
2764 struct arg abstime
= decode_arg("abstime", factory
->params
, argc
, argv
);
2765 bool babstime
= ARG_BOOLEAN(abstime
);
2767 struct arg remaining
= decode_arg("remaining", factory
->params
, argc
, argv
);
2768 unsigned int uremaining
= ARG_UINTEGER(remaining
);
2770 struct arg interval
= decode_arg("interval", factory
->params
, argc
, argv
);
2771 unsigned int uinterval
= ARG_UINTEGER(interval
);
2773 struct arg interval_frac
= decode_arg("interval-nanofrac", factory
->params
, argc
, argv
);
2774 unsigned int uinterval_frac
= ARG_UINTEGER(interval_frac
);
2776 struct arg clockid_
= decode_arg("clockid", factory
->params
, argc
, argv
);
2777 const char *sclockid
= ARG_STRING(clockid_
);
2780 if (decode_clockid (sclockid
, &clockid
) == false)
2781 err(EXIT_FAILURE
, "unknown clockid: %s", sclockid
);
2783 free_arg(&clockid_
);
2784 free_arg(&interval_frac
);
2785 free_arg(&interval
);
2786 free_arg(&remaining
);
2790 int r
= clock_gettime(clockid
, &now
);
2792 err(EXIT_FAILURE
, "failed in clock_gettime(2)");
2795 tfd
= timerfd_create(clockid
, 0);
2797 err(EXIT_FAILURE
, "failed in timerfd_create(2)");
2799 tspec
.it_value
.tv_sec
= (babstime
? now
.tv_sec
: 0) + uremaining
;
2800 tspec
.it_value
.tv_nsec
= (babstime
? now
.tv_nsec
: 0);
2802 tspec
.it_interval
.tv_sec
= uinterval
;
2803 tspec
.it_interval
.tv_nsec
= uinterval_frac
;
2805 if (timerfd_settime(tfd
, babstime
? TFD_TIMER_ABSTIME
: 0, &tspec
, NULL
) < 0) {
2809 err(EXIT_FAILURE
, "failed in timerfd_settime(2)");
2812 if (tfd
!= fdescs
[0].fd
) {
2813 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2817 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2822 fdescs
[0] = (struct fdesc
){
2824 .close
= close_fdesc
,
2831 static void *make_signalfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2832 int argc _U_
, char ** argv _U_
)
2837 if (sigemptyset(&mask
) < 0)
2838 err(EXIT_FAILURE
, "failed in sigemptyset()");
2839 if (sigaddset(&mask
, SIGFPE
) < 0)
2840 err(EXIT_FAILURE
, "failed in sigaddset(FPE)");
2841 if (sigaddset(&mask
, SIGUSR1
) < 0)
2842 err(EXIT_FAILURE
, "failed in sigaddset(USR1)");
2843 if (sigaddset(&mask
, numsig
) < 0)
2844 err(EXIT_FAILURE
, "failed in sigaddset(%d)", numsig
);
2846 int sfd
= signalfd(-1, &mask
, 0);
2848 err(EXIT_FAILURE
, "failed in signalfd(2)");
2850 if (sfd
!= fdescs
[0].fd
) {
2851 if (dup2(sfd
, fdescs
[0].fd
) < 0) {
2855 err(EXIT_FAILURE
, "failed to dup %d -> %d", sfd
, fdescs
[0].fd
);
2860 fdescs
[0] = (struct fdesc
){
2862 .close
= close_fdesc
,
2870 /* ref. linux/Documentation/networking/tuntap.rst */
2871 static void *make_cdev_tun(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2872 int argc _U_
, char ** argv _U_
)
2874 int tfd
= open("/dev/net/tun", O_RDWR
);
2878 err(EXIT_FAILURE
, "failed in opening /dev/net/tun");
2880 memset(&ifr
, 0, sizeof(ifr
));
2882 ifr
.ifr_flags
= IFF_TUN
;
2883 strcpy(ifr
.ifr_name
, "mkfds%d");
2885 if (ioctl(tfd
, TUNSETIFF
, (void *) &ifr
) < 0) {
2889 err(EXIT_FAILURE
, "failed in setting \"lo\" to the tun device");
2892 if (tfd
!= fdescs
[0].fd
) {
2893 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2897 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2902 fdescs
[0] = (struct fdesc
){
2904 .close
= close_fdesc
,
2908 return xstrdup(ifr
.ifr_name
);
2911 static void report_cdev_tun(const struct factory
*factory _U_
,
2912 int nth
, void *data
, FILE *fp
)
2915 char *devname
= data
;
2916 fprintf(fp
, "%s", devname
);
2920 static void free_cdev_tun(const struct factory
* factory _U_
, void *data
)
2925 static void *make_bpf_prog(const struct factory
*factory
, struct fdesc fdescs
[],
2926 int argc
, char ** argv
)
2928 struct arg prog_type_id
= decode_arg("prog-type-id", factory
->params
, argc
, argv
);
2929 int iprog_type_id
= ARG_INTEGER(prog_type_id
);
2931 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
2932 const char *sname
= ARG_STRING(name
);
2935 union bpf_attr attr
;
2936 /* Just doing exit with 0. */
2937 struct bpf_insn insns
[] = {
2939 .code
= BPF_ALU64
| BPF_MOV
| BPF_K
,
2940 .dst_reg
= BPF_REG_0
, .src_reg
= 0, .off
= 0, .imm
= 0
2943 .code
= BPF_JMP
| BPF_EXIT
,
2944 .dst_reg
= 0, .src_reg
= 0, .off
= 0, .imm
= 0
2948 memset(&attr
, 0, sizeof(attr
));
2949 attr
.prog_type
= iprog_type_id
;
2950 attr
.insns
= (uint64_t)(unsigned long)insns
;
2951 attr
.insn_cnt
= ARRAY_SIZE(insns
);
2952 attr
.license
= (int64_t)(unsigned long)"GPL";
2953 strncpy(attr
.prog_name
, sname
, sizeof(attr
.prog_name
) - 1);
2956 free_arg(&prog_type_id
);
2958 bfd
= syscall(SYS_bpf
, BPF_PROG_LOAD
, &attr
, sizeof(attr
));
2960 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_PROG_LOAD)");
2962 if (bfd
!= fdescs
[0].fd
) {
2963 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
2967 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
2972 fdescs
[0] = (struct fdesc
){
2974 .close
= close_fdesc
,
2981 static void *make_some_pipes(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2982 int argc _U_
, char ** argv _U_
)
2984 /* Reserver fds before making pipes */
2985 for (int i
= 0; i
< factory
->N
; i
++) {
2986 close(fdescs
[i
].fd
);
2987 if (dup2(0, fdescs
[0].fd
) < 0)
2988 err(EXIT_FAILURE
, "failed to reserve fd %d with dup2", fdescs
[0].fd
);
2991 for (int i
= 0; i
< (factory
->N
) / 2; i
++) {
2996 mode
= 1 << (i
% 3);
2997 if (mode
== MX_WRITE
) {
3003 err(EXIT_FAILURE
, "failed to make pipe");
3005 if (dup2(pd
[0], fdescs
[2 * i
+ r
].fd
) < 0)
3006 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[0], fdescs
[2 * i
+ r
].fd
);
3008 fdescs
[2 * 1 + r
].close
= close_fdesc
;
3010 if (dup2(pd
[1], fdescs
[2 * i
+ w
].fd
) < 0)
3011 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[1], fdescs
[2 * i
+ 2].fd
);
3013 fdescs
[2 * 1 + w
].close
= close_fdesc
;
3015 fdescs
[2 * i
].mx_modes
|= mode
;
3017 /* Make the pipe for writing full. */
3018 if (fdescs
[2 * i
].mx_modes
& MX_WRITE
) {
3019 int n
= fcntl(fdescs
[2 * i
].fd
, F_GETPIPE_SZ
);
3023 err(EXIT_FAILURE
, "failed to get PIPE BUFFER SIZE from %d", fdescs
[2 * i
].fd
);
3026 if (write(fdescs
[2 * i
].fd
, buf
, n
) != n
)
3027 err(EXIT_FAILURE
, "failed to fill the pipe buffer specified with %d",
3037 static void *make_bpf_map(const struct factory
*factory
, struct fdesc fdescs
[],
3038 int argc
, char ** argv
)
3040 struct arg map_type_id
= decode_arg("map-type-id", factory
->params
, argc
, argv
);
3041 int imap_type_id
= ARG_INTEGER(map_type_id
);
3043 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
3044 const char *sname
= ARG_STRING(name
);
3047 union bpf_attr attr
= {
3048 .map_type
= imap_type_id
,
3054 strncpy(attr
.map_name
, sname
, sizeof(attr
.map_name
) - 1);
3057 free_arg(&map_type_id
);
3059 bfd
= syscall(SYS_bpf
, BPF_MAP_CREATE
, &attr
, sizeof(attr
));
3061 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_MAP_CREATE)");
3063 if (bfd
!= fdescs
[0].fd
) {
3064 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
3068 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
3073 fdescs
[0] = (struct fdesc
){
3075 .close
= close_fdesc
,
3082 static void *make_pty(const struct factory
*factory _U_
, struct fdesc fdescs
[],
3083 int argc _U_
, char ** argv _U_
)
3088 int ptmx_fd
= posix_openpt(O_RDWR
);
3090 err(EXIT_FAILURE
, "failed in opening /dev/ptmx");
3092 if (unlockpt(ptmx_fd
) < 0) {
3096 err(EXIT_FAILURE
, "failed in unlockpt()");
3099 if (ioctl(ptmx_fd
, TIOCGPTN
, &index
) < 0) {
3103 err(EXIT_FAILURE
, "failed in ioctl(TIOCGPTN)");
3106 pts
= ptsname(ptmx_fd
);
3111 err(EXIT_FAILURE
, "failed in ptsname()");
3114 if (ptmx_fd
!= fdescs
[0].fd
) {
3115 if (dup2(ptmx_fd
, fdescs
[0].fd
) < 0) {
3119 err(EXIT_FAILURE
, "failed to dup %d -> %d", ptmx_fd
, fdescs
[0].fd
);
3122 ptmx_fd
= fdescs
[0].fd
;
3125 pts_fd
= open(pts
, O_RDONLY
);
3130 err(EXIT_FAILURE
, "failed in opening %s", pts
);
3133 if (pts_fd
!= fdescs
[1].fd
) {
3134 if (dup2(pts_fd
, fdescs
[1].fd
) < 0) {
3139 err(EXIT_FAILURE
, "failed to dup %d -> %d", pts_fd
, fdescs
[1].fd
);
3142 pts_fd
= fdescs
[1].fd
;
3145 fdescs
[0] = (struct fdesc
){
3147 .close
= close_fdesc
,
3150 fdescs
[1] = (struct fdesc
){
3152 .close
= close_fdesc
,
3156 indexp
= xmalloc(sizeof(index
));
3161 static void report_pty(const struct factory
*factory _U_
,
3162 int nth
, void *data
, FILE *fp
)
3166 fprintf(fp
, "%d", *index
);
3170 static void free_pty(const struct factory
* factory _U_
, void *data
)
3180 static void *make_mmap(const struct factory
*factory
, struct fdesc fdescs
[] _U_
,
3181 int argc
, char ** argv
)
3183 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
3184 const char *sfile
= ARG_STRING(file
);
3186 int fd
= open(sfile
, O_RDONLY
);
3188 err(EXIT_FAILURE
, "failed in opening %s", sfile
);
3192 if (fstat(fd
, &sb
) < 0) {
3196 err(EXIT_FAILURE
, "failed in fstat()");
3198 char *addr
= mmap(NULL
, sb
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
3199 if (addr
== MAP_FAILED
) {
3203 err(EXIT_FAILURE
, "failed in mmap()");
3207 struct mmap_data
*data
= xmalloc(sizeof(*data
));
3209 data
->len
= sb
.st_size
;
3214 /* Do as unshare --map-root-user. */
3215 static void map_root_user(uid_t uid
, uid_t gid
)
3222 n
= snprintf(buf
, sizeof(buf
), "0 %d 1", uid
);
3223 mapfd
= open("/proc/self/uid_map", O_WRONLY
);
3226 "failed to open /proc/self/uid_map");
3227 r
= write (mapfd
, buf
, n
);
3230 "failed to write to /proc/self/uid_map");
3233 "failed to write to /proc/self/uid_map");
3236 mapfd
= open("/proc/self/setgroups", O_WRONLY
);
3239 "failed to open /proc/self/setgroups");
3240 r
= write (mapfd
, "deny", 4);
3243 "failed to write to /proc/self/setgroups");
3246 "failed to write to /proc/self/setgroups");
3249 n
= snprintf(buf
, sizeof(buf
), "0 %d 1", gid
);
3250 mapfd
= open("/proc/self/gid_map", O_WRONLY
);
3253 "failed to open /proc/self/gid_map");
3254 r
= write (mapfd
, buf
, n
);
3257 "failed to write to /proc/self/gid_map");
3260 "failed to write to /proc/self/gid_map");
3264 static void *make_userns(const struct factory
*factory _U_
, struct fdesc fdescs
[],
3265 int argc _U_
, char ** argv _U_
)
3267 uid_t uid
= geteuid();
3268 uid_t gid
= getegid();
3270 if (unshare(CLONE_NEWUSER
) < 0)
3271 err((errno
== EPERM
? EXIT_EPERM
: EXIT_FAILURE
),
3272 "failed in the 1st unshare(2)");
3274 map_root_user(uid
, gid
);
3276 int userns
= open("/proc/self/ns/user", O_RDONLY
);
3278 err(EXIT_FAILURE
, "failed to open /proc/self/ns/user for the new user ns");
3280 if (unshare(CLONE_NEWUSER
) < 0) {
3284 err((errno
== EPERM
? EXIT_EPERM
: EXIT_FAILURE
),
3285 "failed in the 2nd unshare(2)");
3288 if (userns
!= fdescs
[0].fd
) {
3289 if (dup2(userns
, fdescs
[0].fd
) < 0) {
3293 err(EXIT_FAILURE
, "failed to dup %d -> %d", userns
, fdescs
[0].fd
);
3298 fdescs
[0] = (struct fdesc
){
3300 .close
= close_fdesc
,
3307 static void free_mmap(const struct factory
* factory _U_
, void *data
)
3309 munmap(((struct mmap_data
*)data
)->addr
,
3310 ((struct mmap_data
*)data
)->len
);
3313 static int send_diag_request(int diagsd
, void *req
, size_t req_size
)
3315 struct sockaddr_nl nladdr
= {
3316 .nl_family
= AF_NETLINK
,
3319 struct nlmsghdr nlh
= {
3320 .nlmsg_len
= sizeof(nlh
) + req_size
,
3321 .nlmsg_type
= SOCK_DIAG_BY_FAMILY
,
3322 .nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
,
3325 struct iovec iovecs
[] = {
3326 { &nlh
, sizeof(nlh
) },
3330 const struct msghdr mhd
= {
3331 .msg_namelen
= sizeof(nladdr
),
3332 .msg_name
= &nladdr
,
3333 .msg_iovlen
= ARRAY_SIZE(iovecs
),
3337 if (sendmsg(diagsd
, &mhd
, 0) < 0)
3343 static void *make_sockdiag(const struct factory
*factory
, struct fdesc fdescs
[],
3344 int argc
, char ** argv
)
3346 struct arg family
= decode_arg("family", factory
->params
, argc
, argv
);
3347 const char *sfamily
= ARG_STRING(family
);
3353 struct unix_diag_req udr
;
3355 if (strcmp(sfamily
, "unix") == 0)
3358 errx(EXIT_FAILURE
, "unknown/unsupported family: %s", sfamily
);
3361 diagsd
= socket(AF_NETLINK
, SOCK_DGRAM
, NETLINK_SOCK_DIAG
);
3363 err(errno
== EPROTONOSUPPORT
? EXIT_EPROTONOSUPPORT
: EXIT_FAILURE
,
3364 "failed in sendmsg()");
3366 if (ifamily
== AF_UNIX
) {
3367 udr
= (struct unix_diag_req
) {
3368 .sdiag_family
= AF_UNIX
,
3369 .udiag_states
= -1, /* set the all bits. */
3370 .udiag_show
= UDIAG_SHOW_NAME
| UDIAG_SHOW_PEER
| UNIX_DIAG_SHUTDOWN
,
3373 reqlen
= sizeof(udr
);
3376 e
= send_diag_request(diagsd
, req
, reqlen
);
3380 if (errno
== EACCES
)
3381 err(EXIT_EACCES
, "failed in sendmsg()");
3382 if (errno
== ENOENT
)
3383 err(EXIT_ENOENT
, "failed in sendmsg()");
3384 err(EXIT_FAILURE
, "failed in sendmsg()");
3388 if (diagsd
!= fdescs
[0].fd
) {
3389 if (dup2(diagsd
, fdescs
[0].fd
) < 0) {
3393 err(EXIT_FAILURE
, "failed to dup %d -> %d", diagsd
, fdescs
[0].fd
);
3398 fdescs
[0] = (struct fdesc
){
3400 .close
= close_fdesc
,
3407 #define PARAM_END { .name = NULL, }
3408 static const struct factory factories
[] = {
3410 .name
= "ro-regular-file",
3411 .desc
= "read-only regular file",
3415 .make
= open_ro_regular_file
,
3416 .params
= (struct parameter
[]) {
3419 .type
= PTYPE_STRING
,
3420 .desc
= "file to be opened",
3421 .defv
.string
= "/etc/passwd",
3425 .type
= PTYPE_INTEGER
,
3426 .desc
= "seek bytes after open with SEEK_CUR",
3430 .name
= "read-lease",
3431 .type
= PTYPE_BOOLEAN
,
3432 .desc
= "taking out read lease for the file",
3433 .defv
.boolean
= false,
3439 .name
= "make-regular-file",
3440 .desc
= "regular file for writing",
3444 .make
= make_w_regular_file
,
3445 .free
= free_after_closing_duplicated_fd
,
3446 .params
= (struct parameter
[]) {
3449 .type
= PTYPE_STRING
,
3450 .desc
= "file to be made",
3451 .defv
.string
= "./test_mkfds_make_regular_file",
3455 .type
= PTYPE_BOOLEAN
,
3456 .desc
= "delete the file just after making it",
3457 .defv
.boolean
= false,
3460 .name
= "write-bytes",
3461 .type
= PTYPE_INTEGER
,
3462 .desc
= "write something (> 0)",
3467 .type
= PTYPE_BOOLEAN
,
3468 .desc
= "open the new file readable way",
3469 .defv
.string
= false,
3473 .type
= PTYPE_STRING
,
3474 .desc
= "the way for file locking: [none]|flock-sh|flock-ex|posix-r-|posix--w|posix-rw|ofd-r-|ofd--w|ofd-rw|lease-w",
3475 .defv
.string
= "none",
3479 .type
= PTYPE_INTEGER
,
3480 .desc
= "the number for the fd duplicated from the original fd",
3487 .name
= "pipe-no-fork",
3488 .desc
= "making pair of fds with pipe(2)",
3493 .params
= (struct parameter
[]) {
3496 .type
= PTYPE_STRING
,
3497 .desc
= "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")",
3498 .defv
.string
= "--",
3502 .type
= PTYPE_INTEGER
,
3503 .desc
= "file descriptor for duplicating the pipe input",
3508 .type
= PTYPE_INTEGER
,
3509 .desc
= "file descriptor for duplicating the pipe output",
3516 .name
= "directory",
3517 .desc
= "directory",
3521 .make
= open_directory
,
3522 .params
= (struct parameter
[]) {
3525 .type
= PTYPE_STRING
,
3526 .desc
= "directory to be opened",
3531 .type
= PTYPE_INTEGER
,
3532 .desc
= "read the number of dentries after open with readdir(3)",
3539 .name
= "rw-character-device",
3540 .desc
= "character device with O_RDWR flag",
3544 .make
= open_rw_chrdev
,
3545 .params
= (struct parameter
[]) {
3548 .type
= PTYPE_STRING
,
3549 .desc
= "character device node to be opened",
3550 .defv
.string
= "/dev/zero",
3556 .name
= "socketpair",
3557 .desc
= "AF_UNIX socket pair created with socketpair(2)",
3561 .make
= make_socketpair
,
3562 .params
= (struct parameter
[]) {
3565 .type
= PTYPE_STRING
,
3566 .desc
= "STREAM, DGRAM, or SEQPACKET",
3567 .defv
.string
= "STREAM",
3570 .name
= "halfclose",
3571 .type
= PTYPE_BOOLEAN
,
3572 .desc
= "Shutdown the read end of the 1st socket, the write end of the 2nd socket",
3573 .defv
.boolean
= false,
3580 .desc
= "symbolic link itself opened with O_PATH",
3584 .make
= open_with_opath
,
3585 .params
= (struct parameter
[]) {
3588 .type
= PTYPE_STRING
,
3589 .desc
= "path to a symbolic link",
3590 .defv
.string
= "/dev/stdin",
3596 .name
= "ro-block-device",
3597 .desc
= "block device with O_RDONLY flag",
3601 .make
= open_ro_blkdev
,
3602 .params
= (struct parameter
[]) {
3605 .type
= PTYPE_STRING
,
3606 .desc
= "block device node to be opened",
3607 .defv
.string
= "/dev/nullb0",
3613 .name
= "mapped-packet-socket",
3614 .desc
= "mmap'ed AF_PACKET socket",
3618 .make
= make_mmapped_packet_socket
,
3619 .params
= (struct parameter
[]) {
3622 .type
= PTYPE_STRING
,
3623 .desc
= "DGRAM or RAW",
3624 .defv
.string
= "RAW",
3627 .name
= "interface",
3628 .type
= PTYPE_STRING
,
3629 .desc
= "a name of network interface like eth0 or lo",
3630 .defv
.string
= "lo",
3637 .desc
= "pidfd returned from pidfd_open(2)",
3642 .params
= (struct parameter
[]) {
3644 .name
= "target-pid",
3645 .type
= PTYPE_INTEGER
,
3646 .desc
= "the pid of the target process",
3654 .desc
= "inotify fd returned from inotify_init(2)",
3658 .make
= make_inotify_fd
,
3659 .params
= (struct parameter
[]) {
3662 .type
= PTYPE_STRING
,
3663 .desc
= "the directory that the inotify monitors",
3668 .type
= PTYPE_STRING
,
3669 .desc
= "the file that the inotify monitors",
3670 .defv
.string
= "/etc/fstab",
3676 .name
= "unix-stream",
3677 .desc
= "AF_UNIX+SOCK_STREAM sockets",
3681 .make
= make_unix_stream
,
3682 .params
= (struct parameter
[]) {
3685 .type
= PTYPE_STRING
,
3686 .desc
= "path for listening-socket bound to",
3687 .defv
.string
= "/tmp/test_mkfds-unix-stream",
3691 .type
= PTYPE_INTEGER
,
3692 .desc
= "backlog passed to listen(2)",
3697 .type
= PTYPE_BOOLEAN
,
3698 .desc
= "use PATH as an abstract socket address",
3699 .defv
.boolean
= false,
3702 .name
= "server-shutdown",
3703 .type
= PTYPE_INTEGER
,
3704 .desc
= "shutdown the accepted socket; 1: R, 2: W, 3: RW",
3708 .name
= "client-shutdown",
3709 .type
= PTYPE_INTEGER
,
3710 .desc
= "shutdown the client socket; 1: R, 2: W, 3: RW",
3715 .type
= PTYPE_STRING
,
3716 .desc
= "stream or seqpacket",
3717 .defv
.string
= "stream",
3723 .name
= "unix-dgram",
3724 .desc
= "AF_UNIX+SOCK_DGRAM sockets",
3728 .make
= make_unix_dgram
,
3729 .params
= (struct parameter
[]) {
3732 .type
= PTYPE_STRING
,
3733 .desc
= "path for unix non-stream bound to",
3734 .defv
.string
= "/tmp/test_mkfds-unix-dgram",
3738 .type
= PTYPE_BOOLEAN
,
3739 .desc
= "use PATH as an abstract socket address",
3740 .defv
.boolean
= false,
3746 .name
= "unix-in-netns",
3747 .desc
= "make a unix socket in a new network namespace",
3751 .make
= make_unix_in_new_netns
,
3752 .params
= (struct parameter
[]) {
3755 .type
= PTYPE_STRING
,
3756 .desc
= "dgram, stream, or seqpacket",
3757 .defv
.string
= "stream",
3761 .type
= PTYPE_STRING
,
3762 .desc
= "path for unix non-stream bound to",
3763 .defv
.string
= "/tmp/test_mkfds-unix-in-netns",
3767 .type
= PTYPE_BOOLEAN
,
3768 .desc
= "use PATH as an abstract socket address",
3769 .defv
.boolean
= false,
3776 .desc
= "AF_INET+SOCK_STREAM sockets",
3781 .params
= (struct parameter
[]) {
3783 .name
= "server-port",
3784 .type
= PTYPE_INTEGER
,
3785 .desc
= "TCP port the server may listen",
3786 .defv
.integer
= 12345,
3789 .name
= "client-port",
3790 .type
= PTYPE_INTEGER
,
3791 .desc
= "TCP port the client may bind",
3792 .defv
.integer
= 23456,
3799 .desc
= "AF_INET+SOCK_DGRAM sockets",
3804 .params
= (struct parameter
[]) {
3807 .type
= PTYPE_BOOLEAN
,
3808 .desc
= "Use UDPLITE instead of UDP",
3809 .defv
.boolean
= false,
3812 .name
= "server-port",
3813 .type
= PTYPE_INTEGER
,
3814 .desc
= "UDP port the server may listen",
3815 .defv
.integer
= 12345,
3818 .name
= "client-port",
3819 .type
= PTYPE_INTEGER
,
3820 .desc
= "UDP port the client may bind",
3821 .defv
.integer
= 23456,
3824 .name
= "server-do-bind",
3825 .type
= PTYPE_BOOLEAN
,
3826 .desc
= "call bind with the server socket",
3827 .defv
.boolean
= true,
3830 .name
= "client-do-bind",
3831 .type
= PTYPE_BOOLEAN
,
3832 .desc
= "call bind with the client socket",
3833 .defv
.boolean
= true,
3836 .name
= "client-do-connect",
3837 .type
= PTYPE_BOOLEAN
,
3838 .desc
= "call connect with the client socket",
3839 .defv
.boolean
= true,
3846 .desc
= "AF_INET+SOCK_RAW sockets",
3851 .params
= (struct parameter
[]) {
3854 .type
= PTYPE_INTEGER
,
3855 .desc
= "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
3856 .defv
.integer
= IPPROTO_IPIP
,
3864 .desc
= "AF_INET+SOCK_DGRAM+IPPROTO_ICMP sockets",
3869 .params
= (struct parameter
[]) {
3872 .type
= PTYPE_BOOLEAN
,
3873 .desc
= "call connect(2) with the socket",
3874 .defv
.boolean
= true,
3878 .type
= PTYPE_BOOLEAN
,
3879 .desc
= "call bind(2) with the socket",
3880 .defv
.boolean
= true,
3884 .type
= PTYPE_INTEGER
,
3885 .desc
= "ICMP echo request id",
3893 .desc
= "AF_INET6+SOCK_STREAM sockets",
3898 .params
= (struct parameter
[]) {
3900 .name
= "server-port",
3901 .type
= PTYPE_INTEGER
,
3902 .desc
= "TCP port the server may listen",
3903 .defv
.integer
= 12345,
3906 .name
= "client-port",
3907 .type
= PTYPE_INTEGER
,
3908 .desc
= "TCP port the client may bind",
3909 .defv
.integer
= 23456,
3916 .desc
= "AF_INET6+SOCK_DGRAM sockets",
3921 .params
= (struct parameter
[]) {
3924 .type
= PTYPE_BOOLEAN
,
3925 .desc
= "Use UDPLITE instead of UDP",
3926 .defv
.boolean
= false,
3929 .name
= "server-port",
3930 .type
= PTYPE_INTEGER
,
3931 .desc
= "UDP port the server may listen",
3932 .defv
.integer
= 12345,
3935 .name
= "client-port",
3936 .type
= PTYPE_INTEGER
,
3937 .desc
= "UDP port the client may bind",
3938 .defv
.integer
= 23456,
3941 .name
= "server-do-bind",
3942 .type
= PTYPE_BOOLEAN
,
3943 .desc
= "call bind with the server socket",
3944 .defv
.boolean
= true,
3947 .name
= "client-do-bind",
3948 .type
= PTYPE_BOOLEAN
,
3949 .desc
= "call bind with the client socket",
3950 .defv
.boolean
= true,
3953 .name
= "client-do-connect",
3954 .type
= PTYPE_BOOLEAN
,
3955 .desc
= "call connect with the client socket",
3956 .defv
.boolean
= true,
3963 .desc
= "AF_INET6+SOCK_RAW sockets",
3968 .params
= (struct parameter
[]) {
3971 .type
= PTYPE_INTEGER
,
3972 .desc
= "protocol passed to socket(AF_INET6, SOCK_RAW, protocol)",
3973 .defv
.integer
= IPPROTO_IPIP
,
3981 .desc
= "AF_INET6+SOCK_DGRAM+IPPROTO_ICMPV6 sockets",
3986 .params
= (struct parameter
[]) {
3989 .type
= PTYPE_BOOLEAN
,
3990 .desc
= "call connect(2) with the socket",
3991 .defv
.boolean
= true,
3995 .type
= PTYPE_BOOLEAN
,
3996 .desc
= "call bind(2) with the socket",
3997 .defv
.boolean
= true,
4001 .type
= PTYPE_INTEGER
,
4002 .desc
= "ICMP echo request id",
4011 .desc
= "open a file specifying a netns",
4016 .params
= (struct parameter
[]) {
4023 .desc
= "AF_NETLINK sockets",
4027 .make
= make_netlink
,
4028 .params
= (struct parameter
[]) {
4031 .type
= PTYPE_INTEGER
,
4032 .desc
= "protocol passed to socket(AF_NETLINK, SOCK_RAW, protocol)",
4033 .defv
.integer
= NETLINK_USERSOCK
,
4037 .type
= PTYPE_UINTEGER
,
4038 .desc
= "multicast groups of netlink communication (requires CAP_NET_ADMIN)",
4046 .desc
= "make an eventfd connecting two processes",
4051 .make
= make_eventfd
,
4052 .report
= report_eventfd
,
4053 .free
= free_eventfd
,
4054 .params
= (struct parameter
[]) {
4060 .desc
= "make a mqueue connecting two processes",
4065 .make
= make_mqueue
,
4066 .report
= report_mqueue
,
4067 .free
= free_mqueue
,
4068 .params
= (struct parameter
[]) {
4071 .type
= PTYPE_STRING
,
4072 .desc
= "path for mqueue",
4073 .defv
.string
= "/test_mkfds-mqueue",
4080 .desc
= "shared memory mapped with SYSVIPC shmem syscalls",
4084 .make
= make_sysvshm
,
4085 .free
= free_sysvshm
,
4086 .params
= (struct parameter
[]) {
4091 .name
= "eventpoll",
4092 .desc
= "make eventpoll (epoll) file",
4096 .make
= make_eventpoll
,
4097 .params
= (struct parameter
[]) {
4103 .desc
= "make timerfd",
4107 .make
= make_timerfd
,
4108 .params
= (struct parameter
[]) {
4111 .type
= PTYPE_STRING
,
4112 .desc
= "ID: realtime, monotonic, boottime, realtime-alarm, or boottime-alarm",
4113 .defv
.string
= "realtime",
4117 .type
= PTYPE_BOOLEAN
,
4118 .desc
= "use TFD_TIMER_ABSTIME flag",
4119 .defv
.boolean
= false,
4122 .name
= "remaining",
4123 .type
= PTYPE_UINTEGER
,
4124 .desc
= "remaining seconds for expiration",
4125 .defv
.uinteger
= 99,
4129 .type
= PTYPE_UINTEGER
,
4130 .desc
= "inteval in seconds",
4131 .defv
.uinteger
= 10,
4134 .name
= "interval-nanofrac",
4135 .type
= PTYPE_UINTEGER
,
4136 .desc
= "nsec part of inteval",
4145 .desc
= "make signalfd",
4149 .make
= make_signalfd
,
4150 .params
= (struct parameter
[]) {
4156 .desc
= "open /dev/net/tun",
4161 .make
= make_cdev_tun
,
4162 .report
= report_cdev_tun
,
4163 .free
= free_cdev_tun
,
4164 .params
= (struct parameter
[]) {
4170 .desc
= "make bpf-prog",
4174 .make
= make_bpf_prog
,
4175 .params
= (struct parameter
[]) {
4177 .name
= "prog-type-id",
4178 .type
= PTYPE_INTEGER
,
4179 .desc
= "program type by id",
4184 .type
= PTYPE_STRING
,
4185 .desc
= "name assigned to bpf prog object",
4186 .defv
.string
= "mkfds_bpf_prog",
4192 .name
= "multiplexing",
4193 .desc
= "make pipes monitored by multiplexers",
4197 .make
= make_some_pipes
,
4198 .params
= (struct parameter
[]) {
4204 .desc
= "make bpf-map",
4208 .make
= make_bpf_map
,
4209 .params
= (struct parameter
[]) {
4211 .name
= "map-type-id",
4212 .type
= PTYPE_INTEGER
,
4213 .desc
= "map type by id",
4218 .type
= PTYPE_STRING
,
4219 .desc
= "name assigned to the bpf map object",
4220 .defv
.string
= "mkfds_bpf_map",
4227 .desc
= "make a pair of ptmx and pts",
4233 .report
= report_pty
,
4235 .params
= (struct parameter
[]) {
4241 .desc
= "do mmap the given file",
4247 .params
= (struct parameter
[]) {
4250 .type
= PTYPE_STRING
,
4251 .desc
= "file to be opened",
4252 .defv
.string
= "/etc/passwd",
4259 .desc
= "open a user namespae",
4263 .make
= make_userns
,
4264 .params
= (struct parameter
[]) {
4270 .desc
= "make a sockdiag netlink socket",
4274 .make
= make_sockdiag
,
4275 .params
= (struct parameter
[]) {
4278 .type
= PTYPE_STRING
,
4279 /* TODO: inet, inet6 */
4280 .desc
= "name of a protocol family ([unix])",
4281 .defv
.string
= "unix",
4288 static int count_parameters(const struct factory
*factory
)
4291 const struct parameter
*p
= factory
->params
;
4296 return p
- factory
->params
;
4299 static void print_factory(const struct factory
*factory
)
4301 printf("%-20s %4s %5d %7d %6d %s\n",
4303 factory
->priv
? "yes": "no",
4306 count_parameters(factory
),
4310 static void list_factories(void)
4312 printf("%-20s PRIV COUNT NRETURN NPARAM DESCRIPTION\n", "FACTORY");
4313 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4314 print_factory(factories
+ i
);
4317 static const struct factory
*find_factory(const char *name
)
4319 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4320 if (strcmp(factories
[i
].name
, name
) == 0)
4321 return factories
+ i
;
4325 static void list_parameters(const char *factory_name
)
4327 const struct factory
*factory
= find_factory(factory_name
);
4328 const char *fmt
= "%-15s %-8s %15s %s\n";
4331 errx(EXIT_FAILURE
, "no such factory: %s", factory_name
);
4333 if (!factory
->params
)
4336 printf(fmt
, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION");
4337 for (const struct parameter
*p
= factory
->params
; p
->name
!= NULL
; p
++) {
4338 char *defv
= ptype_classes
[p
->type
].sprint(&p
->defv
);
4339 printf(fmt
, p
->name
, ptype_classes
[p
->type
].name
, defv
, p
->desc
);
4344 static void rename_self(const char *comm
)
4346 if (prctl(PR_SET_NAME
, (unsigned long)comm
, 0, 0, 0) < 0)
4347 err(EXIT_FAILURE
, "failed to rename self via prctl: %s", comm
);
4350 static void do_nothing(int signum _U_
)
4354 #ifdef __NR_pidfd_open
4357 pidfd_open(pid_t pid
, unsigned int flags
)
4359 return syscall(__NR_pidfd_open
, pid
, flags
);
4363 pidfd_open(pid_t pid _U_
, unsigned int flags _U_
)
4373 struct multiplexer
{
4375 void (*fn
)(bool, struct fdesc
*fdescs
, size_t n_fdescs
);
4378 #if defined(__NR_select) || defined(__NR_poll)
4379 static void sighandler_nop(int si _U_
)
4385 #define DEFUN_WAIT_EVENT_SELECT(NAME,SYSCALL,XDECLS,SETUP_SIG_HANDLER,SYSCALL_INVOCATION) \
4386 static void wait_event_##NAME(bool add_stdin, struct fdesc *fdescs, size_t n_fdescs) \
4394 FD_ZERO(&readfds); \
4395 FD_ZERO(&writefds); \
4396 FD_ZERO(&exceptfds); \
4397 /* Monitor the standard input only when the process \
4398 * is in foreground. */ \
4401 FD_SET(0, &readfds); \
4404 for (size_t i = 0; i < n_fdescs; i++) { \
4405 if (fdescs[i].mx_modes & MX_READ) { \
4406 n = max(n, fdescs[i].fd + 1); \
4407 FD_SET(fdescs[i].fd, &readfds); \
4409 if (fdescs[i].mx_modes & MX_WRITE) { \
4410 n = max(n, fdescs[i].fd + 1); \
4411 FD_SET(fdescs[i].fd, &writefds); \
4413 if (fdescs[i].mx_modes & MX_EXCEPT) { \
4414 n = max(n, fdescs[i].fd + 1); \
4415 FD_SET(fdescs[i].fd, &exceptfds); \
4421 if (SYSCALL_INVOCATION < 0 \
4422 && errno != EINTR) \
4423 err(EXIT_FAILURE, "failed in " SYSCALL); \
4426 DEFUN_WAIT_EVENT_SELECT(default,
4429 sigemptyset(&sigset
);,
4430 pselect(n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4432 #ifdef __NR_pselect6
4433 DEFUN_WAIT_EVENT_SELECT(pselect6
,
4436 sigemptyset(&sigset
);,
4437 syscall(__NR_pselect6
, n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4441 DEFUN_WAIT_EVENT_SELECT(select
,
4444 signal(SIGCONT
,sighandler_nop
);,
4445 syscall(__NR_select
, n
, &readfds
, &writefds
, &exceptfds
, NULL
))
4449 static DEFUN_WAIT_EVENT_POLL(poll
,
4452 signal(SIGCONT
,sighandler_nop
);,
4453 syscall(__NR_poll
, pfds
, n
, -1))
4456 #define DEFAULT_MULTIPLEXER 0
4457 static struct multiplexer multiplexers
[] = {
4460 .fn
= wait_event_default
,
4462 #ifdef __NR_pselect6
4465 .fn
= wait_event_pselect6
,
4471 .fn
= wait_event_select
,
4477 .fn
= wait_event_poll
,
4483 .fn
= wait_event_ppoll
,
4488 static struct multiplexer
*lookup_multiplexer(const char *name
)
4490 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4491 if (strcmp(name
, multiplexers
[i
].name
) == 0)
4492 return multiplexers
+ i
;
4496 static void list_multiplexers(void)
4499 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4500 puts(multiplexers
[i
].name
);
4503 static bool is_available(const char *factory
)
4505 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4506 if (strcmp(factories
[i
].name
, factory
) == 0)
4512 int main(int argc
, char **argv
)
4515 const struct factory
*factory
;
4516 struct fdesc fdescs
[MAX_N
];
4520 bool monitor_stdin
= true;
4522 struct multiplexer
*wait_event
= NULL
;
4524 static const struct option longopts
[] = {
4525 { "is-available",required_argument
,NULL
, 'a' },
4526 { "list", no_argument
, NULL
, 'l' },
4527 { "parameters", required_argument
, NULL
, 'I' },
4528 { "comm", required_argument
, NULL
, 'r' },
4529 { "quiet", no_argument
, NULL
, 'q' },
4530 { "dont-monitor-stdin", no_argument
, NULL
, 'X' },
4531 { "dont-puase", no_argument
, NULL
, 'c' },
4532 { "wait-with", required_argument
, NULL
, 'w' },
4533 { "multiplexers",no_argument
,NULL
, 'W' },
4534 { "help", no_argument
, NULL
, 'h' },
4535 { NULL
, 0, NULL
, 0 },
4538 while ((c
= getopt_long(argc
, argv
, "a:lhqcI:r:w:WX", longopts
, NULL
)) != -1) {
4541 usage(stdout
, EXIT_SUCCESS
);
4543 exit(is_available(optarg
)? 0: 1);
4548 list_parameters(optarg
);
4557 wait_event
= lookup_multiplexer(optarg
);
4558 if (wait_event
== NULL
)
4559 errx(EXIT_FAILURE
, "unknown multiplexer: %s", optarg
);
4562 list_multiplexers();
4565 rename_self(optarg
);
4568 monitor_stdin
= false;
4571 usage(stderr
, EXIT_FAILURE
);
4576 errx(EXIT_FAILURE
, "no file descriptor specification given");
4578 if (cont
&& wait_event
)
4579 errx(EXIT_FAILURE
, "don't specify both -c/--dont-puase and -w/--wait-with options");
4580 if (wait_event
== NULL
)
4581 wait_event
= multiplexers
+ DEFAULT_MULTIPLEXER
;
4583 factory
= find_factory(argv
[optind
]);
4585 errx(EXIT_FAILURE
, "no such factory: %s", argv
[optind
]);
4586 assert(factory
->N
+ factory
->EX_N
< MAX_N
);
4589 if ((optind
+ factory
->N
) > argc
)
4590 errx(EXIT_FAILURE
, "not enough file descriptors given for %s",
4593 if (factory
->priv
&& getuid() != 0)
4594 errx(EXIT_FAILURE
, "%s factory requires root privilege", factory
->name
);
4596 for (int i
= 0; i
< MAX_N
; i
++) {
4598 fdescs
[i
].mx_modes
= 0;
4599 fdescs
[i
].close
= NULL
;
4602 for (int i
= 0; i
< factory
->N
; i
++) {
4603 char *str
= argv
[optind
+ i
];
4608 fd
= strtol(str
, &ep
, 10);
4610 err(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4612 errx(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4614 errx(EXIT_FAILURE
, "garbage at the end of number: %s", str
);
4616 errx(EXIT_FAILURE
, "fd number should not be negative: %s", str
);
4618 errx(EXIT_FAILURE
, "fd 0, 1, 2 are reserved: %s", str
);
4621 optind
+= factory
->N
;
4623 data
= factory
->make(factory
, fdescs
, argc
- optind
, argv
+ optind
);
4625 signal(SIGCONT
, do_nothing
);
4628 printf("%d", getpid());
4629 if (factory
->report
) {
4630 for (int i
= 0; i
< factory
->EX_R
; i
++) {
4632 factory
->report(factory
, i
, data
, stdout
);
4640 wait_event
->fn(monitor_stdin
,
4641 fdescs
, factory
->N
+ factory
->EX_N
);
4643 for (int i
= 0; i
< factory
->N
+ factory
->EX_N
; i
++)
4644 if (fdescs
[i
].fd
>= 0 && fdescs
[i
].close
)
4645 fdescs
[i
].close(fdescs
[i
].fd
, fdescs
[i
].data
);
4648 factory
->free(factory
, data
);