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/sockios.h> /* SIOCGSKNS */
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
49 #include <sys/epoll.h>
50 #include <sys/eventfd.h>
51 #include <sys/inotify.h>
52 #include <sys/ioctl.h>
54 #include <sys/prctl.h>
55 #include <sys/select.h>
56 #include <sys/signalfd.h>
57 #include <sys/socket.h>
59 #include <sys/syscall.h>
60 #include <sys/timerfd.h>
61 #include <sys/types.h>
69 #define EXIT_ENOPROTOOPT 19
70 #define EXIT_EPROTONOSUPPORT 20
71 #define EXIT_EACCESS 21
73 #define _U_ __attribute__((__unused__))
75 static int pidfd_open(pid_t pid
, unsigned int flags
);
76 static void do_nothing(int signum _U_
);
78 static void __attribute__((__noreturn__
)) usage(FILE *out
, int status
)
80 fputs("\nUsage:\n", out
);
81 fprintf(out
, " %s [options] FACTORY FD... [PARAM=VAL...]\n", program_invocation_short_name
);
83 fputs("\nOptions:\n", out
);
84 fputs(" -l, --list list available file descriptor factories and exit\n", out
);
85 fputs(" -I, --parameters <factory> list parameters the factory takes\n", out
);
86 fputs(" -r, --comm <name> rename self\n", out
);
87 fputs(" -q, --quiet don't print pid(s)\n", out
);
88 fputs(" -X, --dont-monitor-stdin don't monitor stdin when pausing\n", out
);
89 fputs(" -c, --dont-pause don't pause after making fd(s)\n", out
);
90 fputs(" -w, --wait-with <multiplexer> use MULTIPLEXER for waiting events\n", out
);
91 fputs(" -W, --multiplexers list multiplexers\n", out
);
94 fputs("Examples:\n", out
);
95 fprintf(out
, "Using 3, open /etc/group:\n\n $ %s ro-regular-file 3 file=/etc/group\n\n",
96 program_invocation_short_name
);
97 fprintf(out
, "Using 3 and 4, make a pipe:\n\n $ %s pipe-no-fork 3 4\n\n",
98 program_invocation_short_name
);
106 unsigned long uinteger
;
120 /* Covert to a string representation.
121 * A caller must free the returned value with free(3) after using. */
122 char *(*sprint
)(const union value
*value
);
124 /* Convert from a string. If ARG is NULL, use DEFV instead.
125 * A caller must free the returned value with the free method
127 union value (*read
)(const char *arg
, const union value
*defv
);
129 /* Free the value returned from the read method. */
130 void (*free
)(union value value
);
133 #define ARG_STRING(A) (A.v.string)
134 #define ARG_INTEGER(A) (A.v.integer)
135 #define ARG_UINTEGER(A) (A.v.uinteger)
136 #define ARG_BOOLEAN(A) (A.v.boolean)
139 void (*free
)(union value value
);
144 const enum ptype type
;
146 union value defv
; /* Default value */
149 static char *string_sprint(const union value
*value
)
151 return xstrdup(value
->string
);
154 static union value
string_read(const char *arg
, const union value
*defv
)
156 return (union value
){ .string
= xstrdup(arg
?: defv
->string
) };
159 static void string_free(union value value
)
161 free((void *)value
.string
);
164 static char *integer_sprint(const union value
*value
)
167 xasprintf(&str
, "%ld", value
->integer
);
171 static union value
integer_read(const char *arg
, const union value
*defv
)
180 r
.integer
= strtol(arg
, &ep
, 10);
182 err(EXIT_FAILURE
, "fail to make a number from %s", arg
);
183 else if (*ep
!= '\0')
184 errx(EXIT_FAILURE
, "garbage at the end of number: %s", arg
);
188 static void integer_free(union value value _U_
)
193 static char *uinteger_sprint(const union value
*value
)
196 xasprintf(&str
, "%lu", value
->uinteger
);
200 static union value
uinteger_read(const char *arg
, const union value
*defv
)
209 r
.uinteger
= strtoul(arg
, &ep
, 10);
211 err(EXIT_FAILURE
, "fail to make a number from %s", arg
);
212 else if (*ep
!= '\0')
213 errx(EXIT_FAILURE
, "garbage at the end of number: %s", arg
);
217 static void uinteger_free(union value value _U_
)
222 static char *boolean_sprint(const union value
*value
)
224 return xstrdup(value
->boolean
? "true": "false");
227 static union value
boolean_read(const char *arg
, const union value
*defv
)
234 if (strcasecmp(arg
, "true") == 0
235 || strcmp(arg
, "1") == 0
236 || strcasecmp(arg
, "yes") == 0
237 || strcasecmp(arg
, "y") == 0)
244 static void boolean_free(union value value _U_
)
249 struct ptype_class ptype_classes
[] = {
252 .sprint
= string_sprint
,
258 .sprint
= integer_sprint
,
259 .read
= integer_read
,
260 .free
= integer_free
,
264 .sprint
= uinteger_sprint
,
265 .read
= uinteger_read
,
266 .free
= uinteger_free
,
270 .sprint
= boolean_sprint
,
271 .read
= boolean_read
,
272 .free
= boolean_free
,
276 static struct arg
decode_arg(const char *pname
,
277 const struct parameter
*parameters
,
278 int argc
, char **argv
)
281 size_t len
= strlen(pname
);
282 const struct parameter
*p
= NULL
;
285 while (parameters
->name
) {
286 if (strcmp(pname
, parameters
->name
) == 0) {
293 errx(EXIT_FAILURE
, "no such parameter: %s", pname
);
295 for (int i
= 0; i
< argc
; i
++) {
296 if (strncmp(pname
, argv
[i
], len
) == 0) {
301 } else if (*v
== '\0')
303 "no value given for \"%s\" parameter",
309 arg
.v
= ptype_classes
[p
->type
].read (v
, &p
->defv
);
310 arg
.free
= ptype_classes
[p
->type
].free
;
314 static void free_arg(struct arg
*arg
)
320 const char *name
; /* [-a-zA-Z0-9_]+ */
322 bool priv
; /* the root privilege is needed to make fd(s) */
324 int N
; /* the number of fds this factory makes */
325 int EX_N
; /* fds made optionally */
326 int EX_R
; /* the number of extra words printed to stdout. */
327 void *(*make
)(const struct factory
*, struct fdesc
[], int, char **);
328 void (*free
)(const struct factory
*, void *);
329 void (*report
)(const struct factory
*, int, void *, FILE *);
330 const struct parameter
* params
;
333 static void close_fdesc(int fd
, void *data _U_
)
338 volatile ssize_t unused_result_ok
;
339 static void abort_with_child_death_message(int signum _U_
)
341 const char msg
[] = "the child process exits unexpectedly";
342 unused_result_ok
= write(2, msg
, sizeof(msg
));
346 static void *open_ro_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
347 int argc
, char ** argv
)
349 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
350 struct arg offset
= decode_arg("offset", factory
->params
, argc
, argv
);
351 struct arg lease_r
= decode_arg("read-lease", factory
->params
, argc
, argv
);
353 int fd
= open(ARG_STRING(file
), O_RDONLY
);
355 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(file
));
358 if (ARG_INTEGER(offset
) != 0) {
359 if (lseek(fd
, (off_t
)ARG_INTEGER(offset
), SEEK_CUR
) < 0) {
363 err(EXIT_FAILURE
, "failed to seek 0 -> %ld", ARG_INTEGER(offset
));
368 if (ARG_BOOLEAN(lease_r
)) {
369 if (fcntl(fd
, F_SETLEASE
, F_RDLCK
) < 0) {
373 err(EXIT_FAILURE
, "failed to take out a read lease");
378 if (fd
!= fdescs
[0].fd
) {
379 if (dup2(fd
, fdescs
[0].fd
) < 0) {
383 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
388 fdescs
[0] = (struct fdesc
){
390 .close
= close_fdesc
,
397 static void unlink_and_close_fdesc(int fd
, void *data
)
405 typedef void (*lockFn
)(int fd
, const char *fname
, int dupfd
);
407 static void lock_fn_none(int fd _U_
, const char *fname _U_
, int dupfd _U_
)
412 static void lock_fn_flock_sh(int fd
, const char *fname
, int dupfd
)
414 if (flock(fd
, LOCK_SH
) < 0) {
421 err(EXIT_FAILURE
, "failed to lock");
425 static void lock_fn_flock_ex(int fd
, const char *fname
, int dupfd
)
427 if (flock(fd
, LOCK_EX
) < 0) {
434 err(EXIT_FAILURE
, "failed to lock");
438 static void lock_fn_posix_r_(int fd
, const char *fname
, int dupfd
)
442 .l_whence
= SEEK_SET
,
446 if (fcntl(fd
, F_SETLK
, &r
) < 0) {
453 err(EXIT_FAILURE
, "failed to lock");
457 static void lock_fn_posix__w(int fd
, const char *fname
, int dupfd
)
461 .l_whence
= SEEK_SET
,
465 if (fcntl(fd
, F_SETLK
, &w
) < 0) {
472 err(EXIT_FAILURE
, "failed to lock");
476 static void lock_fn_posix_rw(int fd
, const char *fname
, int dupfd
)
480 .l_whence
= SEEK_SET
,
486 .l_whence
= SEEK_SET
,
490 if (fcntl(fd
, F_SETLK
, &r
) < 0) {
497 err(EXIT_FAILURE
, "failed to lock(read)");
499 if (fcntl(fd
, F_SETLK
, &w
) < 0) {
506 err(EXIT_FAILURE
, "failed to lock(write)");
510 static void lock_fn_ofd_r_(int fd
, const char *fname
, int dupfd
)
514 .l_whence
= SEEK_SET
,
519 if (fcntl(fd
, F_OFD_SETLK
, &r
) < 0) {
526 err(EXIT_FAILURE
, "failed to lock");
530 static void lock_fn_ofd__w(int fd
, const char *fname
, int dupfd
)
534 .l_whence
= SEEK_SET
,
539 if (fcntl(fd
, F_OFD_SETLK
, &w
) < 0) {
546 err(EXIT_FAILURE
, "failed to lock");
550 static void lock_fn_ofd_rw(int fd
, const char *fname
, int dupfd
)
554 .l_whence
= SEEK_SET
,
561 .l_whence
= SEEK_SET
,
566 if (fcntl(fd
, F_OFD_SETLK
, &r
) < 0) {
573 err(EXIT_FAILURE
, "failed to lock(read)");
575 if (fcntl(fd
, F_OFD_SETLK
, &w
) < 0) {
582 err(EXIT_FAILURE
, "failed to lock(write)");
586 static void lock_fn_lease_w(int fd
, const char *fname
, int dupfd
)
588 if (fcntl(fd
, F_SETLEASE
, F_WRLCK
) < 0) {
595 err(EXIT_FAILURE
, "failed to take out a write lease");
600 static void *make_w_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
601 int argc
, char ** argv
)
605 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
606 char *fname
= xstrdup(ARG_STRING(file
));
608 struct arg
delete = decode_arg("delete", factory
->params
, argc
, argv
);
609 bool bDelete
= ARG_BOOLEAN(delete);
611 struct arg write_bytes
= decode_arg("write-bytes", factory
->params
, argc
, argv
);
612 int iWrite_bytes
= ARG_INTEGER(write_bytes
);
614 struct arg readable
= decode_arg("readable", factory
->params
, argc
, argv
);
615 bool bReadable
= ARG_BOOLEAN(readable
);
617 struct arg lock
= decode_arg("lock", factory
->params
, argc
, argv
);
618 const char *sLock
= ARG_STRING(lock
);
621 struct arg dupfd
= decode_arg("dupfd", factory
->params
, argc
, argv
);
622 int iDupfd
= ARG_INTEGER(dupfd
);
626 if (iWrite_bytes
< 0)
627 errx(EXIT_FAILURE
, "write-bytes must be a positive number or zero.");
629 if (strcmp(sLock
, "none") == 0)
630 lock_fn
= lock_fn_none
;
631 else if (strcmp(sLock
, "flock-sh") == 0)
632 lock_fn
= lock_fn_flock_sh
;
633 else if (strcmp(sLock
, "flock-ex") == 0)
634 lock_fn
= lock_fn_flock_ex
;
635 else if (strcmp(sLock
, "posix-r-") == 0) {
637 if (iWrite_bytes
< 1)
639 lock_fn
= lock_fn_posix_r_
;
640 } else if (strcmp(sLock
, "posix--w") == 0) {
641 if (iWrite_bytes
< 1)
643 lock_fn
= lock_fn_posix__w
;
644 } else if (strcmp(sLock
, "posix-rw") == 0) {
646 if (iWrite_bytes
< 3)
648 lock_fn
= lock_fn_posix_rw
;
649 } else if (strcmp(sLock
, "ofd-r-") == 0) {
651 if (iWrite_bytes
< 1)
653 lock_fn
= lock_fn_ofd_r_
;
654 } else if (strcmp(sLock
, "ofd--w") == 0) {
655 if (iWrite_bytes
< 1)
657 lock_fn
= lock_fn_ofd__w
;
658 } else if (strcmp(sLock
, "ofd-rw") == 0) {
660 if (iWrite_bytes
< 3)
662 lock_fn
= lock_fn_ofd_rw
;
663 } else if (strcmp(sLock
, "lease-w") == 0)
664 lock_fn
= lock_fn_lease_w
;
666 errx(EXIT_FAILURE
, "unexpected value for lock parameter: %s", sLock
);
671 free_arg(&write_bytes
);
675 fd
= open(fname
, O_CREAT
|O_EXCL
|(bReadable
? O_RDWR
: O_WRONLY
), S_IWUSR
);
677 err(EXIT_FAILURE
, "failed to make: %s", fname
);
679 if (fd
!= fdescs
[0].fd
) {
680 if (dup2(fd
, fdescs
[0].fd
) < 0) {
686 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
693 if (unlink(fname
) < 0) {
697 err(EXIT_FAILURE
, "failed to unlink %s", fname
);
703 for (int i
= 0; i
< iWrite_bytes
; i
++) {
704 if (write(fd
, "z", 1) != 1) {
710 err(EXIT_FAILURE
, "failed to write");
715 if (dup2(fd
, iDupfd
) < 0) {
721 err(EXIT_FAILURE
, "failed in dup2");
723 data
= xmalloc(sizeof (iDupfd
));
724 *((int *)data
) = iDupfd
;
727 lock_fn(fd
, fname
, iDupfd
);
729 fdescs
[0] = (struct fdesc
){
731 .close
= bDelete
? close_fdesc
: unlink_and_close_fdesc
,
738 static void free_after_closing_duplicated_fd(const struct factory
* factory _U_
, void *data
)
747 static void *make_pipe(const struct factory
*factory
, struct fdesc fdescs
[],
748 int argc
, char ** argv
)
751 int nonblock_flags
[2] = {0, 0};
752 struct arg nonblock
= decode_arg("nonblock", factory
->params
, argc
, argv
);
753 if (strlen(ARG_STRING(nonblock
)) != 2) {
754 errx(EXIT_FAILURE
, "string value for %s has unexpected length: %s",
755 "nonblock", ARG_STRING(nonblock
));
758 /* Make extra pipe descriptors for making pipe objects connected
759 * with fds more than 2.
760 * See https://github.com/util-linux/util-linux/pull/1622
761 * about the background of the requirement. */
762 struct arg rdup
= decode_arg("rdup", factory
->params
, argc
, argv
);
763 struct arg wdup
= decode_arg("wdup", factory
->params
, argc
, argv
);
765 xpd
[0] = ARG_INTEGER(rdup
);
766 xpd
[1] = ARG_INTEGER(wdup
);
768 for (int i
= 0; i
< 2; i
++) {
769 if (ARG_STRING(nonblock
)[i
] == '-')
771 if ((i
== 0 && ARG_STRING(nonblock
)[i
] == 'r')
772 || (i
== 1 && ARG_STRING(nonblock
)[i
] == 'w'))
773 nonblock_flags
[i
] = 1;
775 errx(EXIT_FAILURE
, "unexpected value %c for the %s fd of %s",
776 ARG_STRING(nonblock
)[i
],
777 (i
== 0)? "read": "write",
783 err(EXIT_FAILURE
, "failed to make pipe");
785 for (int i
= 0; i
< 2; i
++) {
786 if (nonblock_flags
[i
]) {
787 int flags
= fcntl(pd
[i
], F_GETFL
);
788 if (fcntl(pd
[i
], F_SETFL
, flags
|O_NONBLOCK
) < 0) {
793 errx(EXIT_FAILURE
, "failed to set NONBLOCK flag to the %s fd",
794 (i
== 0)? "read": "write");
799 for (int i
= 0; i
< 2; i
++) {
800 if (pd
[i
] != fdescs
[i
].fd
) {
801 if (dup2(pd
[i
], fdescs
[i
].fd
) < 0) {
806 err(EXIT_FAILURE
, "failed to dup %d -> %d",
807 pd
[i
], fdescs
[i
].fd
);
811 fdescs
[i
] = (struct fdesc
){
813 .close
= close_fdesc
,
818 /* Make extra pipe descriptors. */
819 for (int i
= 0; i
< 2; i
++) {
821 if (dup2(fdescs
[i
].fd
, xpd
[i
]) < 0) {
825 if (i
> 0 && xpd
[0] >= 0)
828 err(EXIT_FAILURE
, "failed to dup %d -> %d",
829 fdescs
[i
].fd
, xpd
[i
]);
831 fdescs
[i
+ 2] = (struct fdesc
){
833 .close
= close_fdesc
,
842 static void close_dir(int fd
, void *data
)
848 close_fdesc(fd
, NULL
);
851 static void *open_directory(const struct factory
*factory
, struct fdesc fdescs
[],
852 int argc
, char ** argv
)
854 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
855 struct arg dentries
= decode_arg("dentries", factory
->params
, argc
, argv
);
858 int fd
= open(ARG_STRING(dir
), O_RDONLY
|O_DIRECTORY
);
860 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(dir
));
863 if (fd
!= fdescs
[0].fd
) {
864 if (dup2(fd
, fdescs
[0].fd
) < 0) {
868 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
873 if (ARG_INTEGER(dentries
) > 0) {
874 dp
= fdopendir(fdescs
[0].fd
);
879 err(EXIT_FAILURE
, "failed to make DIR* from fd: %s", ARG_STRING(dir
));
881 for (int i
= 0; i
< ARG_INTEGER(dentries
); i
++) {
882 struct dirent
*d
= readdir(dp
);
887 err(EXIT_FAILURE
, "failed in readdir(3)");
893 fdescs
[0] = (struct fdesc
){
902 static void *open_rw_chrdev(const struct factory
*factory
, struct fdesc fdescs
[],
903 int argc
, char ** argv
)
905 struct arg chrdev
= decode_arg("chrdev", factory
->params
, argc
, argv
);
906 int fd
= open(ARG_STRING(chrdev
), O_RDWR
);
908 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(chrdev
));
911 if (fd
!= fdescs
[0].fd
) {
912 if (dup2(fd
, fdescs
[0].fd
) < 0) {
916 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
921 fdescs
[0] = (struct fdesc
){
923 .close
= close_fdesc
,
930 static void *make_socketpair(const struct factory
*factory
, struct fdesc fdescs
[],
931 int argc
, char ** argv
)
934 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
936 struct arg halfclose
= decode_arg("halfclose", factory
->params
, argc
, argv
);
939 bhalfclose
= ARG_BOOLEAN(halfclose
);
940 free_arg(&halfclose
);
942 if (strcmp(ARG_STRING(socktype
), "STREAM") == 0)
943 isocktype
= SOCK_STREAM
;
944 else if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
945 isocktype
= SOCK_DGRAM
;
946 else if (strcmp(ARG_STRING(socktype
), "SEQPACKET") == 0)
947 isocktype
= SOCK_SEQPACKET
;
950 "unknown socket type for socketpair(AF_UNIX,...): %s",
951 ARG_STRING(socktype
));
954 if (socketpair(AF_UNIX
, isocktype
, 0, sd
) < 0)
955 err(EXIT_FAILURE
, "failed to make socket pair");
958 if (shutdown(sd
[0], SHUT_RD
) < 0)
960 "failed to shutdown the read end of the 1st socket");
961 if (shutdown(sd
[1], SHUT_WR
) < 0)
963 "failed to shutdown the write end of the 2nd socket");
966 for (int i
= 0; i
< 2; i
++) {
967 if (sd
[i
] != fdescs
[i
].fd
) {
968 if (dup2(sd
[i
], fdescs
[i
].fd
) < 0) {
973 err(EXIT_FAILURE
, "failed to dup %d -> %d",
974 sd
[i
], fdescs
[i
].fd
);
978 fdescs
[i
] = (struct fdesc
){
980 .close
= close_fdesc
,
988 static void *open_with_opath(const struct factory
*factory
, struct fdesc fdescs
[],
989 int argc
, char ** argv
)
991 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
992 int fd
= open(ARG_STRING(path
), O_PATH
|O_NOFOLLOW
);
994 err(EXIT_FAILURE
, "failed to open with O_PATH: %s", ARG_STRING(path
));
997 if (fd
!= fdescs
[0].fd
) {
998 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1002 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1007 fdescs
[0] = (struct fdesc
){
1009 .close
= close_fdesc
,
1016 static void *open_ro_blkdev(const struct factory
*factory
, struct fdesc fdescs
[],
1017 int argc
, char ** argv
)
1019 struct arg blkdev
= decode_arg("blkdev", factory
->params
, argc
, argv
);
1020 int fd
= open(ARG_STRING(blkdev
), O_RDONLY
);
1022 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(blkdev
));
1025 if (fd
!= fdescs
[0].fd
) {
1026 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1030 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1035 fdescs
[0] = (struct fdesc
){
1037 .close
= close_fdesc
,
1044 static int make_packet_socket(int socktype
, const char *interface
)
1047 struct sockaddr_ll addr
;
1049 sd
= socket(AF_PACKET
, socktype
, htons(ETH_P_ALL
));
1051 err(EXIT_FAILURE
, "failed to make a socket with AF_PACKET");
1053 if (interface
== NULL
)
1054 return sd
; /* Just making a socket */
1056 memset(&addr
, 0, sizeof(struct sockaddr_ll
));
1057 addr
.sll_family
= AF_PACKET
;
1058 addr
.sll_ifindex
= if_nametoindex(interface
);
1059 if (addr
.sll_ifindex
== 0) {
1064 "failed to get the interface index for %s", interface
);
1066 if (bind(sd
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_ll
)) < 0) {
1071 "failed to get the interface index for %s", interface
);
1077 struct munmap_data
{
1082 static void close_fdesc_after_munmap(int fd
, void *data
)
1084 struct munmap_data
*munmap_data
= data
;
1085 munmap(munmap_data
->ptr
, munmap_data
->len
);
1090 static void *make_mmapped_packet_socket(const struct factory
*factory
, struct fdesc fdescs
[],
1091 int argc
, char ** argv
)
1094 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
1095 struct arg interface
= decode_arg("interface", factory
->params
, argc
, argv
);
1098 const char *sinterface
;
1099 struct tpacket_req req
;
1100 struct munmap_data
*munmap_data
;
1102 if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
1103 isocktype
= SOCK_DGRAM
;
1104 else if (strcmp(ARG_STRING(socktype
), "RAW") == 0)
1105 isocktype
= SOCK_RAW
;
1108 "unknown socket type for socket(AF_PACKET,...): %s",
1109 ARG_STRING(socktype
));
1110 free_arg(&socktype
);
1112 sinterface
= ARG_STRING(interface
);
1113 sd
= make_packet_socket(isocktype
, sinterface
);
1114 free_arg(&interface
);
1116 /* Specify the spec of ring buffers.
1119 * - linux/Documentation/networking/packet_mmap.rst
1120 * - https://sites.google.com/site/packetmmap/home
1122 req
.tp_block_size
= getpagesize();
1123 req
.tp_frame_size
= getpagesize();
1124 req
.tp_block_nr
= 1;
1125 req
.tp_frame_nr
= 1;
1126 if (setsockopt(sd
, SOL_PACKET
, PACKET_TX_RING
, (char *)&req
, sizeof(req
)) < 0) {
1130 err((errno
== ENOPROTOOPT
? EXIT_ENOPROTOOPT
: EXIT_FAILURE
),
1131 "failed to specify a buffer spec to a packet socket");
1134 munmap_data
= xmalloc(sizeof (*munmap_data
));
1135 munmap_data
->len
= (size_t) req
.tp_block_size
* req
.tp_block_nr
;
1136 munmap_data
->ptr
= mmap(NULL
, munmap_data
->len
, PROT_WRITE
, MAP_SHARED
, sd
, 0);
1137 if (munmap_data
->ptr
== MAP_FAILED
) {
1142 err(EXIT_FAILURE
, "failed to do mmap a packet socket");
1145 if (sd
!= fdescs
[0].fd
) {
1146 if (dup2(sd
, fdescs
[0].fd
) < 0) {
1149 munmap(munmap_data
->ptr
, munmap_data
->len
);
1152 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
1157 fdescs
[0] = (struct fdesc
){
1159 .close
= close_fdesc_after_munmap
,
1160 .data
= munmap_data
,
1166 static void *make_pidfd(const struct factory
*factory
, struct fdesc fdescs
[],
1167 int argc
, char ** argv
)
1169 struct arg target_pid
= decode_arg("target-pid", factory
->params
, argc
, argv
);
1170 pid_t pid
= ARG_INTEGER(target_pid
);
1172 int fd
= pidfd_open(pid
, 0);
1174 err_nosys(EXIT_FAILURE
, "failed in pidfd_open(%d)", (int)pid
);
1175 free_arg(&target_pid
);
1177 if (fd
!= fdescs
[0].fd
) {
1178 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1182 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1187 fdescs
[0] = (struct fdesc
){
1189 .close
= close_fdesc
,
1196 static void *make_inotify_fd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
1197 int argc _U_
, char ** argv _U_
)
1199 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
1200 const char *sdir
= ARG_STRING(dir
);
1201 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
1202 const char *sfile
= ARG_STRING(file
);
1204 int fd
= inotify_init();
1206 err(EXIT_FAILURE
, "failed in inotify_init()");
1208 if (inotify_add_watch(fd
, sdir
, IN_DELETE
) < 0) {
1212 err(EXIT_FAILURE
, "failed in inotify_add_watch(\"%s\")", sdir
);
1216 if (inotify_add_watch(fd
, sfile
, IN_DELETE
) < 0) {
1220 err(EXIT_FAILURE
, "failed in inotify_add_watch(\"%s\")", sfile
);
1224 if (fd
!= fdescs
[0].fd
) {
1225 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1229 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1234 fdescs
[0] = (struct fdesc
){
1236 .close
= close_fdesc
,
1243 static void close_unix_socket(int fd
, void *data
)
1253 static void *make_unix_stream_core(const struct factory
*factory
, struct fdesc fdescs
[],
1254 int argc
, char ** argv
, int type
, const char *typestr
)
1256 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1257 const char *spath
= ARG_STRING(path
);
1259 struct arg backlog
= decode_arg("backlog", factory
->params
, argc
, argv
);
1260 int ibacklog
= ARG_INTEGER(path
);
1262 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1263 bool babstract
= ARG_BOOLEAN(abstract
);
1265 struct arg server_shutdown
= decode_arg("server-shutdown", factory
->params
, argc
, argv
);
1266 int iserver_shutdown
= ARG_INTEGER(server_shutdown
);
1267 struct arg client_shutdown
= decode_arg("client-shutdown", factory
->params
, argc
, argv
);
1268 int iclient_shutdown
= ARG_INTEGER(client_shutdown
);
1270 int ssd
, csd
, asd
; /* server, client, and accepted socket descriptors */
1271 struct sockaddr_un un
;
1272 size_t un_len
= sizeof(un
);
1274 memset(&un
, 0, sizeof(un
));
1275 un
.sun_family
= AF_UNIX
;
1277 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1278 size_t pathlen
= strlen(spath
);
1279 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1280 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1282 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1284 free_arg(&client_shutdown
);
1285 free_arg(&server_shutdown
);
1286 free_arg(&abstract
);
1290 if (iserver_shutdown
< 0 || iserver_shutdown
> 3)
1291 errx(EXIT_FAILURE
, "the server shudown specification in unexpected range");
1292 if (iclient_shutdown
< 0 || iclient_shutdown
> 3)
1293 errx(EXIT_FAILURE
, "the client shudown specification in unexpected range");
1295 ssd
= socket(AF_UNIX
, type
, 0);
1298 "failed to make a socket with AF_UNIX + SOCK_%s (server side)", typestr
);
1299 if (ssd
!= fdescs
[0].fd
) {
1300 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1304 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1310 fdescs
[0] = (struct fdesc
){
1312 .close
= close_unix_socket
,
1317 unlink(un
.sun_path
);
1318 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1322 err(EXIT_FAILURE
, "failed to bind a socket for listening");
1326 fdescs
[0].data
= xstrdup(un
.sun_path
);
1327 if (listen(ssd
, ibacklog
) < 0) {
1329 close_unix_socket(ssd
, fdescs
[0].data
);
1331 err(EXIT_FAILURE
, "failed to listen a socket");
1334 csd
= socket(AF_UNIX
, type
, 0);
1337 "failed to make a socket with AF_UNIX + SOCK_%s (client side)", typestr
);
1338 if (csd
!= fdescs
[1].fd
) {
1339 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1342 close_unix_socket(ssd
, fdescs
[0].data
);
1344 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1350 fdescs
[1] = (struct fdesc
){
1352 .close
= close_fdesc
,
1356 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1358 close_fdesc(csd
, NULL
);
1359 close_unix_socket(ssd
, fdescs
[0].data
);
1361 err(EXIT_FAILURE
, "failed to connect a socket to the listening socket");
1365 unlink(un
.sun_path
);
1367 asd
= accept(ssd
, NULL
, NULL
);
1370 close_fdesc(csd
, NULL
);
1371 close_unix_socket(ssd
, fdescs
[0].data
);
1373 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1375 if (asd
!= fdescs
[2].fd
) {
1376 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1379 close_fdesc(csd
, NULL
);
1380 close_unix_socket(ssd
, fdescs
[0].data
);
1382 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1388 if (iserver_shutdown
& (1 << 0))
1389 shutdown(asd
, SHUT_RD
);
1390 if (iserver_shutdown
& (1 << 1))
1391 shutdown(asd
, SHUT_WR
);
1392 if (iclient_shutdown
& (1 << 0))
1393 shutdown(csd
, SHUT_RD
);
1394 if (iclient_shutdown
& (1 << 1))
1395 shutdown(csd
, SHUT_WR
);
1400 static void *make_unix_stream(const struct factory
*factory
, struct fdesc fdescs
[],
1401 int argc
, char ** argv
)
1403 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1404 const char *stype
= ARG_STRING(type
);
1407 const char *typestr
;
1409 if (strcmp(stype
, "stream") == 0) {
1410 typesym
= SOCK_STREAM
;
1412 } else if (strcmp(stype
, "seqpacket") == 0) {
1413 typesym
= SOCK_SEQPACKET
;
1414 typestr
= "SEQPACKET";
1416 errx(EXIT_FAILURE
, "unknown unix socket type: %s", stype
);
1420 return make_unix_stream_core(factory
, fdescs
, argc
, argv
, typesym
, typestr
);
1423 static void *make_unix_dgram(const struct factory
*factory
, struct fdesc fdescs
[],
1424 int argc
, char ** argv
)
1426 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1427 const char *spath
= ARG_STRING(path
);
1429 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1430 bool babstract
= ARG_BOOLEAN(abstract
);
1432 int ssd
, csd
; /* server and client socket descriptors */
1434 struct sockaddr_un un
;
1435 size_t un_len
= sizeof(un
);
1437 memset(&un
, 0, sizeof(un
));
1438 un
.sun_family
= AF_UNIX
;
1440 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1441 size_t pathlen
= strlen(spath
);
1442 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1443 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1445 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1447 free_arg(&abstract
);
1450 ssd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1453 "failed to make a socket with AF_UNIX + SOCK_DGRAM (server side)");
1454 if (ssd
!= fdescs
[0].fd
) {
1455 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1459 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1465 fdescs
[0] = (struct fdesc
){
1467 .close
= close_unix_socket
,
1472 unlink(un
.sun_path
);
1473 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1477 err(EXIT_FAILURE
, "failed to bind a socket for server");
1481 fdescs
[0].data
= xstrdup(un
.sun_path
);
1482 csd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1485 "failed to make a socket with AF_UNIX + SOCK_DGRAM (client side)");
1486 if (csd
!= fdescs
[1].fd
) {
1487 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1490 close_unix_socket(ssd
, fdescs
[0].data
);
1492 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1498 fdescs
[1] = (struct fdesc
){
1500 .close
= close_fdesc
,
1504 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1506 close_fdesc(csd
, NULL
);
1507 close_unix_socket(ssd
, fdescs
[0].data
);
1509 err(EXIT_FAILURE
, "failed to connect a socket to the server socket");
1513 unlink(un
.sun_path
);
1518 static void *make_unix_in_new_netns(const struct factory
*factory
, struct fdesc fdescs
[],
1519 int argc
, char ** argv
)
1521 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1522 const char *stype
= ARG_STRING(type
);
1524 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1525 const char *spath
= ARG_STRING(path
);
1527 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1528 bool babstract
= ARG_BOOLEAN(abstract
);
1531 const char *typestr
;
1533 struct sockaddr_un un
;
1534 size_t un_len
= sizeof(un
);
1536 int self_netns
, tmp_netns
, sd
;
1538 if (strcmp(stype
, "stream") == 0) {
1539 typesym
= SOCK_STREAM
;
1541 } else if (strcmp(stype
, "seqpacket") == 0) {
1542 typesym
= SOCK_SEQPACKET
;
1543 typestr
= "SEQPACKET";
1544 } else if (strcmp(stype
, "dgram") == 0) {
1545 typesym
= SOCK_DGRAM
;
1548 free_arg(&abstract
);
1551 errx(EXIT_FAILURE
, "unknown unix socket type: %s", stype
);
1554 memset(&un
, 0, sizeof(un
));
1555 un
.sun_family
= AF_UNIX
;
1557 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1558 size_t pathlen
= strlen(spath
);
1559 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1560 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1562 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1564 free_arg(&abstract
);
1568 self_netns
= open("/proc/self/ns/net", O_RDONLY
);
1570 err(EXIT_FAILURE
, "failed to open /proc/self/ns/net");
1571 if (self_netns
!= fdescs
[0].fd
) {
1572 if (dup2(self_netns
, fdescs
[0].fd
) < 0) {
1576 err(EXIT_FAILURE
, "failed to dup %d -> %d", self_netns
, fdescs
[0].fd
);
1579 self_netns
= fdescs
[0].fd
;
1582 fdescs
[0] = (struct fdesc
){
1584 .close
= close_fdesc
,
1588 if (unshare(CLONE_NEWNET
) < 0) {
1590 close_fdesc(self_netns
, NULL
);
1592 err((errno
== EPERM
? EXIT_EPERM
: EXIT_FAILURE
),
1593 "failed in unshare");
1596 tmp_netns
= open("/proc/self/ns/net", O_RDONLY
);
1597 if (tmp_netns
< 0) {
1599 close_fdesc(self_netns
, NULL
);
1601 err(EXIT_FAILURE
, "failed to open /proc/self/ns/net for the new netns");
1603 if (tmp_netns
!= fdescs
[1].fd
) {
1604 if (dup2(tmp_netns
, fdescs
[1].fd
) < 0) {
1606 close_fdesc(self_netns
, NULL
);
1609 err(EXIT_FAILURE
, "failed to dup %d -> %d", tmp_netns
, fdescs
[1].fd
);
1612 tmp_netns
= fdescs
[1].fd
;
1615 fdescs
[1] = (struct fdesc
){
1617 .close
= close_fdesc
,
1621 sd
= socket(AF_UNIX
, typesym
, 0);
1624 close_fdesc(self_netns
, NULL
);
1625 close_fdesc(tmp_netns
, NULL
);
1628 "failed to make a socket with AF_UNIX + SOCK_%s",
1632 if (sd
!= fdescs
[2].fd
) {
1633 if (dup2(sd
, fdescs
[2].fd
) < 0) {
1635 close_fdesc(self_netns
, NULL
);
1636 close_fdesc(tmp_netns
, NULL
);
1639 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[2].fd
);
1645 fdescs
[2] = (struct fdesc
){
1647 .close
= close_unix_socket
,
1652 unlink(un
.sun_path
);
1653 if (bind(sd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1655 close_fdesc(self_netns
, NULL
);
1656 close_fdesc(tmp_netns
, NULL
);
1657 close_unix_socket(sd
, NULL
);
1659 err(EXIT_FAILURE
, "failed to bind a socket");
1663 fdescs
[2].data
= xstrdup(un
.sun_path
);
1665 if (typesym
!= SOCK_DGRAM
) {
1666 if (listen(sd
, 1) < 0) {
1668 close_fdesc(self_netns
, NULL
);
1669 close_fdesc(tmp_netns
, NULL
);
1670 close_unix_socket(sd
, fdescs
[2].data
);
1672 err(EXIT_FAILURE
, "failed to listen a socket");
1676 if (setns(self_netns
, CLONE_NEWNET
) < 0) {
1678 close_fdesc(self_netns
, NULL
);
1679 close_fdesc(tmp_netns
, NULL
);
1680 close_unix_socket(sd
, fdescs
[2].data
);
1682 err(EXIT_FAILURE
, "failed to swich back to the original net namespace");
1688 static void *make_tcp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1689 int argc
, char ** argv
,
1691 void (*init_addr
)(struct sockaddr
*, unsigned short),
1693 struct sockaddr
* sin
, struct sockaddr
* cin
)
1695 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1696 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1697 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1698 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1704 free_arg(&server_port
);
1705 free_arg(&client_port
);
1707 ssd
= socket(family
, SOCK_STREAM
, 0);
1710 "failed to make a tcp socket for listening");
1712 if (setsockopt(ssd
, SOL_SOCKET
,
1713 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1717 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1720 if (ssd
!= fdescs
[0].fd
) {
1721 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1725 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1731 init_addr(sin
, iserver_port
);
1732 if (bind(ssd
, sin
, addr_size
) < 0) {
1736 err(EXIT_FAILURE
, "failed to bind a listening socket");
1739 if (listen(ssd
, 1) < 0) {
1743 err(EXIT_FAILURE
, "failed to listen a socket");
1746 csd
= socket(family
, SOCK_STREAM
, 0);
1752 "failed to make a tcp client socket");
1755 if (setsockopt(csd
, SOL_SOCKET
,
1756 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1761 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1764 if (csd
!= fdescs
[1].fd
) {
1765 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1770 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1776 init_addr(cin
, iclient_port
);
1777 if (bind(csd
, cin
, addr_size
) < 0) {
1782 err(EXIT_FAILURE
, "failed to bind a client socket");
1785 if (connect(csd
, sin
, addr_size
) < 0) {
1790 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1793 asd
= accept(ssd
, NULL
, NULL
);
1799 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1801 if (asd
!= fdescs
[2].fd
) {
1802 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1807 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1813 fdescs
[0] = (struct fdesc
) {
1815 .close
= close_fdesc
,
1818 fdescs
[1] = (struct fdesc
) {
1820 .close
= close_fdesc
,
1823 fdescs
[2] = (struct fdesc
) {
1825 .close
= close_fdesc
,
1832 static void tcp_init_addr(struct sockaddr
*addr
, unsigned short port
)
1834 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
1835 memset(in
, 0, sizeof(*in
));
1836 in
->sin_family
= AF_INET
;
1837 in
->sin_port
= htons(port
);
1838 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1841 static void *make_tcp(const struct factory
*factory
, struct fdesc fdescs
[],
1842 int argc
, char ** argv
)
1844 struct sockaddr_in sin
, cin
;
1845 return make_tcp_common(factory
, fdescs
, argc
, argv
,
1847 tcp_init_addr
, sizeof(sin
),
1848 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1851 static void *make_udp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1852 int argc
, char ** argv
,
1854 void (*init_addr
)(struct sockaddr
*, unsigned short),
1856 struct sockaddr
* sin
, struct sockaddr
* cin
)
1858 struct arg lite
= decode_arg("lite", factory
->params
, argc
, argv
);
1859 bool blite
= ARG_BOOLEAN(lite
);
1861 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1862 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1863 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1864 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1866 struct arg server_do_bind
= decode_arg("server-do-bind", factory
->params
, argc
, argv
);
1867 bool bserver_do_bind
= ARG_BOOLEAN(server_do_bind
);
1868 struct arg client_do_bind
= decode_arg("client-do-bind", factory
->params
, argc
, argv
);
1869 bool bclient_do_bind
= ARG_BOOLEAN(client_do_bind
);
1870 struct arg client_do_connect
= decode_arg("client-do-connect", factory
->params
, argc
, argv
);
1871 bool bclient_do_connect
= ARG_BOOLEAN(client_do_connect
);
1877 free_arg(&client_do_connect
);
1878 free_arg(&client_do_bind
);
1879 free_arg(&server_do_bind
);
1880 free_arg(&server_port
);
1881 free_arg(&client_port
);
1884 ssd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1887 "failed to make a udp socket for server");
1889 if (setsockopt(ssd
, SOL_SOCKET
,
1890 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1894 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1897 if (ssd
!= fdescs
[0].fd
) {
1898 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1902 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1908 init_addr(sin
, iserver_port
);
1909 if (bserver_do_bind
) {
1910 if (bind(ssd
, sin
, addr_size
) < 0) {
1914 err(EXIT_FAILURE
, "failed to bind a server socket");
1918 csd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1924 "failed to make a udp client socket");
1927 if (setsockopt(csd
, SOL_SOCKET
,
1928 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1933 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1936 if (csd
!= fdescs
[1].fd
) {
1937 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1942 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1948 if (bclient_do_bind
) {
1949 init_addr(cin
, iclient_port
);
1950 if (bind(csd
, cin
, addr_size
) < 0) {
1955 err(EXIT_FAILURE
, "failed to bind a client socket");
1959 if (bclient_do_connect
) {
1960 if (connect(csd
, sin
, addr_size
) < 0) {
1965 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1969 fdescs
[0] = (struct fdesc
) {
1971 .close
= close_fdesc
,
1974 fdescs
[1] = (struct fdesc
) {
1976 .close
= close_fdesc
,
1983 static void *make_udp(const struct factory
*factory
, struct fdesc fdescs
[],
1984 int argc
, char ** argv
)
1986 struct sockaddr_in sin
, cin
;
1987 return make_udp_common(factory
, fdescs
, argc
, argv
,
1989 tcp_init_addr
, sizeof(sin
),
1990 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1993 static void *make_raw_common(const struct factory
*factory
, struct fdesc fdescs
[],
1994 int argc
, char ** argv
,
1996 void (*init_addr
)(struct sockaddr
*, bool),
1998 struct sockaddr
* sin
)
2000 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
2001 int iprotocol
= ARG_INTEGER(protocol
);
2004 free_arg(&protocol
);
2006 ssd
= socket(family
, SOCK_RAW
, iprotocol
);
2009 "failed to make a udp socket for server");
2011 if (ssd
!= fdescs
[0].fd
) {
2012 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
2016 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
2022 init_addr(sin
, false);
2023 if (bind(ssd
, sin
, addr_size
) < 0) {
2027 err(EXIT_FAILURE
, "failed in bind(2)");
2030 init_addr(sin
, true);
2031 if (connect(ssd
, sin
, addr_size
) < 0) {
2035 err(EXIT_FAILURE
, "failed in connect(2)");
2038 fdescs
[0] = (struct fdesc
) {
2040 .close
= close_fdesc
,
2047 static void raw_init_addr(struct sockaddr
* addr
, bool remote_addr
)
2049 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
2050 memset(in
, 0, sizeof(*in
));
2051 in
->sin_family
= AF_INET
;
2052 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
+ (remote_addr
? 1: 0));
2055 static void *make_raw(const struct factory
*factory
, struct fdesc fdescs
[],
2056 int argc
, char ** argv
)
2058 struct sockaddr_in sin
;
2059 return make_raw_common(factory
, fdescs
, argc
, argv
,
2061 raw_init_addr
, sizeof(sin
),
2062 (struct sockaddr
*)&sin
);
2065 static void *make_ping_common(const struct factory
*factory
, struct fdesc fdescs
[],
2066 int argc
, char ** argv
,
2067 int family
, int protocol
,
2068 void (*init_addr
)(struct sockaddr
*, unsigned short),
2070 struct sockaddr
*sin
)
2072 struct arg connect_
= decode_arg("connect", factory
->params
, argc
, argv
);
2073 bool bconnect
= ARG_BOOLEAN(connect_
);
2075 struct arg bind_
= decode_arg("bind", factory
->params
, argc
, argv
);
2076 bool bbind
= ARG_BOOLEAN(bind_
);
2078 struct arg id
= decode_arg("id", factory
->params
, argc
, argv
);
2079 unsigned short iid
= (unsigned short)ARG_INTEGER(id
);
2085 free_arg(&connect_
);
2087 sd
= socket(family
, SOCK_DGRAM
, protocol
);
2089 err((errno
== EACCES
? EXIT_EACCESS
: EXIT_FAILURE
),
2090 "failed to make an icmp socket");
2092 if (sd
!= fdescs
[0].fd
) {
2093 if (dup2(sd
, fdescs
[0].fd
) < 0) {
2097 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
2104 init_addr(sin
, iid
);
2105 if (bind(sd
, sin
, addr_size
) < 0) {
2109 err((errno
== EACCES
? EXIT_EACCESS
: EXIT_FAILURE
),
2110 "failed in bind(2)");
2116 if (connect(sd
, sin
, addr_size
) < 0) {
2120 err(EXIT_FAILURE
, "failed in connect(2)");
2124 fdescs
[0] = (struct fdesc
) {
2126 .close
= close_fdesc
,
2133 static void ping_init_addr(struct sockaddr
*addr
, unsigned short id
)
2135 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
2136 memset(in
, 0, sizeof(*in
));
2137 in
->sin_family
= AF_INET
;
2138 in
->sin_port
= htons(id
);
2139 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2142 static void *make_ping(const struct factory
*factory
, struct fdesc fdescs
[],
2143 int argc
, char ** argv
)
2145 struct sockaddr_in in
;
2146 return make_ping_common(factory
, fdescs
, argc
, argv
,
2147 AF_INET
, IPPROTO_ICMP
,
2150 (struct sockaddr
*)&in
);
2153 static void tcp6_init_addr(struct sockaddr
*addr
, unsigned short port
)
2155 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2156 memset(in6
, 0, sizeof(*in6
));
2157 in6
->sin6_family
= AF_INET6
;
2158 in6
->sin6_flowinfo
= 0;
2159 in6
->sin6_port
= htons(port
);
2160 in6
->sin6_addr
= in6addr_loopback
;
2163 static void *make_tcp6(const struct factory
*factory
, struct fdesc fdescs
[],
2164 int argc
, char ** argv
)
2166 struct sockaddr_in6 sin
, cin
;
2167 return make_tcp_common(factory
, fdescs
, argc
, argv
,
2169 tcp6_init_addr
, sizeof(sin
),
2170 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2173 static void *make_udp6(const struct factory
*factory
, struct fdesc fdescs
[],
2174 int argc
, char ** argv
)
2176 struct sockaddr_in6 sin
, cin
;
2177 return make_udp_common(factory
, fdescs
, argc
, argv
,
2179 tcp6_init_addr
, sizeof(sin
),
2180 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2183 static void raw6_init_addr(struct sockaddr
*addr
, bool remote_addr
)
2185 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2186 memset(in6
, 0, sizeof(*in6
));
2187 in6
->sin6_family
= AF_INET6
;
2188 in6
->sin6_flowinfo
= 0;
2191 /* ::ffff:127.0.0.1 */
2192 in6
->sin6_addr
.s6_addr16
[5] = 0xffff;
2193 in6
->sin6_addr
.s6_addr32
[3] = htonl(INADDR_LOOPBACK
);
2195 in6
->sin6_addr
= in6addr_loopback
;
2198 static void *make_raw6(const struct factory
*factory
, struct fdesc fdescs
[],
2199 int argc
, char ** argv
)
2201 struct sockaddr_in6 sin
;
2202 return make_raw_common(factory
, fdescs
, argc
, argv
,
2204 raw6_init_addr
, sizeof(sin
),
2205 (struct sockaddr
*)&sin
);
2208 static void ping6_init_addr(struct sockaddr
*addr
, unsigned short id
)
2210 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2211 memset(in6
, 0, sizeof(*in6
));
2212 in6
->sin6_family
= AF_INET6
;
2213 in6
->sin6_port
= htons(id
);
2214 in6
->sin6_addr
= in6addr_loopback
;
2217 static void *make_ping6(const struct factory
*factory
, struct fdesc fdescs
[],
2218 int argc
, char ** argv
)
2220 struct sockaddr_in6 in6
;
2221 return make_ping_common(factory
, fdescs
, argc
, argv
,
2222 AF_INET6
, IPPROTO_ICMPV6
,
2225 (struct sockaddr
*)&in6
);
2228 static void *make_netns(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2229 int argc _U_
, char ** argv _U_
)
2231 int sd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
2233 err(EXIT_FAILURE
, "failed in socket()");
2235 int ns
= ioctl(sd
, SIOCGSKNS
);
2237 err_nosys(EXIT_FAILURE
, "failed in ioctl(SIOCGSKNS)");
2240 if (ns
!= fdescs
[0].fd
) {
2241 if (dup2(ns
, fdescs
[0].fd
) < 0) {
2245 err(EXIT_FAILURE
, "failed to dup %d -> %d", ns
, fdescs
[0].fd
);
2250 fdescs
[0] = (struct fdesc
){
2252 .close
= close_fdesc
,
2259 static void *make_netlink(const struct factory
*factory
, struct fdesc fdescs
[],
2260 int argc
, char ** argv
)
2262 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
2263 int iprotocol
= ARG_INTEGER(protocol
);
2264 struct arg groups
= decode_arg("groups", factory
->params
, argc
, argv
);
2265 unsigned int ugroups
= ARG_UINTEGER(groups
);
2268 free_arg(&protocol
);
2270 sd
= socket(AF_NETLINK
, SOCK_RAW
, iprotocol
);
2272 err((errno
== EPROTONOSUPPORT
)? EXIT_EPROTONOSUPPORT
: EXIT_FAILURE
,
2273 "failed in socket()");
2275 if (sd
!= fdescs
[0].fd
) {
2276 if (dup2(sd
, fdescs
[0].fd
) < 0) {
2280 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
2285 struct sockaddr_nl nl
;
2286 memset(&nl
, 0, sizeof(nl
));
2287 nl
.nl_family
= AF_NETLINK
;
2288 nl
.nl_groups
= ugroups
;
2289 if (bind(sd
, (struct sockaddr
*)&nl
, sizeof(nl
)) < 0) {
2293 err(EXIT_FAILURE
, "failed in bind(2)");
2296 fdescs
[0] = (struct fdesc
){
2298 .close
= close_fdesc
,
2305 static void *make_eventfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2306 int argc _U_
, char ** argv _U_
)
2309 pid_t
*pid
= xcalloc(1, sizeof(*pid
));
2311 if (fdescs
[0].fd
== fdescs
[1].fd
)
2312 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2316 err(EXIT_FAILURE
, "failed in eventfd(2)");
2318 if (fd
!= fdescs
[0].fd
) {
2319 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2323 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2328 fdescs
[0] = (struct fdesc
){
2330 .close
= close_fdesc
,
2334 if (dup2(fdescs
[0].fd
, fdescs
[1].fd
) < 0) {
2336 close(fdescs
[0].fd
);
2338 err(EXIT_FAILURE
, "failed to dup %d -> %d", fdescs
[0].fd
, fdescs
[1].fd
);
2341 signal(SIGCHLD
, abort_with_child_death_message
);
2345 close(fdescs
[0].fd
);
2346 close(fdescs
[1].fd
);
2348 err(EXIT_FAILURE
, "failed in fork()");
2349 } else if (*pid
== 0) {
2353 close(fdescs
[0].fd
);
2355 signal(SIGCONT
, do_nothing
);
2356 /* Notify the parent that I'm ready. */
2357 if (write(fdescs
[1].fd
, &v
, sizeof(v
)) != sizeof(v
)) {
2358 close(fdescs
[1].fd
);
2360 "failed in write() to notify the readiness to the prent");
2362 /* Wait till the parent lets me go. */
2365 close(fdescs
[1].fd
);
2370 /* The child owns fdescs[1]. */
2371 close(fdescs
[1].fd
);
2374 /* Wait till the child is ready. */
2375 if (read(fdescs
[0].fd
, &v
, sizeof(uint64_t)) != sizeof(v
)) {
2377 close(fdescs
[0].fd
);
2379 "failed in read() the readiness notification from the child");
2381 signal(SIGCHLD
, SIG_DFL
);
2387 static void report_eventfd(const struct factory
*factory _U_
,
2388 int nth
, void *data
, FILE *fp
)
2391 pid_t
*child
= data
;
2392 fprintf(fp
, "%d", *child
);
2396 static void free_eventfd(const struct factory
* factory _U_
, void *data
)
2398 pid_t child
= *(pid_t
*)data
;
2403 kill(child
, SIGCONT
);
2404 if (waitpid(child
, &wstatus
, 0) < 0)
2405 err(EXIT_FAILURE
, "failed in waitpid()");
2407 if (WIFEXITED(wstatus
)) {
2408 int s
= WEXITSTATUS(wstatus
);
2410 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2411 } else if (WIFSIGNALED(wstatus
)) {
2412 int s
= WTERMSIG(wstatus
);
2413 if (WTERMSIG(wstatus
) != 0)
2414 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2418 struct mqueue_data
{
2424 static void mqueue_data_free(struct mqueue_data
*data
)
2427 mq_unlink(data
->path
);
2428 free((void *)data
->path
);
2432 static void report_mqueue(const struct factory
*factory _U_
,
2433 int nth
, void *data
, FILE *fp
)
2436 fprintf(fp
, "%d", ((struct mqueue_data
*)data
)->pid
);
2440 static void close_mqueue(int fd
, void *data _U_
)
2445 static void free_mqueue(const struct factory
* factory _U_
, void *data
)
2447 struct mqueue_data
*mqueue_data
= data
;
2448 pid_t child
= mqueue_data
->pid
;
2451 mqueue_data_free(mqueue_data
);
2453 kill(child
, SIGCONT
);
2454 if (waitpid(child
, &wstatus
, 0) < 0)
2455 err(EXIT_FAILURE
, "failed in waitpid()");
2457 if (WIFEXITED(wstatus
)) {
2458 int s
= WEXITSTATUS(wstatus
);
2460 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2461 } else if (WIFSIGNALED(wstatus
)) {
2462 int s
= WTERMSIG(wstatus
);
2463 if (WTERMSIG(wstatus
) != 0)
2464 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2468 static void *make_mqueue(const struct factory
*factory
, struct fdesc fdescs
[],
2469 int argc
, char ** argv
)
2471 struct mqueue_data
*mqueue_data
;
2472 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
2473 const char *spath
= ARG_STRING(path
);
2475 struct mq_attr attr
= {
2482 if (spath
[0] != '/')
2483 errx(EXIT_FAILURE
, "the path for mqueue must start with '/': %s", spath
);
2485 if (spath
[0] == '\0')
2486 err(EXIT_FAILURE
, "the path should not be empty");
2488 if (fdescs
[0].fd
== fdescs
[1].fd
)
2489 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2491 mqueue_data
= xmalloc(sizeof(*mqueue_data
));
2492 mqueue_data
->pid
= 0;
2493 mqueue_data
->path
= xstrdup(spath
);
2494 mqueue_data
->created
= false;
2498 fd
= mq_open(mqueue_data
->path
, O_CREAT
|O_EXCL
| O_RDONLY
, S_IRUSR
| S_IWUSR
, &attr
);
2500 mqueue_data_free(mqueue_data
);
2501 err(EXIT_FAILURE
, "failed in mq_open(3) for reading");
2504 mqueue_data
->created
= true;
2505 if (fd
!= fdescs
[0].fd
) {
2506 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2509 mqueue_data_free(mqueue_data
);
2511 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2516 fdescs
[0] = (struct fdesc
){
2518 .close
= close_mqueue
,
2522 fd
= mq_open(mqueue_data
->path
, O_WRONLY
, S_IRUSR
| S_IWUSR
, NULL
);
2525 mq_close(fdescs
[0].fd
);
2526 mqueue_data_free(mqueue_data
);
2528 err(EXIT_FAILURE
, "failed in mq_open(3) for writing");
2531 if (fd
!= fdescs
[1].fd
) {
2532 if (dup2(fd
, fdescs
[1].fd
) < 0) {
2535 mq_close(fdescs
[0].fd
);
2537 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[1].fd
);
2541 fdescs
[1] = (struct fdesc
){
2543 .close
= close_mqueue
,
2547 signal(SIGCHLD
, abort_with_child_death_message
);
2548 mqueue_data
->pid
= fork();
2549 if (mqueue_data
->pid
< -1) {
2551 mq_close(fdescs
[0].fd
);
2552 mq_close(fdescs
[1].fd
);
2553 mqueue_data_free(mqueue_data
);
2555 err(EXIT_FAILURE
, "failed in fork()");
2556 } else if (mqueue_data
->pid
== 0) {
2557 mqueue_data
->created
= false;
2558 mqueue_data_free(mqueue_data
);
2559 mq_close(fdescs
[0].fd
);
2561 signal(SIGCONT
, do_nothing
);
2562 /* Notify the parent that I'm ready. */
2563 if (mq_send(fdescs
[1].fd
, "", 0, 0) < 0)
2565 "failed in mq_send() to notify the readiness to the prent");
2566 /* Wait till the parent lets me go. */
2569 mq_close(fdescs
[1].fd
);
2574 /* The child owns fdescs[1]. */
2575 mq_close(fdescs
[1].fd
);
2578 /* Wait till the child is ready. */
2579 if (mq_receive(fdescs
[0].fd
, &c
, 1, NULL
) < 0) {
2580 mq_close(fdescs
[0].fd
);
2581 mqueue_data_free(mqueue_data
);
2583 "failed in mq_receive() the readiness notification from the child");
2585 signal(SIGCHLD
, SIG_DFL
);
2590 struct sysvshm_data
{
2595 static void *make_sysvshm(const struct factory
*factory _U_
, struct fdesc fdescs
[] _U_
,
2596 int argc _U_
, char ** argv _U_
)
2598 size_t pagesize
= getpagesize();
2599 struct sysvshm_data
*sysvshm_data
;
2600 int id
= shmget(IPC_PRIVATE
, pagesize
, IPC_CREAT
| 0600);
2604 err(EXIT_FAILURE
, "failed to do shmget(.., %zu, ...)",
2607 start
= shmat(id
, NULL
, SHM_RDONLY
);
2608 if (start
== (void *) -1) {
2610 shmctl(id
, IPC_RMID
, NULL
);
2612 err(EXIT_FAILURE
, "failed to do shmat(%d,...)", id
);
2615 sysvshm_data
= xmalloc(sizeof(*sysvshm_data
));
2616 sysvshm_data
->addr
= start
;
2617 sysvshm_data
->id
= id
;
2618 return sysvshm_data
;
2621 static void free_sysvshm(const struct factory
*factory _U_
, void *data
)
2623 struct sysvshm_data
*sysvshm_data
= data
;
2625 shmdt(sysvshm_data
->addr
);
2626 shmctl(sysvshm_data
->id
, IPC_RMID
, NULL
);
2629 static void *make_eventpoll(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2630 int argc _U_
, char ** argv _U_
)
2639 .file
= "DUMMY, DONT'USE THIS"
2641 .file
= "/dev/random",
2645 .file
= "/dev/random",
2651 efd
= epoll_create(1);
2653 err(EXIT_FAILURE
, "failed in epoll_create(2)");
2654 if (efd
!= fdescs
[0].fd
) {
2655 if (dup2(efd
, fdescs
[0].fd
) < 0) {
2659 err(EXIT_FAILURE
, "failed to dup %d -> %d", efd
, fdescs
[0].fd
);
2664 fdescs
[0] = (struct fdesc
){
2666 .close
= close_fdesc
,
2670 for (size_t i
= 1; i
< ARRAY_SIZE(specs
); i
++) {
2671 int fd
= open(specs
[i
].file
, specs
[i
].flag
);
2675 for (size_t j
= i
- 1; j
> 0; j
--)
2676 close(fdescs
[j
].fd
);
2678 err(EXIT_FAILURE
, "failed in open(\"%s\",...)",
2681 if (fd
!= fdescs
[i
].fd
) {
2682 if (dup2(fd
, fdescs
[i
].fd
) < 0) {
2685 for (size_t j
= i
- 1; j
> 0; j
--)
2686 close(fdescs
[j
].fd
);
2689 err(EXIT_FAILURE
, "failed to dup %d -> %d",
2694 fdescs
[i
] = (struct fdesc
) {
2696 .close
= close_fdesc
,
2699 if (epoll_ctl(efd
, EPOLL_CTL_ADD
, fdescs
[i
].fd
,
2700 &(struct epoll_event
) {
2701 .events
= specs
[i
].events
,
2702 .data
= {.ptr
= NULL
,}
2706 for (size_t j
= i
; j
> 0; j
--)
2707 close(fdescs
[j
].fd
);
2710 "failed to add fd %d to the eventpoll fd with epoll_ctl",
2718 static bool decode_clockid(const char *sclockid
, clockid_t
*clockid
)
2720 if (sclockid
== NULL
)
2722 if (sclockid
[0] == '\0')
2725 if (strcmp(sclockid
, "realtime") == 0)
2726 *clockid
= CLOCK_REALTIME
;
2727 else if (strcmp(sclockid
, "monotonic") == 0)
2728 *clockid
= CLOCK_MONOTONIC
;
2729 else if (strcmp(sclockid
, "boottime") == 0)
2730 *clockid
= CLOCK_BOOTTIME
;
2731 else if (strcmp(sclockid
, "realtime-alarm") == 0)
2732 *clockid
= CLOCK_REALTIME_ALARM
;
2733 else if (strcmp(sclockid
, "boottime-alarm") == 0)
2734 *clockid
= CLOCK_BOOTTIME_ALARM
;
2740 static void *make_timerfd(const struct factory
*factory
, struct fdesc fdescs
[],
2741 int argc
, char ** argv
)
2744 struct timespec now
;
2745 struct itimerspec tspec
;
2747 struct arg abstime
= decode_arg("abstime", factory
->params
, argc
, argv
);
2748 bool babstime
= ARG_BOOLEAN(abstime
);
2750 struct arg remaining
= decode_arg("remaining", factory
->params
, argc
, argv
);
2751 unsigned int uremaining
= ARG_UINTEGER(remaining
);
2753 struct arg interval
= decode_arg("interval", factory
->params
, argc
, argv
);
2754 unsigned int uinterval
= ARG_UINTEGER(interval
);
2756 struct arg interval_frac
= decode_arg("interval-nanofrac", factory
->params
, argc
, argv
);
2757 unsigned int uinterval_frac
= ARG_UINTEGER(interval_frac
);
2759 struct arg clockid_
= decode_arg("clockid", factory
->params
, argc
, argv
);
2760 const char *sclockid
= ARG_STRING(clockid_
);
2763 if (decode_clockid (sclockid
, &clockid
) == false)
2764 err(EXIT_FAILURE
, "unknown clockid: %s", sclockid
);
2766 free_arg(&clockid_
);
2767 free_arg(&interval_frac
);
2768 free_arg(&interval
);
2769 free_arg(&remaining
);
2773 int r
= clock_gettime(clockid
, &now
);
2775 err(EXIT_FAILURE
, "failed in clock_gettime(2)");
2778 tfd
= timerfd_create(clockid
, 0);
2780 err(EXIT_FAILURE
, "failed in timerfd_create(2)");
2782 tspec
.it_value
.tv_sec
= (babstime
? now
.tv_sec
: 0) + uremaining
;
2783 tspec
.it_value
.tv_nsec
= (babstime
? now
.tv_nsec
: 0);
2785 tspec
.it_interval
.tv_sec
= uinterval
;
2786 tspec
.it_interval
.tv_nsec
= uinterval_frac
;
2788 if (timerfd_settime(tfd
, babstime
? TFD_TIMER_ABSTIME
: 0, &tspec
, NULL
) < 0) {
2792 err(EXIT_FAILURE
, "failed in timerfd_settime(2)");
2795 if (tfd
!= fdescs
[0].fd
) {
2796 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2800 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2805 fdescs
[0] = (struct fdesc
){
2807 .close
= close_fdesc
,
2814 static void *make_signalfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2815 int argc _U_
, char ** argv _U_
)
2820 if (sigemptyset(&mask
) < 0)
2821 err(EXIT_FAILURE
, "failed in sigemptyset()");
2822 if (sigaddset(&mask
, SIGFPE
) < 0)
2823 err(EXIT_FAILURE
, "failed in sigaddset(FPE)");
2824 if (sigaddset(&mask
, SIGUSR1
) < 0)
2825 err(EXIT_FAILURE
, "failed in sigaddset(USR1)");
2826 if (sigaddset(&mask
, numsig
) < 0)
2827 err(EXIT_FAILURE
, "failed in sigaddset(%d)", numsig
);
2829 int sfd
= signalfd(-1, &mask
, 0);
2831 err(EXIT_FAILURE
, "failed in signalfd(2)");
2833 if (sfd
!= fdescs
[0].fd
) {
2834 if (dup2(sfd
, fdescs
[0].fd
) < 0) {
2838 err(EXIT_FAILURE
, "failed to dup %d -> %d", sfd
, fdescs
[0].fd
);
2843 fdescs
[0] = (struct fdesc
){
2845 .close
= close_fdesc
,
2853 /* ref. linux/Documentation/networking/tuntap.rst */
2854 static void *make_cdev_tun(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2855 int argc _U_
, char ** argv _U_
)
2857 int tfd
= open("/dev/net/tun", O_RDWR
);
2861 err(EXIT_FAILURE
, "failed in opening /dev/net/tun");
2863 memset(&ifr
, 0, sizeof(ifr
));
2865 ifr
.ifr_flags
= IFF_TUN
;
2866 strcpy(ifr
.ifr_name
, "mkfds%d");
2868 if (ioctl(tfd
, TUNSETIFF
, (void *) &ifr
) < 0) {
2872 err(EXIT_FAILURE
, "failed in setting \"lo\" to the tun device");
2875 if (tfd
!= fdescs
[0].fd
) {
2876 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2880 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2885 fdescs
[0] = (struct fdesc
){
2887 .close
= close_fdesc
,
2891 return xstrdup(ifr
.ifr_name
);
2894 static void report_cdev_tun(const struct factory
*factory _U_
,
2895 int nth
, void *data
, FILE *fp
)
2898 char *devname
= data
;
2899 fprintf(fp
, "%s", devname
);
2903 static void free_cdev_tun(const struct factory
* factory _U_
, void *data
)
2908 static void *make_bpf_prog(const struct factory
*factory
, struct fdesc fdescs
[],
2909 int argc
, char ** argv
)
2911 struct arg prog_type_id
= decode_arg("prog-type-id", factory
->params
, argc
, argv
);
2912 int iprog_type_id
= ARG_INTEGER(prog_type_id
);
2914 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
2915 const char *sname
= ARG_STRING(name
);
2918 union bpf_attr attr
;
2919 /* Just doing exit with 0. */
2920 struct bpf_insn insns
[] = {
2922 .code
= BPF_ALU64
| BPF_MOV
| BPF_K
,
2923 .dst_reg
= BPF_REG_0
, .src_reg
= 0, .off
= 0, .imm
= 0
2926 .code
= BPF_JMP
| BPF_EXIT
,
2927 .dst_reg
= 0, .src_reg
= 0, .off
= 0, .imm
= 0
2931 memset(&attr
, 0, sizeof(attr
));
2932 attr
.prog_type
= iprog_type_id
;
2933 attr
.insns
= (uint64_t)(unsigned long)insns
;
2934 attr
.insn_cnt
= ARRAY_SIZE(insns
);
2935 attr
.license
= (int64_t)(unsigned long)"GPL";
2936 strncpy(attr
.prog_name
, sname
, sizeof(attr
.prog_name
) - 1);
2939 free_arg(&prog_type_id
);
2941 bfd
= syscall(SYS_bpf
, BPF_PROG_LOAD
, &attr
, sizeof(attr
));
2943 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_PROG_LOAD)");
2945 if (bfd
!= fdescs
[0].fd
) {
2946 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
2950 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
2955 fdescs
[0] = (struct fdesc
){
2957 .close
= close_fdesc
,
2964 static void *make_some_pipes(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2965 int argc _U_
, char ** argv _U_
)
2967 /* Reserver fds before making pipes */
2968 for (int i
= 0; i
< factory
->N
; i
++) {
2969 close(fdescs
[i
].fd
);
2970 if (dup2(0, fdescs
[0].fd
) < 0)
2971 err(EXIT_FAILURE
, "failed to reserve fd %d with dup2", fdescs
[0].fd
);
2974 for (int i
= 0; i
< (factory
->N
) / 2; i
++) {
2979 mode
= 1 << (i
% 3);
2980 if (mode
== MX_WRITE
) {
2986 err(EXIT_FAILURE
, "failed to make pipe");
2988 if (dup2(pd
[0], fdescs
[2 * i
+ r
].fd
) < 0)
2989 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[0], fdescs
[2 * i
+ r
].fd
);
2991 fdescs
[2 * 1 + r
].close
= close_fdesc
;
2993 if (dup2(pd
[1], fdescs
[2 * i
+ w
].fd
) < 0)
2994 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[1], fdescs
[2 * i
+ 2].fd
);
2996 fdescs
[2 * 1 + w
].close
= close_fdesc
;
2998 fdescs
[2 * i
].mx_modes
|= mode
;
3000 /* Make the pipe for writing full. */
3001 if (fdescs
[2 * i
].mx_modes
& MX_WRITE
) {
3002 int n
= fcntl(fdescs
[2 * i
].fd
, F_GETPIPE_SZ
);
3006 err(EXIT_FAILURE
, "failed to get PIPE BUFFER SIZE from %d", fdescs
[2 * i
].fd
);
3009 if (write(fdescs
[2 * i
].fd
, buf
, n
) != n
)
3010 err(EXIT_FAILURE
, "failed to fill the pipe buffer specified with %d",
3020 static void *make_bpf_map(const struct factory
*factory
, struct fdesc fdescs
[],
3021 int argc
, char ** argv
)
3023 struct arg map_type_id
= decode_arg("map-type-id", factory
->params
, argc
, argv
);
3024 int imap_type_id
= ARG_INTEGER(map_type_id
);
3026 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
3027 const char *sname
= ARG_STRING(name
);
3030 union bpf_attr attr
= {
3031 .map_type
= imap_type_id
,
3037 strncpy(attr
.map_name
, sname
, sizeof(attr
.map_name
) - 1);
3040 free_arg(&map_type_id
);
3042 bfd
= syscall(SYS_bpf
, BPF_MAP_CREATE
, &attr
, sizeof(attr
));
3044 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_MAP_CREATE)");
3046 if (bfd
!= fdescs
[0].fd
) {
3047 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
3051 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
3056 fdescs
[0] = (struct fdesc
){
3058 .close
= close_fdesc
,
3065 static void *make_pty(const struct factory
*factory _U_
, struct fdesc fdescs
[],
3066 int argc _U_
, char ** argv _U_
)
3071 int ptmx_fd
= posix_openpt(O_RDWR
);
3073 err(EXIT_FAILURE
, "failed in opening /dev/ptmx");
3075 if (unlockpt(ptmx_fd
) < 0) {
3079 err(EXIT_FAILURE
, "failed in unlockpt()");
3082 if (ioctl(ptmx_fd
, TIOCGPTN
, &index
) < 0) {
3086 err(EXIT_FAILURE
, "failed in ioctl(TIOCGPTN)");
3089 pts
= ptsname(ptmx_fd
);
3094 err(EXIT_FAILURE
, "failed in ptsname()");
3097 if (ptmx_fd
!= fdescs
[0].fd
) {
3098 if (dup2(ptmx_fd
, fdescs
[0].fd
) < 0) {
3102 err(EXIT_FAILURE
, "failed to dup %d -> %d", ptmx_fd
, fdescs
[0].fd
);
3105 ptmx_fd
= fdescs
[0].fd
;
3108 pts_fd
= open(pts
, O_RDONLY
);
3113 err(EXIT_FAILURE
, "failed in opening %s", pts
);
3116 if (pts_fd
!= fdescs
[1].fd
) {
3117 if (dup2(pts_fd
, fdescs
[1].fd
) < 0) {
3122 err(EXIT_FAILURE
, "failed to dup %d -> %d", pts_fd
, fdescs
[1].fd
);
3125 pts_fd
= fdescs
[1].fd
;
3128 fdescs
[0] = (struct fdesc
){
3130 .close
= close_fdesc
,
3133 fdescs
[1] = (struct fdesc
){
3135 .close
= close_fdesc
,
3139 indexp
= xmalloc(sizeof(index
));
3144 static void report_pty(const struct factory
*factory _U_
,
3145 int nth
, void *data
, FILE *fp
)
3149 fprintf(fp
, "%d", *index
);
3153 static void free_pty(const struct factory
* factory _U_
, void *data
)
3158 #define PARAM_END { .name = NULL, }
3159 static const struct factory factories
[] = {
3161 .name
= "ro-regular-file",
3162 .desc
= "read-only regular file",
3166 .make
= open_ro_regular_file
,
3167 .params
= (struct parameter
[]) {
3170 .type
= PTYPE_STRING
,
3171 .desc
= "file to be opened",
3172 .defv
.string
= "/etc/passwd",
3176 .type
= PTYPE_INTEGER
,
3177 .desc
= "seek bytes after open with SEEK_CUR",
3181 .name
= "read-lease",
3182 .type
= PTYPE_BOOLEAN
,
3183 .desc
= "taking out read lease for the file",
3184 .defv
.boolean
= false,
3190 .name
= "make-regular-file",
3191 .desc
= "regular file for writing",
3195 .make
= make_w_regular_file
,
3196 .free
= free_after_closing_duplicated_fd
,
3197 .params
= (struct parameter
[]) {
3200 .type
= PTYPE_STRING
,
3201 .desc
= "file to be made",
3202 .defv
.string
= "./test_mkfds_make_regular_file",
3206 .type
= PTYPE_BOOLEAN
,
3207 .desc
= "delete the file just after making it",
3208 .defv
.boolean
= false,
3211 .name
= "write-bytes",
3212 .type
= PTYPE_INTEGER
,
3213 .desc
= "write something (> 0)",
3218 .type
= PTYPE_BOOLEAN
,
3219 .desc
= "open the new file readable way",
3220 .defv
.string
= false,
3224 .type
= PTYPE_STRING
,
3225 .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",
3226 .defv
.string
= "none",
3230 .type
= PTYPE_INTEGER
,
3231 .desc
= "the number for the fd duplicated from the original fd",
3238 .name
= "pipe-no-fork",
3239 .desc
= "making pair of fds with pipe(2)",
3244 .params
= (struct parameter
[]) {
3247 .type
= PTYPE_STRING
,
3248 .desc
= "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")",
3249 .defv
.string
= "--",
3253 .type
= PTYPE_INTEGER
,
3254 .desc
= "file descriptor for duplicating the pipe input",
3259 .type
= PTYPE_INTEGER
,
3260 .desc
= "file descriptor for duplicating the pipe output",
3267 .name
= "directory",
3268 .desc
= "directory",
3272 .make
= open_directory
,
3273 .params
= (struct parameter
[]) {
3276 .type
= PTYPE_STRING
,
3277 .desc
= "directory to be opened",
3282 .type
= PTYPE_INTEGER
,
3283 .desc
= "read the number of dentries after open with readdir(3)",
3290 .name
= "rw-character-device",
3291 .desc
= "character device with O_RDWR flag",
3295 .make
= open_rw_chrdev
,
3296 .params
= (struct parameter
[]) {
3299 .type
= PTYPE_STRING
,
3300 .desc
= "character device node to be opened",
3301 .defv
.string
= "/dev/zero",
3307 .name
= "socketpair",
3308 .desc
= "AF_UNIX socket pair created with socketpair(2)",
3312 .make
= make_socketpair
,
3313 .params
= (struct parameter
[]) {
3316 .type
= PTYPE_STRING
,
3317 .desc
= "STREAM, DGRAM, or SEQPACKET",
3318 .defv
.string
= "STREAM",
3321 .name
= "halfclose",
3322 .type
= PTYPE_BOOLEAN
,
3323 .desc
= "Shutdown the read end of the 1st socket, the write end of the 2nd socket",
3324 .defv
.boolean
= false,
3331 .desc
= "symbolic link itself opened with O_PATH",
3335 .make
= open_with_opath
,
3336 .params
= (struct parameter
[]) {
3339 .type
= PTYPE_STRING
,
3340 .desc
= "path to a symbolic link",
3341 .defv
.string
= "/dev/stdin",
3347 .name
= "ro-block-device",
3348 .desc
= "block device with O_RDONLY flag",
3352 .make
= open_ro_blkdev
,
3353 .params
= (struct parameter
[]) {
3356 .type
= PTYPE_STRING
,
3357 .desc
= "block device node to be opened",
3358 .defv
.string
= "/dev/nullb0",
3364 .name
= "mapped-packet-socket",
3365 .desc
= "mmap'ed AF_PACKET socket",
3369 .make
= make_mmapped_packet_socket
,
3370 .params
= (struct parameter
[]) {
3373 .type
= PTYPE_STRING
,
3374 .desc
= "DGRAM or RAW",
3375 .defv
.string
= "RAW",
3378 .name
= "interface",
3379 .type
= PTYPE_STRING
,
3380 .desc
= "a name of network interface like eth0 or lo",
3381 .defv
.string
= "lo",
3388 .desc
= "pidfd returned from pidfd_open(2)",
3393 .params
= (struct parameter
[]) {
3395 .name
= "target-pid",
3396 .type
= PTYPE_INTEGER
,
3397 .desc
= "the pid of the target process",
3405 .desc
= "inotify fd returned from inotify_init(2)",
3409 .make
= make_inotify_fd
,
3410 .params
= (struct parameter
[]) {
3413 .type
= PTYPE_STRING
,
3414 .desc
= "the directory that the inotify monitors",
3419 .type
= PTYPE_STRING
,
3420 .desc
= "the file that the inotify monitors",
3421 .defv
.string
= "/etc/fstab",
3427 .name
= "unix-stream",
3428 .desc
= "AF_UNIX+SOCK_STREAM sockets",
3432 .make
= make_unix_stream
,
3433 .params
= (struct parameter
[]) {
3436 .type
= PTYPE_STRING
,
3437 .desc
= "path for listening-socket bound to",
3438 .defv
.string
= "/tmp/test_mkfds-unix-stream",
3442 .type
= PTYPE_INTEGER
,
3443 .desc
= "backlog passed to listen(2)",
3448 .type
= PTYPE_BOOLEAN
,
3449 .desc
= "use PATH as an abstract socket address",
3450 .defv
.boolean
= false,
3453 .name
= "server-shutdown",
3454 .type
= PTYPE_INTEGER
,
3455 .desc
= "shutdown the accepted socket; 1: R, 2: W, 3: RW",
3459 .name
= "client-shutdown",
3460 .type
= PTYPE_INTEGER
,
3461 .desc
= "shutdown the client socket; 1: R, 2: W, 3: RW",
3466 .type
= PTYPE_STRING
,
3467 .desc
= "stream or seqpacket",
3468 .defv
.string
= "stream",
3474 .name
= "unix-dgram",
3475 .desc
= "AF_UNIX+SOCK_DGRAM sockets",
3479 .make
= make_unix_dgram
,
3480 .params
= (struct parameter
[]) {
3483 .type
= PTYPE_STRING
,
3484 .desc
= "path for unix non-stream bound to",
3485 .defv
.string
= "/tmp/test_mkfds-unix-dgram",
3489 .type
= PTYPE_BOOLEAN
,
3490 .desc
= "use PATH as an abstract socket address",
3491 .defv
.boolean
= false,
3497 .name
= "unix-in-netns",
3498 .desc
= "make a unix socket in a new network namespace",
3502 .make
= make_unix_in_new_netns
,
3503 .params
= (struct parameter
[]) {
3506 .type
= PTYPE_STRING
,
3507 .desc
= "dgram, stream, or seqpacket",
3508 .defv
.string
= "stream",
3512 .type
= PTYPE_STRING
,
3513 .desc
= "path for unix non-stream bound to",
3514 .defv
.string
= "/tmp/test_mkfds-unix-in-netns",
3518 .type
= PTYPE_BOOLEAN
,
3519 .desc
= "use PATH as an abstract socket address",
3520 .defv
.boolean
= false,
3527 .desc
= "AF_INET+SOCK_STREAM sockets",
3532 .params
= (struct parameter
[]) {
3534 .name
= "server-port",
3535 .type
= PTYPE_INTEGER
,
3536 .desc
= "TCP port the server may listen",
3537 .defv
.integer
= 12345,
3540 .name
= "client-port",
3541 .type
= PTYPE_INTEGER
,
3542 .desc
= "TCP port the client may bind",
3543 .defv
.integer
= 23456,
3550 .desc
= "AF_INET+SOCK_DGRAM sockets",
3555 .params
= (struct parameter
[]) {
3558 .type
= PTYPE_BOOLEAN
,
3559 .desc
= "Use UDPLITE instead of UDP",
3560 .defv
.boolean
= false,
3563 .name
= "server-port",
3564 .type
= PTYPE_INTEGER
,
3565 .desc
= "UDP port the server may listen",
3566 .defv
.integer
= 12345,
3569 .name
= "client-port",
3570 .type
= PTYPE_INTEGER
,
3571 .desc
= "UDP port the client may bind",
3572 .defv
.integer
= 23456,
3575 .name
= "server-do-bind",
3576 .type
= PTYPE_BOOLEAN
,
3577 .desc
= "call bind with the server socket",
3578 .defv
.boolean
= true,
3581 .name
= "client-do-bind",
3582 .type
= PTYPE_BOOLEAN
,
3583 .desc
= "call bind with the client socket",
3584 .defv
.boolean
= true,
3587 .name
= "client-do-connect",
3588 .type
= PTYPE_BOOLEAN
,
3589 .desc
= "call connect with the client socket",
3590 .defv
.boolean
= true,
3597 .desc
= "AF_INET+SOCK_RAW sockets",
3602 .params
= (struct parameter
[]) {
3605 .type
= PTYPE_INTEGER
,
3606 .desc
= "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
3607 .defv
.integer
= IPPROTO_IPIP
,
3615 .desc
= "AF_INET+SOCK_DGRAM+IPPROTO_ICMP sockets",
3620 .params
= (struct parameter
[]) {
3623 .type
= PTYPE_BOOLEAN
,
3624 .desc
= "call connect(2) with the socket",
3625 .defv
.boolean
= true,
3629 .type
= PTYPE_BOOLEAN
,
3630 .desc
= "call bind(2) with the socket",
3631 .defv
.boolean
= true,
3635 .type
= PTYPE_INTEGER
,
3636 .desc
= "ICMP echo request id",
3644 .desc
= "AF_INET6+SOCK_STREAM sockets",
3649 .params
= (struct parameter
[]) {
3651 .name
= "server-port",
3652 .type
= PTYPE_INTEGER
,
3653 .desc
= "TCP port the server may listen",
3654 .defv
.integer
= 12345,
3657 .name
= "client-port",
3658 .type
= PTYPE_INTEGER
,
3659 .desc
= "TCP port the client may bind",
3660 .defv
.integer
= 23456,
3667 .desc
= "AF_INET6+SOCK_DGRAM sockets",
3672 .params
= (struct parameter
[]) {
3675 .type
= PTYPE_BOOLEAN
,
3676 .desc
= "Use UDPLITE instead of UDP",
3677 .defv
.boolean
= false,
3680 .name
= "server-port",
3681 .type
= PTYPE_INTEGER
,
3682 .desc
= "UDP port the server may listen",
3683 .defv
.integer
= 12345,
3686 .name
= "client-port",
3687 .type
= PTYPE_INTEGER
,
3688 .desc
= "UDP port the client may bind",
3689 .defv
.integer
= 23456,
3692 .name
= "server-do-bind",
3693 .type
= PTYPE_BOOLEAN
,
3694 .desc
= "call bind with the server socket",
3695 .defv
.boolean
= true,
3698 .name
= "client-do-bind",
3699 .type
= PTYPE_BOOLEAN
,
3700 .desc
= "call bind with the client socket",
3701 .defv
.boolean
= true,
3704 .name
= "client-do-connect",
3705 .type
= PTYPE_BOOLEAN
,
3706 .desc
= "call connect with the client socket",
3707 .defv
.boolean
= true,
3714 .desc
= "AF_INET6+SOCK_RAW sockets",
3719 .params
= (struct parameter
[]) {
3722 .type
= PTYPE_INTEGER
,
3723 .desc
= "protocol passed to socket(AF_INET6, SOCK_RAW, protocol)",
3724 .defv
.integer
= IPPROTO_IPIP
,
3732 .desc
= "AF_INET6+SOCK_DGRAM+IPPROTO_ICMPV6 sockets",
3737 .params
= (struct parameter
[]) {
3740 .type
= PTYPE_BOOLEAN
,
3741 .desc
= "call connect(2) with the socket",
3742 .defv
.boolean
= true,
3746 .type
= PTYPE_BOOLEAN
,
3747 .desc
= "call bind(2) with the socket",
3748 .defv
.boolean
= true,
3752 .type
= PTYPE_INTEGER
,
3753 .desc
= "ICMP echo request id",
3761 .desc
= "open a file specifying a netns",
3766 .params
= (struct parameter
[]) {
3772 .desc
= "AF_NETLINK sockets",
3776 .make
= make_netlink
,
3777 .params
= (struct parameter
[]) {
3780 .type
= PTYPE_INTEGER
,
3781 .desc
= "protocol passed to socket(AF_NETLINK, SOCK_RAW, protocol)",
3782 .defv
.integer
= NETLINK_USERSOCK
,
3786 .type
= PTYPE_UINTEGER
,
3787 .desc
= "multicast groups of netlink communication (requires CAP_NET_ADMIN)",
3795 .desc
= "make an eventfd connecting two processes",
3800 .make
= make_eventfd
,
3801 .report
= report_eventfd
,
3802 .free
= free_eventfd
,
3803 .params
= (struct parameter
[]) {
3809 .desc
= "make a mqueue connecting two processes",
3814 .make
= make_mqueue
,
3815 .report
= report_mqueue
,
3816 .free
= free_mqueue
,
3817 .params
= (struct parameter
[]) {
3820 .type
= PTYPE_STRING
,
3821 .desc
= "path for mqueue",
3822 .defv
.string
= "/test_mkfds-mqueue",
3829 .desc
= "shared memory mapped with SYSVIPC shmem syscalls",
3833 .make
= make_sysvshm
,
3834 .free
= free_sysvshm
,
3835 .params
= (struct parameter
[]) {
3840 .name
= "eventpoll",
3841 .desc
= "make eventpoll (epoll) file",
3845 .make
= make_eventpoll
,
3846 .params
= (struct parameter
[]) {
3852 .desc
= "make timerfd",
3856 .make
= make_timerfd
,
3857 .params
= (struct parameter
[]) {
3860 .type
= PTYPE_STRING
,
3861 .desc
= "ID: realtime, monotonic, boottime, realtime-alarm, or boottime-alarm",
3862 .defv
.string
= "realtime",
3866 .type
= PTYPE_BOOLEAN
,
3867 .desc
= "use TFD_TIMER_ABSTIME flag",
3868 .defv
.boolean
= false,
3871 .name
= "remaining",
3872 .type
= PTYPE_UINTEGER
,
3873 .desc
= "remaining seconds for expiration",
3874 .defv
.uinteger
= 99,
3878 .type
= PTYPE_UINTEGER
,
3879 .desc
= "inteval in seconds",
3880 .defv
.uinteger
= 10,
3883 .name
= "interval-nanofrac",
3884 .type
= PTYPE_UINTEGER
,
3885 .desc
= "nsec part of inteval",
3894 .desc
= "make signalfd",
3898 .make
= make_signalfd
,
3899 .params
= (struct parameter
[]) {
3905 .desc
= "open /dev/net/tun",
3910 .make
= make_cdev_tun
,
3911 .report
= report_cdev_tun
,
3912 .free
= free_cdev_tun
,
3913 .params
= (struct parameter
[]) {
3919 .desc
= "make bpf-prog",
3923 .make
= make_bpf_prog
,
3924 .params
= (struct parameter
[]) {
3926 .name
= "prog-type-id",
3927 .type
= PTYPE_INTEGER
,
3928 .desc
= "program type by id",
3933 .type
= PTYPE_STRING
,
3934 .desc
= "name assigned to bpf prog object",
3935 .defv
.string
= "mkfds_bpf_prog",
3941 .name
= "multiplexing",
3942 .desc
= "making pipes monitored by multiplexers",
3946 .make
= make_some_pipes
,
3947 .params
= (struct parameter
[]) {
3953 .desc
= "make bpf-map",
3957 .make
= make_bpf_map
,
3958 .params
= (struct parameter
[]) {
3960 .name
= "map-type-id",
3961 .type
= PTYPE_INTEGER
,
3962 .desc
= "map type by id",
3967 .type
= PTYPE_STRING
,
3968 .desc
= "name assigned to the bpf map object",
3969 .defv
.string
= "mkfds_bpf_map",
3976 .desc
= "make a pair of ptmx and pts",
3982 .report
= report_pty
,
3984 .params
= (struct parameter
[]) {
3990 static int count_parameters(const struct factory
*factory
)
3993 const struct parameter
*p
= factory
->params
;
3998 return p
- factory
->params
;
4001 static void print_factory(const struct factory
*factory
)
4003 printf("%-20s %4s %5d %7d %6d %s\n",
4005 factory
->priv
? "yes": "no",
4008 count_parameters(factory
),
4012 static void list_factories(void)
4014 printf("%-20s PRIV COUNT NRETURN NPARAM DESCRIPTION\n", "FACTORY");
4015 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4016 print_factory(factories
+ i
);
4019 static const struct factory
*find_factory(const char *name
)
4021 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4022 if (strcmp(factories
[i
].name
, name
) == 0)
4023 return factories
+ i
;
4027 static void list_parameters(const char *factory_name
)
4029 const struct factory
*factory
= find_factory(factory_name
);
4030 const char *fmt
= "%-15s %-8s %15s %s\n";
4033 errx(EXIT_FAILURE
, "no such factory: %s", factory_name
);
4035 if (!factory
->params
)
4038 printf(fmt
, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION");
4039 for (const struct parameter
*p
= factory
->params
; p
->name
!= NULL
; p
++) {
4040 char *defv
= ptype_classes
[p
->type
].sprint(&p
->defv
);
4041 printf(fmt
, p
->name
, ptype_classes
[p
->type
].name
, defv
, p
->desc
);
4046 static void rename_self(const char *comm
)
4048 if (prctl(PR_SET_NAME
, (unsigned long)comm
, 0, 0, 0) < 0)
4049 err(EXIT_FAILURE
, "failed to rename self via prctl: %s", comm
);
4052 static void do_nothing(int signum _U_
)
4056 #ifdef __NR_pidfd_open
4059 pidfd_open(pid_t pid
, unsigned int flags
)
4061 return syscall(__NR_pidfd_open
, pid
, flags
);
4065 pidfd_open(pid_t pid _U_
, unsigned int flags _U_
)
4075 struct multiplexer
{
4077 void (*fn
)(bool, struct fdesc
*fdescs
, size_t n_fdescs
);
4080 #if defined(__NR_select) || defined(__NR_poll)
4081 static void sighandler_nop(int si _U_
)
4087 #define DEFUN_WAIT_EVENT_SELECT(NAME,SYSCALL,XDECLS,SETUP_SIG_HANDLER,SYSCALL_INVOCATION) \
4088 static void wait_event_##NAME(bool add_stdin, struct fdesc *fdescs, size_t n_fdescs) \
4096 FD_ZERO(&readfds); \
4097 FD_ZERO(&writefds); \
4098 FD_ZERO(&exceptfds); \
4099 /* Monitor the standard input only when the process \
4100 * is in foreground. */ \
4103 FD_SET(0, &readfds); \
4106 for (size_t i = 0; i < n_fdescs; i++) { \
4107 if (fdescs[i].mx_modes & MX_READ) { \
4108 n = max(n, fdescs[i].fd + 1); \
4109 FD_SET(fdescs[i].fd, &readfds); \
4111 if (fdescs[i].mx_modes & MX_WRITE) { \
4112 n = max(n, fdescs[i].fd + 1); \
4113 FD_SET(fdescs[i].fd, &writefds); \
4115 if (fdescs[i].mx_modes & MX_EXCEPT) { \
4116 n = max(n, fdescs[i].fd + 1); \
4117 FD_SET(fdescs[i].fd, &exceptfds); \
4123 if (SYSCALL_INVOCATION < 0 \
4124 && errno != EINTR) \
4125 err(EXIT_FAILURE, "failed in " SYSCALL); \
4128 DEFUN_WAIT_EVENT_SELECT(default,
4131 sigemptyset(&sigset
);,
4132 pselect(n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4134 #ifdef __NR_pselect6
4135 DEFUN_WAIT_EVENT_SELECT(pselect6
,
4138 sigemptyset(&sigset
);,
4139 syscall(__NR_pselect6
, n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4143 DEFUN_WAIT_EVENT_SELECT(select
,
4146 signal(SIGCONT
,sighandler_nop
);,
4147 syscall(__NR_select
, n
, &readfds
, &writefds
, &exceptfds
, NULL
))
4151 static DEFUN_WAIT_EVENT_POLL(poll
,
4154 signal(SIGCONT
,sighandler_nop
);,
4155 syscall(__NR_poll
, pfds
, n
, -1))
4158 #define DEFAULT_MULTIPLEXER 0
4159 static struct multiplexer multiplexers
[] = {
4162 .fn
= wait_event_default
,
4164 #ifdef __NR_pselect6
4167 .fn
= wait_event_pselect6
,
4173 .fn
= wait_event_select
,
4179 .fn
= wait_event_poll
,
4185 .fn
= wait_event_ppoll
,
4190 static struct multiplexer
*lookup_multiplexer(const char *name
)
4192 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4193 if (strcmp(name
, multiplexers
[i
].name
) == 0)
4194 return multiplexers
+ i
;
4198 static void list_multiplexers(void)
4201 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4202 puts(multiplexers
[i
].name
);
4205 int main(int argc
, char **argv
)
4208 const struct factory
*factory
;
4209 struct fdesc fdescs
[MAX_N
];
4213 bool monitor_stdin
= true;
4215 struct multiplexer
*wait_event
= NULL
;
4217 static const struct option longopts
[] = {
4218 { "list", no_argument
, NULL
, 'l' },
4219 { "parameters", required_argument
, NULL
, 'I' },
4220 { "comm", required_argument
, NULL
, 'r' },
4221 { "quiet", no_argument
, NULL
, 'q' },
4222 { "dont-monitor-stdin", no_argument
, NULL
, 'X' },
4223 { "dont-puase", no_argument
, NULL
, 'c' },
4224 { "wait-with", required_argument
, NULL
, 'w' },
4225 { "multiplexers",no_argument
,NULL
, 'W' },
4226 { "help", no_argument
, NULL
, 'h' },
4227 { NULL
, 0, NULL
, 0 },
4230 while ((c
= getopt_long(argc
, argv
, "lhqcI:r:w:WX", longopts
, NULL
)) != -1) {
4233 usage(stdout
, EXIT_SUCCESS
);
4238 list_parameters(optarg
);
4247 wait_event
= lookup_multiplexer(optarg
);
4248 if (wait_event
== NULL
)
4249 errx(EXIT_FAILURE
, "unknown multiplexer: %s", optarg
);
4252 list_multiplexers();
4255 rename_self(optarg
);
4258 monitor_stdin
= false;
4261 usage(stderr
, EXIT_FAILURE
);
4266 errx(EXIT_FAILURE
, "no file descriptor specification given");
4268 if (cont
&& wait_event
)
4269 errx(EXIT_FAILURE
, "don't specify both -c/--dont-puase and -w/--wait-with options");
4270 if (wait_event
== NULL
)
4271 wait_event
= multiplexers
+ DEFAULT_MULTIPLEXER
;
4273 factory
= find_factory(argv
[optind
]);
4275 errx(EXIT_FAILURE
, "no such factory: %s", argv
[optind
]);
4276 assert(factory
->N
+ factory
->EX_N
< MAX_N
);
4279 if ((optind
+ factory
->N
) > argc
)
4280 errx(EXIT_FAILURE
, "not enough file descriptors given for %s",
4283 if (factory
->priv
&& getuid() != 0)
4284 errx(EXIT_FAILURE
, "%s factory requires root privilege", factory
->name
);
4286 for (int i
= 0; i
< MAX_N
; i
++) {
4288 fdescs
[i
].mx_modes
= 0;
4289 fdescs
[i
].close
= NULL
;
4292 for (int i
= 0; i
< factory
->N
; i
++) {
4293 char *str
= argv
[optind
+ i
];
4298 fd
= strtol(str
, &ep
, 10);
4300 err(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4302 errx(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4304 errx(EXIT_FAILURE
, "garbage at the end of number: %s", str
);
4306 errx(EXIT_FAILURE
, "fd number should not be negative: %s", str
);
4308 errx(EXIT_FAILURE
, "fd 0, 1, 2 are reserved: %s", str
);
4311 optind
+= factory
->N
;
4313 data
= factory
->make(factory
, fdescs
, argc
- optind
, argv
+ optind
);
4315 signal(SIGCONT
, do_nothing
);
4318 printf("%d", getpid());
4319 if (factory
->report
) {
4320 for (int i
= 0; i
< factory
->EX_R
; i
++) {
4322 factory
->report(factory
, i
, data
, stdout
);
4330 wait_event
->fn(monitor_stdin
,
4331 fdescs
, factory
->N
+ factory
->EX_N
);
4333 for (int i
= 0; i
< factory
->N
+ factory
->EX_N
; i
++)
4334 if (fdescs
[i
].fd
>= 0 && fdescs
[i
].close
)
4335 fdescs
[i
].close(fdescs
[i
].fd
, fdescs
[i
].data
);
4338 factory
->free (factory
, data
);