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(" -a, --is-available <factory> exit 0 if the factory is available\n", out
);
85 fputs(" -l, --list list available file descriptor factories and exit\n", out
);
86 fputs(" -I, --parameters <factory> list parameters the factory takes\n", out
);
87 fputs(" -r, --comm <name> rename self\n", out
);
88 fputs(" -q, --quiet don't print pid(s)\n", out
);
89 fputs(" -X, --dont-monitor-stdin don't monitor stdin when pausing\n", out
);
90 fputs(" -c, --dont-pause don't pause after making fd(s)\n", out
);
91 fputs(" -w, --wait-with <multiplexer> use MULTIPLEXER for waiting events\n", out
);
92 fputs(" -W, --multiplexers list multiplexers\n", out
);
95 fputs("Examples:\n", out
);
96 fprintf(out
, "Using 3, open /etc/group:\n\n $ %s ro-regular-file 3 file=/etc/group\n\n",
97 program_invocation_short_name
);
98 fprintf(out
, "Using 3 and 4, make a pipe:\n\n $ %s pipe-no-fork 3 4\n\n",
99 program_invocation_short_name
);
107 unsigned long uinteger
;
121 /* Covert to a string representation.
122 * A caller must free the returned value with free(3) after using. */
123 char *(*sprint
)(const union value
*value
);
125 /* Convert from a string. If ARG is NULL, use DEFV instead.
126 * A caller must free the returned value with the free method
128 union value (*read
)(const char *arg
, const union value
*defv
);
130 /* Free the value returned from the read method. */
131 void (*free
)(union value value
);
134 #define ARG_STRING(A) (A.v.string)
135 #define ARG_INTEGER(A) (A.v.integer)
136 #define ARG_UINTEGER(A) (A.v.uinteger)
137 #define ARG_BOOLEAN(A) (A.v.boolean)
140 void (*free
)(union value value
);
145 const enum ptype type
;
147 union value defv
; /* Default value */
150 static char *string_sprint(const union value
*value
)
152 return xstrdup(value
->string
);
155 static union value
string_read(const char *arg
, const union value
*defv
)
157 return (union value
){ .string
= xstrdup(arg
?: defv
->string
) };
160 static void string_free(union value value
)
162 free((void *)value
.string
);
165 static char *integer_sprint(const union value
*value
)
168 xasprintf(&str
, "%ld", value
->integer
);
172 static union value
integer_read(const char *arg
, const union value
*defv
)
181 r
.integer
= strtol(arg
, &ep
, 10);
183 err(EXIT_FAILURE
, "fail to make a number from %s", arg
);
184 else if (*ep
!= '\0')
185 errx(EXIT_FAILURE
, "garbage at the end of number: %s", arg
);
189 static void integer_free(union value value _U_
)
194 static char *uinteger_sprint(const union value
*value
)
197 xasprintf(&str
, "%lu", value
->uinteger
);
201 static union value
uinteger_read(const char *arg
, const union value
*defv
)
210 r
.uinteger
= strtoul(arg
, &ep
, 10);
212 err(EXIT_FAILURE
, "fail to make a number from %s", arg
);
213 else if (*ep
!= '\0')
214 errx(EXIT_FAILURE
, "garbage at the end of number: %s", arg
);
218 static void uinteger_free(union value value _U_
)
223 static char *boolean_sprint(const union value
*value
)
225 return xstrdup(value
->boolean
? "true": "false");
228 static union value
boolean_read(const char *arg
, const union value
*defv
)
235 if (strcasecmp(arg
, "true") == 0
236 || strcmp(arg
, "1") == 0
237 || strcasecmp(arg
, "yes") == 0
238 || strcasecmp(arg
, "y") == 0)
245 static void boolean_free(union value value _U_
)
250 struct ptype_class ptype_classes
[] = {
253 .sprint
= string_sprint
,
259 .sprint
= integer_sprint
,
260 .read
= integer_read
,
261 .free
= integer_free
,
265 .sprint
= uinteger_sprint
,
266 .read
= uinteger_read
,
267 .free
= uinteger_free
,
271 .sprint
= boolean_sprint
,
272 .read
= boolean_read
,
273 .free
= boolean_free
,
277 static struct arg
decode_arg(const char *pname
,
278 const struct parameter
*parameters
,
279 int argc
, char **argv
)
282 size_t len
= strlen(pname
);
283 const struct parameter
*p
= NULL
;
286 while (parameters
->name
) {
287 if (strcmp(pname
, parameters
->name
) == 0) {
294 errx(EXIT_FAILURE
, "no such parameter: %s", pname
);
296 for (int i
= 0; i
< argc
; i
++) {
297 if (strncmp(pname
, argv
[i
], len
) == 0) {
302 } else if (*v
== '\0')
304 "no value given for \"%s\" parameter",
310 arg
.v
= ptype_classes
[p
->type
].read (v
, &p
->defv
);
311 arg
.free
= ptype_classes
[p
->type
].free
;
315 static void free_arg(struct arg
*arg
)
321 const char *name
; /* [-a-zA-Z0-9_]+ */
323 bool priv
; /* the root privilege is needed to make fd(s) */
325 int N
; /* the number of fds this factory makes */
326 int EX_N
; /* fds made optionally */
327 int EX_R
; /* the number of extra words printed to stdout. */
328 void *(*make
)(const struct factory
*, struct fdesc
[], int, char **);
329 void (*free
)(const struct factory
*, void *);
330 void (*report
)(const struct factory
*, int, void *, FILE *);
331 const struct parameter
* params
;
334 static void close_fdesc(int fd
, void *data _U_
)
339 volatile ssize_t unused_result_ok
;
340 static void abort_with_child_death_message(int signum _U_
)
342 const char msg
[] = "the child process exits unexpectedly";
343 unused_result_ok
= write(2, msg
, sizeof(msg
));
347 static void *open_ro_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
348 int argc
, char ** argv
)
350 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
351 struct arg offset
= decode_arg("offset", factory
->params
, argc
, argv
);
352 struct arg lease_r
= decode_arg("read-lease", factory
->params
, argc
, argv
);
354 int fd
= open(ARG_STRING(file
), O_RDONLY
);
356 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(file
));
359 if (ARG_INTEGER(offset
) != 0) {
360 if (lseek(fd
, (off_t
)ARG_INTEGER(offset
), SEEK_CUR
) < 0) {
364 err(EXIT_FAILURE
, "failed to seek 0 -> %ld", ARG_INTEGER(offset
));
369 if (ARG_BOOLEAN(lease_r
)) {
370 if (fcntl(fd
, F_SETLEASE
, F_RDLCK
) < 0) {
374 err(EXIT_FAILURE
, "failed to take out a read lease");
379 if (fd
!= fdescs
[0].fd
) {
380 if (dup2(fd
, fdescs
[0].fd
) < 0) {
384 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
389 fdescs
[0] = (struct fdesc
){
391 .close
= close_fdesc
,
398 static void unlink_and_close_fdesc(int fd
, void *data
)
406 typedef void (*lockFn
)(int fd
, const char *fname
, int dupfd
);
408 static void lock_fn_none(int fd _U_
, const char *fname _U_
, int dupfd _U_
)
413 static void lock_fn_flock_sh(int fd
, const char *fname
, int dupfd
)
415 if (flock(fd
, LOCK_SH
) < 0) {
422 err(EXIT_FAILURE
, "failed to lock");
426 static void lock_fn_flock_ex(int fd
, const char *fname
, int dupfd
)
428 if (flock(fd
, LOCK_EX
) < 0) {
435 err(EXIT_FAILURE
, "failed to lock");
439 static void lock_fn_posix_r_(int fd
, const char *fname
, int dupfd
)
443 .l_whence
= SEEK_SET
,
447 if (fcntl(fd
, F_SETLK
, &r
) < 0) {
454 err(EXIT_FAILURE
, "failed to lock");
458 static void lock_fn_posix__w(int fd
, const char *fname
, int dupfd
)
462 .l_whence
= SEEK_SET
,
466 if (fcntl(fd
, F_SETLK
, &w
) < 0) {
473 err(EXIT_FAILURE
, "failed to lock");
477 static void lock_fn_posix_rw(int fd
, const char *fname
, int dupfd
)
481 .l_whence
= SEEK_SET
,
487 .l_whence
= SEEK_SET
,
491 if (fcntl(fd
, F_SETLK
, &r
) < 0) {
498 err(EXIT_FAILURE
, "failed to lock(read)");
500 if (fcntl(fd
, F_SETLK
, &w
) < 0) {
507 err(EXIT_FAILURE
, "failed to lock(write)");
511 static void lock_fn_ofd_r_(int fd
, const char *fname
, int dupfd
)
515 .l_whence
= SEEK_SET
,
520 if (fcntl(fd
, F_OFD_SETLK
, &r
) < 0) {
527 err(EXIT_FAILURE
, "failed to lock");
531 static void lock_fn_ofd__w(int fd
, const char *fname
, int dupfd
)
535 .l_whence
= SEEK_SET
,
540 if (fcntl(fd
, F_OFD_SETLK
, &w
) < 0) {
547 err(EXIT_FAILURE
, "failed to lock");
551 static void lock_fn_ofd_rw(int fd
, const char *fname
, int dupfd
)
555 .l_whence
= SEEK_SET
,
562 .l_whence
= SEEK_SET
,
567 if (fcntl(fd
, F_OFD_SETLK
, &r
) < 0) {
574 err(EXIT_FAILURE
, "failed to lock(read)");
576 if (fcntl(fd
, F_OFD_SETLK
, &w
) < 0) {
583 err(EXIT_FAILURE
, "failed to lock(write)");
587 static void lock_fn_lease_w(int fd
, const char *fname
, int dupfd
)
589 if (fcntl(fd
, F_SETLEASE
, F_WRLCK
) < 0) {
596 err(EXIT_FAILURE
, "failed to take out a write lease");
601 static void *make_w_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
602 int argc
, char ** argv
)
606 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
607 char *fname
= xstrdup(ARG_STRING(file
));
609 struct arg
delete = decode_arg("delete", factory
->params
, argc
, argv
);
610 bool bDelete
= ARG_BOOLEAN(delete);
612 struct arg write_bytes
= decode_arg("write-bytes", factory
->params
, argc
, argv
);
613 int iWrite_bytes
= ARG_INTEGER(write_bytes
);
615 struct arg readable
= decode_arg("readable", factory
->params
, argc
, argv
);
616 bool bReadable
= ARG_BOOLEAN(readable
);
618 struct arg lock
= decode_arg("lock", factory
->params
, argc
, argv
);
619 const char *sLock
= ARG_STRING(lock
);
622 struct arg dupfd
= decode_arg("dupfd", factory
->params
, argc
, argv
);
623 int iDupfd
= ARG_INTEGER(dupfd
);
627 if (iWrite_bytes
< 0)
628 errx(EXIT_FAILURE
, "write-bytes must be a positive number or zero.");
630 if (strcmp(sLock
, "none") == 0)
631 lock_fn
= lock_fn_none
;
632 else if (strcmp(sLock
, "flock-sh") == 0)
633 lock_fn
= lock_fn_flock_sh
;
634 else if (strcmp(sLock
, "flock-ex") == 0)
635 lock_fn
= lock_fn_flock_ex
;
636 else if (strcmp(sLock
, "posix-r-") == 0) {
638 if (iWrite_bytes
< 1)
640 lock_fn
= lock_fn_posix_r_
;
641 } else if (strcmp(sLock
, "posix--w") == 0) {
642 if (iWrite_bytes
< 1)
644 lock_fn
= lock_fn_posix__w
;
645 } else if (strcmp(sLock
, "posix-rw") == 0) {
647 if (iWrite_bytes
< 3)
649 lock_fn
= lock_fn_posix_rw
;
650 } else if (strcmp(sLock
, "ofd-r-") == 0) {
652 if (iWrite_bytes
< 1)
654 lock_fn
= lock_fn_ofd_r_
;
655 } else if (strcmp(sLock
, "ofd--w") == 0) {
656 if (iWrite_bytes
< 1)
658 lock_fn
= lock_fn_ofd__w
;
659 } else if (strcmp(sLock
, "ofd-rw") == 0) {
661 if (iWrite_bytes
< 3)
663 lock_fn
= lock_fn_ofd_rw
;
664 } else if (strcmp(sLock
, "lease-w") == 0)
665 lock_fn
= lock_fn_lease_w
;
667 errx(EXIT_FAILURE
, "unexpected value for lock parameter: %s", sLock
);
672 free_arg(&write_bytes
);
676 fd
= open(fname
, O_CREAT
|O_EXCL
|(bReadable
? O_RDWR
: O_WRONLY
), S_IWUSR
);
678 err(EXIT_FAILURE
, "failed to make: %s", fname
);
680 if (fd
!= fdescs
[0].fd
) {
681 if (dup2(fd
, fdescs
[0].fd
) < 0) {
687 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
694 if (unlink(fname
) < 0) {
698 err(EXIT_FAILURE
, "failed to unlink %s", fname
);
704 for (int i
= 0; i
< iWrite_bytes
; i
++) {
705 if (write(fd
, "z", 1) != 1) {
711 err(EXIT_FAILURE
, "failed to write");
716 if (dup2(fd
, iDupfd
) < 0) {
722 err(EXIT_FAILURE
, "failed in dup2");
724 data
= xmalloc(sizeof (iDupfd
));
725 *((int *)data
) = iDupfd
;
728 lock_fn(fd
, fname
, iDupfd
);
730 fdescs
[0] = (struct fdesc
){
732 .close
= bDelete
? close_fdesc
: unlink_and_close_fdesc
,
739 static void free_after_closing_duplicated_fd(const struct factory
* factory _U_
, void *data
)
748 static void *make_pipe(const struct factory
*factory
, struct fdesc fdescs
[],
749 int argc
, char ** argv
)
752 int nonblock_flags
[2] = {0, 0};
753 struct arg nonblock
= decode_arg("nonblock", factory
->params
, argc
, argv
);
754 if (strlen(ARG_STRING(nonblock
)) != 2) {
755 errx(EXIT_FAILURE
, "string value for %s has unexpected length: %s",
756 "nonblock", ARG_STRING(nonblock
));
759 /* Make extra pipe descriptors for making pipe objects connected
760 * with fds more than 2.
761 * See https://github.com/util-linux/util-linux/pull/1622
762 * about the background of the requirement. */
763 struct arg rdup
= decode_arg("rdup", factory
->params
, argc
, argv
);
764 struct arg wdup
= decode_arg("wdup", factory
->params
, argc
, argv
);
766 xpd
[0] = ARG_INTEGER(rdup
);
767 xpd
[1] = ARG_INTEGER(wdup
);
769 for (int i
= 0; i
< 2; i
++) {
770 if (ARG_STRING(nonblock
)[i
] == '-')
772 if ((i
== 0 && ARG_STRING(nonblock
)[i
] == 'r')
773 || (i
== 1 && ARG_STRING(nonblock
)[i
] == 'w'))
774 nonblock_flags
[i
] = 1;
776 errx(EXIT_FAILURE
, "unexpected value %c for the %s fd of %s",
777 ARG_STRING(nonblock
)[i
],
778 (i
== 0)? "read": "write",
784 err(EXIT_FAILURE
, "failed to make pipe");
786 for (int i
= 0; i
< 2; i
++) {
787 if (nonblock_flags
[i
]) {
788 int flags
= fcntl(pd
[i
], F_GETFL
);
789 if (fcntl(pd
[i
], F_SETFL
, flags
|O_NONBLOCK
) < 0) {
794 errx(EXIT_FAILURE
, "failed to set NONBLOCK flag to the %s fd",
795 (i
== 0)? "read": "write");
800 for (int i
= 0; i
< 2; i
++) {
801 if (pd
[i
] != fdescs
[i
].fd
) {
802 if (dup2(pd
[i
], fdescs
[i
].fd
) < 0) {
807 err(EXIT_FAILURE
, "failed to dup %d -> %d",
808 pd
[i
], fdescs
[i
].fd
);
812 fdescs
[i
] = (struct fdesc
){
814 .close
= close_fdesc
,
819 /* Make extra pipe descriptors. */
820 for (int i
= 0; i
< 2; i
++) {
822 if (dup2(fdescs
[i
].fd
, xpd
[i
]) < 0) {
826 if (i
> 0 && xpd
[0] >= 0)
829 err(EXIT_FAILURE
, "failed to dup %d -> %d",
830 fdescs
[i
].fd
, xpd
[i
]);
832 fdescs
[i
+ 2] = (struct fdesc
){
834 .close
= close_fdesc
,
843 static void close_dir(int fd
, void *data
)
849 close_fdesc(fd
, NULL
);
852 static void *open_directory(const struct factory
*factory
, struct fdesc fdescs
[],
853 int argc
, char ** argv
)
855 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
856 struct arg dentries
= decode_arg("dentries", factory
->params
, argc
, argv
);
859 int fd
= open(ARG_STRING(dir
), O_RDONLY
|O_DIRECTORY
);
861 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(dir
));
864 if (fd
!= fdescs
[0].fd
) {
865 if (dup2(fd
, fdescs
[0].fd
) < 0) {
869 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
874 if (ARG_INTEGER(dentries
) > 0) {
875 dp
= fdopendir(fdescs
[0].fd
);
880 err(EXIT_FAILURE
, "failed to make DIR* from fd: %s", ARG_STRING(dir
));
882 for (int i
= 0; i
< ARG_INTEGER(dentries
); i
++) {
883 struct dirent
*d
= readdir(dp
);
888 err(EXIT_FAILURE
, "failed in readdir(3)");
894 fdescs
[0] = (struct fdesc
){
903 static void *open_rw_chrdev(const struct factory
*factory
, struct fdesc fdescs
[],
904 int argc
, char ** argv
)
906 struct arg chrdev
= decode_arg("chrdev", factory
->params
, argc
, argv
);
907 int fd
= open(ARG_STRING(chrdev
), O_RDWR
);
909 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(chrdev
));
912 if (fd
!= fdescs
[0].fd
) {
913 if (dup2(fd
, fdescs
[0].fd
) < 0) {
917 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
922 fdescs
[0] = (struct fdesc
){
924 .close
= close_fdesc
,
931 static void *make_socketpair(const struct factory
*factory
, struct fdesc fdescs
[],
932 int argc
, char ** argv
)
935 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
937 struct arg halfclose
= decode_arg("halfclose", factory
->params
, argc
, argv
);
940 bhalfclose
= ARG_BOOLEAN(halfclose
);
941 free_arg(&halfclose
);
943 if (strcmp(ARG_STRING(socktype
), "STREAM") == 0)
944 isocktype
= SOCK_STREAM
;
945 else if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
946 isocktype
= SOCK_DGRAM
;
947 else if (strcmp(ARG_STRING(socktype
), "SEQPACKET") == 0)
948 isocktype
= SOCK_SEQPACKET
;
951 "unknown socket type for socketpair(AF_UNIX,...): %s",
952 ARG_STRING(socktype
));
955 if (socketpair(AF_UNIX
, isocktype
, 0, sd
) < 0)
956 err(EXIT_FAILURE
, "failed to make socket pair");
959 if (shutdown(sd
[0], SHUT_RD
) < 0)
961 "failed to shutdown the read end of the 1st socket");
962 if (shutdown(sd
[1], SHUT_WR
) < 0)
964 "failed to shutdown the write end of the 2nd socket");
967 for (int i
= 0; i
< 2; i
++) {
968 if (sd
[i
] != fdescs
[i
].fd
) {
969 if (dup2(sd
[i
], fdescs
[i
].fd
) < 0) {
974 err(EXIT_FAILURE
, "failed to dup %d -> %d",
975 sd
[i
], fdescs
[i
].fd
);
979 fdescs
[i
] = (struct fdesc
){
981 .close
= close_fdesc
,
989 static void *open_with_opath(const struct factory
*factory
, struct fdesc fdescs
[],
990 int argc
, char ** argv
)
992 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
993 int fd
= open(ARG_STRING(path
), O_PATH
|O_NOFOLLOW
);
995 err(EXIT_FAILURE
, "failed to open with O_PATH: %s", ARG_STRING(path
));
998 if (fd
!= fdescs
[0].fd
) {
999 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1003 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1008 fdescs
[0] = (struct fdesc
){
1010 .close
= close_fdesc
,
1017 static void *open_ro_blkdev(const struct factory
*factory
, struct fdesc fdescs
[],
1018 int argc
, char ** argv
)
1020 struct arg blkdev
= decode_arg("blkdev", factory
->params
, argc
, argv
);
1021 int fd
= open(ARG_STRING(blkdev
), O_RDONLY
);
1023 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(blkdev
));
1026 if (fd
!= fdescs
[0].fd
) {
1027 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1031 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1036 fdescs
[0] = (struct fdesc
){
1038 .close
= close_fdesc
,
1045 static int make_packet_socket(int socktype
, const char *interface
)
1048 struct sockaddr_ll addr
;
1050 sd
= socket(AF_PACKET
, socktype
, htons(ETH_P_ALL
));
1052 err(EXIT_FAILURE
, "failed to make a socket with AF_PACKET");
1054 if (interface
== NULL
)
1055 return sd
; /* Just making a socket */
1057 memset(&addr
, 0, sizeof(struct sockaddr_ll
));
1058 addr
.sll_family
= AF_PACKET
;
1059 addr
.sll_ifindex
= if_nametoindex(interface
);
1060 if (addr
.sll_ifindex
== 0) {
1065 "failed to get the interface index for %s", interface
);
1067 if (bind(sd
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_ll
)) < 0) {
1072 "failed to get the interface index for %s", interface
);
1078 struct munmap_data
{
1083 static void close_fdesc_after_munmap(int fd
, void *data
)
1085 struct munmap_data
*munmap_data
= data
;
1086 munmap(munmap_data
->ptr
, munmap_data
->len
);
1091 static void *make_mmapped_packet_socket(const struct factory
*factory
, struct fdesc fdescs
[],
1092 int argc
, char ** argv
)
1095 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
1096 struct arg interface
= decode_arg("interface", factory
->params
, argc
, argv
);
1099 const char *sinterface
;
1100 struct tpacket_req req
;
1101 struct munmap_data
*munmap_data
;
1103 if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
1104 isocktype
= SOCK_DGRAM
;
1105 else if (strcmp(ARG_STRING(socktype
), "RAW") == 0)
1106 isocktype
= SOCK_RAW
;
1109 "unknown socket type for socket(AF_PACKET,...): %s",
1110 ARG_STRING(socktype
));
1111 free_arg(&socktype
);
1113 sinterface
= ARG_STRING(interface
);
1114 sd
= make_packet_socket(isocktype
, sinterface
);
1115 free_arg(&interface
);
1117 /* Specify the spec of ring buffers.
1120 * - linux/Documentation/networking/packet_mmap.rst
1121 * - https://sites.google.com/site/packetmmap/home
1123 req
.tp_block_size
= getpagesize();
1124 req
.tp_frame_size
= getpagesize();
1125 req
.tp_block_nr
= 1;
1126 req
.tp_frame_nr
= 1;
1127 if (setsockopt(sd
, SOL_PACKET
, PACKET_TX_RING
, (char *)&req
, sizeof(req
)) < 0) {
1131 err((errno
== ENOPROTOOPT
? EXIT_ENOPROTOOPT
: EXIT_FAILURE
),
1132 "failed to specify a buffer spec to a packet socket");
1135 munmap_data
= xmalloc(sizeof (*munmap_data
));
1136 munmap_data
->len
= (size_t) req
.tp_block_size
* req
.tp_block_nr
;
1137 munmap_data
->ptr
= mmap(NULL
, munmap_data
->len
, PROT_WRITE
, MAP_SHARED
, sd
, 0);
1138 if (munmap_data
->ptr
== MAP_FAILED
) {
1143 err(EXIT_FAILURE
, "failed to do mmap a packet socket");
1146 if (sd
!= fdescs
[0].fd
) {
1147 if (dup2(sd
, fdescs
[0].fd
) < 0) {
1150 munmap(munmap_data
->ptr
, munmap_data
->len
);
1153 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
1158 fdescs
[0] = (struct fdesc
){
1160 .close
= close_fdesc_after_munmap
,
1161 .data
= munmap_data
,
1167 static void *make_pidfd(const struct factory
*factory
, struct fdesc fdescs
[],
1168 int argc
, char ** argv
)
1170 struct arg target_pid
= decode_arg("target-pid", factory
->params
, argc
, argv
);
1171 pid_t pid
= ARG_INTEGER(target_pid
);
1173 int fd
= pidfd_open(pid
, 0);
1175 err_nosys(EXIT_FAILURE
, "failed in pidfd_open(%d)", (int)pid
);
1176 free_arg(&target_pid
);
1178 if (fd
!= fdescs
[0].fd
) {
1179 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1183 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1188 fdescs
[0] = (struct fdesc
){
1190 .close
= close_fdesc
,
1197 static void *make_inotify_fd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
1198 int argc _U_
, char ** argv _U_
)
1200 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
1201 const char *sdir
= ARG_STRING(dir
);
1202 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
1203 const char *sfile
= ARG_STRING(file
);
1205 int fd
= inotify_init();
1207 err(EXIT_FAILURE
, "failed in inotify_init()");
1209 if (inotify_add_watch(fd
, sdir
, IN_DELETE
) < 0) {
1213 err(EXIT_FAILURE
, "failed in inotify_add_watch(\"%s\")", sdir
);
1217 if (inotify_add_watch(fd
, sfile
, IN_DELETE
) < 0) {
1221 err(EXIT_FAILURE
, "failed in inotify_add_watch(\"%s\")", sfile
);
1225 if (fd
!= fdescs
[0].fd
) {
1226 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1230 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1235 fdescs
[0] = (struct fdesc
){
1237 .close
= close_fdesc
,
1244 static void close_unix_socket(int fd
, void *data
)
1254 static void *make_unix_stream_core(const struct factory
*factory
, struct fdesc fdescs
[],
1255 int argc
, char ** argv
, int type
, const char *typestr
)
1257 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1258 const char *spath
= ARG_STRING(path
);
1260 struct arg backlog
= decode_arg("backlog", factory
->params
, argc
, argv
);
1261 int ibacklog
= ARG_INTEGER(path
);
1263 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1264 bool babstract
= ARG_BOOLEAN(abstract
);
1266 struct arg server_shutdown
= decode_arg("server-shutdown", factory
->params
, argc
, argv
);
1267 int iserver_shutdown
= ARG_INTEGER(server_shutdown
);
1268 struct arg client_shutdown
= decode_arg("client-shutdown", factory
->params
, argc
, argv
);
1269 int iclient_shutdown
= ARG_INTEGER(client_shutdown
);
1271 int ssd
, csd
, asd
; /* server, client, and accepted socket descriptors */
1272 struct sockaddr_un un
;
1273 size_t un_len
= sizeof(un
);
1275 memset(&un
, 0, sizeof(un
));
1276 un
.sun_family
= AF_UNIX
;
1278 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1279 size_t pathlen
= strlen(spath
);
1280 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1281 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1283 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1285 free_arg(&client_shutdown
);
1286 free_arg(&server_shutdown
);
1287 free_arg(&abstract
);
1291 if (iserver_shutdown
< 0 || iserver_shutdown
> 3)
1292 errx(EXIT_FAILURE
, "the server shudown specification in unexpected range");
1293 if (iclient_shutdown
< 0 || iclient_shutdown
> 3)
1294 errx(EXIT_FAILURE
, "the client shudown specification in unexpected range");
1296 ssd
= socket(AF_UNIX
, type
, 0);
1299 "failed to make a socket with AF_UNIX + SOCK_%s (server side)", typestr
);
1300 if (ssd
!= fdescs
[0].fd
) {
1301 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1305 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1311 fdescs
[0] = (struct fdesc
){
1313 .close
= close_unix_socket
,
1318 unlink(un
.sun_path
);
1319 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1323 err(EXIT_FAILURE
, "failed to bind a socket for listening");
1327 fdescs
[0].data
= xstrdup(un
.sun_path
);
1328 if (listen(ssd
, ibacklog
) < 0) {
1330 close_unix_socket(ssd
, fdescs
[0].data
);
1332 err(EXIT_FAILURE
, "failed to listen a socket");
1335 csd
= socket(AF_UNIX
, type
, 0);
1338 "failed to make a socket with AF_UNIX + SOCK_%s (client side)", typestr
);
1339 if (csd
!= fdescs
[1].fd
) {
1340 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1343 close_unix_socket(ssd
, fdescs
[0].data
);
1345 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1351 fdescs
[1] = (struct fdesc
){
1353 .close
= close_fdesc
,
1357 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1359 close_fdesc(csd
, NULL
);
1360 close_unix_socket(ssd
, fdescs
[0].data
);
1362 err(EXIT_FAILURE
, "failed to connect a socket to the listening socket");
1366 unlink(un
.sun_path
);
1368 asd
= accept(ssd
, NULL
, NULL
);
1371 close_fdesc(csd
, NULL
);
1372 close_unix_socket(ssd
, fdescs
[0].data
);
1374 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1376 if (asd
!= fdescs
[2].fd
) {
1377 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1380 close_fdesc(csd
, NULL
);
1381 close_unix_socket(ssd
, fdescs
[0].data
);
1383 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1389 if (iserver_shutdown
& (1 << 0))
1390 shutdown(asd
, SHUT_RD
);
1391 if (iserver_shutdown
& (1 << 1))
1392 shutdown(asd
, SHUT_WR
);
1393 if (iclient_shutdown
& (1 << 0))
1394 shutdown(csd
, SHUT_RD
);
1395 if (iclient_shutdown
& (1 << 1))
1396 shutdown(csd
, SHUT_WR
);
1401 static void *make_unix_stream(const struct factory
*factory
, struct fdesc fdescs
[],
1402 int argc
, char ** argv
)
1404 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1405 const char *stype
= ARG_STRING(type
);
1408 const char *typestr
;
1410 if (strcmp(stype
, "stream") == 0) {
1411 typesym
= SOCK_STREAM
;
1413 } else if (strcmp(stype
, "seqpacket") == 0) {
1414 typesym
= SOCK_SEQPACKET
;
1415 typestr
= "SEQPACKET";
1417 errx(EXIT_FAILURE
, "unknown unix socket type: %s", stype
);
1421 return make_unix_stream_core(factory
, fdescs
, argc
, argv
, typesym
, typestr
);
1424 static void *make_unix_dgram(const struct factory
*factory
, struct fdesc fdescs
[],
1425 int argc
, char ** argv
)
1427 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1428 const char *spath
= ARG_STRING(path
);
1430 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1431 bool babstract
= ARG_BOOLEAN(abstract
);
1433 int ssd
, csd
; /* server and client socket descriptors */
1435 struct sockaddr_un un
;
1436 size_t un_len
= sizeof(un
);
1438 memset(&un
, 0, sizeof(un
));
1439 un
.sun_family
= AF_UNIX
;
1441 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1442 size_t pathlen
= strlen(spath
);
1443 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1444 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1446 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1448 free_arg(&abstract
);
1451 ssd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1454 "failed to make a socket with AF_UNIX + SOCK_DGRAM (server side)");
1455 if (ssd
!= fdescs
[0].fd
) {
1456 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1460 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1466 fdescs
[0] = (struct fdesc
){
1468 .close
= close_unix_socket
,
1473 unlink(un
.sun_path
);
1474 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1478 err(EXIT_FAILURE
, "failed to bind a socket for server");
1482 fdescs
[0].data
= xstrdup(un
.sun_path
);
1483 csd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1486 "failed to make a socket with AF_UNIX + SOCK_DGRAM (client side)");
1487 if (csd
!= fdescs
[1].fd
) {
1488 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1491 close_unix_socket(ssd
, fdescs
[0].data
);
1493 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1499 fdescs
[1] = (struct fdesc
){
1501 .close
= close_fdesc
,
1505 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1507 close_fdesc(csd
, NULL
);
1508 close_unix_socket(ssd
, fdescs
[0].data
);
1510 err(EXIT_FAILURE
, "failed to connect a socket to the server socket");
1514 unlink(un
.sun_path
);
1519 static void *make_unix_in_new_netns(const struct factory
*factory
, struct fdesc fdescs
[],
1520 int argc
, char ** argv
)
1522 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1523 const char *stype
= ARG_STRING(type
);
1525 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1526 const char *spath
= ARG_STRING(path
);
1528 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1529 bool babstract
= ARG_BOOLEAN(abstract
);
1532 const char *typestr
;
1534 struct sockaddr_un un
;
1535 size_t un_len
= sizeof(un
);
1537 int self_netns
, tmp_netns
, sd
;
1539 if (strcmp(stype
, "stream") == 0) {
1540 typesym
= SOCK_STREAM
;
1542 } else if (strcmp(stype
, "seqpacket") == 0) {
1543 typesym
= SOCK_SEQPACKET
;
1544 typestr
= "SEQPACKET";
1545 } else if (strcmp(stype
, "dgram") == 0) {
1546 typesym
= SOCK_DGRAM
;
1549 free_arg(&abstract
);
1552 errx(EXIT_FAILURE
, "unknown unix socket type: %s", stype
);
1555 memset(&un
, 0, sizeof(un
));
1556 un
.sun_family
= AF_UNIX
;
1558 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1559 size_t pathlen
= strlen(spath
);
1560 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1561 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1563 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1565 free_arg(&abstract
);
1569 self_netns
= open("/proc/self/ns/net", O_RDONLY
);
1571 err(EXIT_FAILURE
, "failed to open /proc/self/ns/net");
1572 if (self_netns
!= fdescs
[0].fd
) {
1573 if (dup2(self_netns
, fdescs
[0].fd
) < 0) {
1577 err(EXIT_FAILURE
, "failed to dup %d -> %d", self_netns
, fdescs
[0].fd
);
1580 self_netns
= fdescs
[0].fd
;
1583 fdescs
[0] = (struct fdesc
){
1585 .close
= close_fdesc
,
1589 if (unshare(CLONE_NEWNET
) < 0) {
1591 close_fdesc(self_netns
, NULL
);
1593 err((errno
== EPERM
? EXIT_EPERM
: EXIT_FAILURE
),
1594 "failed in unshare");
1597 tmp_netns
= open("/proc/self/ns/net", O_RDONLY
);
1598 if (tmp_netns
< 0) {
1600 close_fdesc(self_netns
, NULL
);
1602 err(EXIT_FAILURE
, "failed to open /proc/self/ns/net for the new netns");
1604 if (tmp_netns
!= fdescs
[1].fd
) {
1605 if (dup2(tmp_netns
, fdescs
[1].fd
) < 0) {
1607 close_fdesc(self_netns
, NULL
);
1610 err(EXIT_FAILURE
, "failed to dup %d -> %d", tmp_netns
, fdescs
[1].fd
);
1613 tmp_netns
= fdescs
[1].fd
;
1616 fdescs
[1] = (struct fdesc
){
1618 .close
= close_fdesc
,
1622 sd
= socket(AF_UNIX
, typesym
, 0);
1625 close_fdesc(self_netns
, NULL
);
1626 close_fdesc(tmp_netns
, NULL
);
1629 "failed to make a socket with AF_UNIX + SOCK_%s",
1633 if (sd
!= fdescs
[2].fd
) {
1634 if (dup2(sd
, fdescs
[2].fd
) < 0) {
1636 close_fdesc(self_netns
, NULL
);
1637 close_fdesc(tmp_netns
, NULL
);
1640 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[2].fd
);
1646 fdescs
[2] = (struct fdesc
){
1648 .close
= close_unix_socket
,
1653 unlink(un
.sun_path
);
1654 if (bind(sd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1656 close_fdesc(self_netns
, NULL
);
1657 close_fdesc(tmp_netns
, NULL
);
1658 close_unix_socket(sd
, NULL
);
1660 err(EXIT_FAILURE
, "failed to bind a socket");
1664 fdescs
[2].data
= xstrdup(un
.sun_path
);
1666 if (typesym
!= SOCK_DGRAM
) {
1667 if (listen(sd
, 1) < 0) {
1669 close_fdesc(self_netns
, NULL
);
1670 close_fdesc(tmp_netns
, NULL
);
1671 close_unix_socket(sd
, fdescs
[2].data
);
1673 err(EXIT_FAILURE
, "failed to listen a socket");
1677 if (setns(self_netns
, CLONE_NEWNET
) < 0) {
1679 close_fdesc(self_netns
, NULL
);
1680 close_fdesc(tmp_netns
, NULL
);
1681 close_unix_socket(sd
, fdescs
[2].data
);
1683 err(EXIT_FAILURE
, "failed to swich back to the original net namespace");
1689 static void *make_tcp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1690 int argc
, char ** argv
,
1692 void (*init_addr
)(struct sockaddr
*, unsigned short),
1694 struct sockaddr
* sin
, struct sockaddr
* cin
)
1696 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1697 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1698 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1699 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1705 free_arg(&server_port
);
1706 free_arg(&client_port
);
1708 ssd
= socket(family
, SOCK_STREAM
, 0);
1711 "failed to make a tcp socket for listening");
1713 if (setsockopt(ssd
, SOL_SOCKET
,
1714 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1718 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1721 if (ssd
!= fdescs
[0].fd
) {
1722 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1726 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1732 init_addr(sin
, iserver_port
);
1733 if (bind(ssd
, sin
, addr_size
) < 0) {
1737 err(EXIT_FAILURE
, "failed to bind a listening socket");
1740 if (listen(ssd
, 1) < 0) {
1744 err(EXIT_FAILURE
, "failed to listen a socket");
1747 csd
= socket(family
, SOCK_STREAM
, 0);
1753 "failed to make a tcp client socket");
1756 if (setsockopt(csd
, SOL_SOCKET
,
1757 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1762 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1765 if (csd
!= fdescs
[1].fd
) {
1766 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1771 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1777 init_addr(cin
, iclient_port
);
1778 if (bind(csd
, cin
, addr_size
) < 0) {
1783 err(EXIT_FAILURE
, "failed to bind a client socket");
1786 if (connect(csd
, sin
, addr_size
) < 0) {
1791 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1794 asd
= accept(ssd
, NULL
, NULL
);
1800 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1802 if (asd
!= fdescs
[2].fd
) {
1803 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1808 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1814 fdescs
[0] = (struct fdesc
) {
1816 .close
= close_fdesc
,
1819 fdescs
[1] = (struct fdesc
) {
1821 .close
= close_fdesc
,
1824 fdescs
[2] = (struct fdesc
) {
1826 .close
= close_fdesc
,
1833 static void tcp_init_addr(struct sockaddr
*addr
, unsigned short port
)
1835 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
1836 memset(in
, 0, sizeof(*in
));
1837 in
->sin_family
= AF_INET
;
1838 in
->sin_port
= htons(port
);
1839 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1842 static void *make_tcp(const struct factory
*factory
, struct fdesc fdescs
[],
1843 int argc
, char ** argv
)
1845 struct sockaddr_in sin
, cin
;
1846 return make_tcp_common(factory
, fdescs
, argc
, argv
,
1848 tcp_init_addr
, sizeof(sin
),
1849 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1852 static void *make_udp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1853 int argc
, char ** argv
,
1855 void (*init_addr
)(struct sockaddr
*, unsigned short),
1857 struct sockaddr
* sin
, struct sockaddr
* cin
)
1859 struct arg lite
= decode_arg("lite", factory
->params
, argc
, argv
);
1860 bool blite
= ARG_BOOLEAN(lite
);
1862 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1863 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1864 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1865 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1867 struct arg server_do_bind
= decode_arg("server-do-bind", factory
->params
, argc
, argv
);
1868 bool bserver_do_bind
= ARG_BOOLEAN(server_do_bind
);
1869 struct arg client_do_bind
= decode_arg("client-do-bind", factory
->params
, argc
, argv
);
1870 bool bclient_do_bind
= ARG_BOOLEAN(client_do_bind
);
1871 struct arg client_do_connect
= decode_arg("client-do-connect", factory
->params
, argc
, argv
);
1872 bool bclient_do_connect
= ARG_BOOLEAN(client_do_connect
);
1878 free_arg(&client_do_connect
);
1879 free_arg(&client_do_bind
);
1880 free_arg(&server_do_bind
);
1881 free_arg(&server_port
);
1882 free_arg(&client_port
);
1885 ssd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1888 "failed to make a udp socket for server");
1890 if (setsockopt(ssd
, SOL_SOCKET
,
1891 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1895 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1898 if (ssd
!= fdescs
[0].fd
) {
1899 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1903 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1909 init_addr(sin
, iserver_port
);
1910 if (bserver_do_bind
) {
1911 if (bind(ssd
, sin
, addr_size
) < 0) {
1915 err(EXIT_FAILURE
, "failed to bind a server socket");
1919 csd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1925 "failed to make a udp client socket");
1928 if (setsockopt(csd
, SOL_SOCKET
,
1929 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1934 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1937 if (csd
!= fdescs
[1].fd
) {
1938 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1943 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1949 if (bclient_do_bind
) {
1950 init_addr(cin
, iclient_port
);
1951 if (bind(csd
, cin
, addr_size
) < 0) {
1956 err(EXIT_FAILURE
, "failed to bind a client socket");
1960 if (bclient_do_connect
) {
1961 if (connect(csd
, sin
, addr_size
) < 0) {
1966 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1970 fdescs
[0] = (struct fdesc
) {
1972 .close
= close_fdesc
,
1975 fdescs
[1] = (struct fdesc
) {
1977 .close
= close_fdesc
,
1984 static void *make_udp(const struct factory
*factory
, struct fdesc fdescs
[],
1985 int argc
, char ** argv
)
1987 struct sockaddr_in sin
, cin
;
1988 return make_udp_common(factory
, fdescs
, argc
, argv
,
1990 tcp_init_addr
, sizeof(sin
),
1991 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1994 static void *make_raw_common(const struct factory
*factory
, struct fdesc fdescs
[],
1995 int argc
, char ** argv
,
1997 void (*init_addr
)(struct sockaddr
*, bool),
1999 struct sockaddr
* sin
)
2001 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
2002 int iprotocol
= ARG_INTEGER(protocol
);
2005 free_arg(&protocol
);
2007 ssd
= socket(family
, SOCK_RAW
, iprotocol
);
2010 "failed to make a udp socket for server");
2012 if (ssd
!= fdescs
[0].fd
) {
2013 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
2017 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
2023 init_addr(sin
, false);
2024 if (bind(ssd
, sin
, addr_size
) < 0) {
2028 err(EXIT_FAILURE
, "failed in bind(2)");
2031 init_addr(sin
, true);
2032 if (connect(ssd
, sin
, addr_size
) < 0) {
2036 err(EXIT_FAILURE
, "failed in connect(2)");
2039 fdescs
[0] = (struct fdesc
) {
2041 .close
= close_fdesc
,
2048 static void raw_init_addr(struct sockaddr
* addr
, bool remote_addr
)
2050 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
2051 memset(in
, 0, sizeof(*in
));
2052 in
->sin_family
= AF_INET
;
2053 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
+ (remote_addr
? 1: 0));
2056 static void *make_raw(const struct factory
*factory
, struct fdesc fdescs
[],
2057 int argc
, char ** argv
)
2059 struct sockaddr_in sin
;
2060 return make_raw_common(factory
, fdescs
, argc
, argv
,
2062 raw_init_addr
, sizeof(sin
),
2063 (struct sockaddr
*)&sin
);
2066 static void *make_ping_common(const struct factory
*factory
, struct fdesc fdescs
[],
2067 int argc
, char ** argv
,
2068 int family
, int protocol
,
2069 void (*init_addr
)(struct sockaddr
*, unsigned short),
2071 struct sockaddr
*sin
)
2073 struct arg connect_
= decode_arg("connect", factory
->params
, argc
, argv
);
2074 bool bconnect
= ARG_BOOLEAN(connect_
);
2076 struct arg bind_
= decode_arg("bind", factory
->params
, argc
, argv
);
2077 bool bbind
= ARG_BOOLEAN(bind_
);
2079 struct arg id
= decode_arg("id", factory
->params
, argc
, argv
);
2080 unsigned short iid
= (unsigned short)ARG_INTEGER(id
);
2086 free_arg(&connect_
);
2088 sd
= socket(family
, SOCK_DGRAM
, protocol
);
2090 err((errno
== EACCES
? EXIT_EACCESS
: EXIT_FAILURE
),
2091 "failed to make an icmp socket");
2093 if (sd
!= fdescs
[0].fd
) {
2094 if (dup2(sd
, fdescs
[0].fd
) < 0) {
2098 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
2105 init_addr(sin
, iid
);
2106 if (bind(sd
, sin
, addr_size
) < 0) {
2110 err((errno
== EACCES
? EXIT_EACCESS
: EXIT_FAILURE
),
2111 "failed in bind(2)");
2117 if (connect(sd
, sin
, addr_size
) < 0) {
2121 err(EXIT_FAILURE
, "failed in connect(2)");
2125 fdescs
[0] = (struct fdesc
) {
2127 .close
= close_fdesc
,
2134 static void ping_init_addr(struct sockaddr
*addr
, unsigned short id
)
2136 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
2137 memset(in
, 0, sizeof(*in
));
2138 in
->sin_family
= AF_INET
;
2139 in
->sin_port
= htons(id
);
2140 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2143 static void *make_ping(const struct factory
*factory
, struct fdesc fdescs
[],
2144 int argc
, char ** argv
)
2146 struct sockaddr_in in
;
2147 return make_ping_common(factory
, fdescs
, argc
, argv
,
2148 AF_INET
, IPPROTO_ICMP
,
2151 (struct sockaddr
*)&in
);
2154 static void tcp6_init_addr(struct sockaddr
*addr
, unsigned short port
)
2156 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2157 memset(in6
, 0, sizeof(*in6
));
2158 in6
->sin6_family
= AF_INET6
;
2159 in6
->sin6_flowinfo
= 0;
2160 in6
->sin6_port
= htons(port
);
2161 in6
->sin6_addr
= in6addr_loopback
;
2164 static void *make_tcp6(const struct factory
*factory
, struct fdesc fdescs
[],
2165 int argc
, char ** argv
)
2167 struct sockaddr_in6 sin
, cin
;
2168 return make_tcp_common(factory
, fdescs
, argc
, argv
,
2170 tcp6_init_addr
, sizeof(sin
),
2171 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2174 static void *make_udp6(const struct factory
*factory
, struct fdesc fdescs
[],
2175 int argc
, char ** argv
)
2177 struct sockaddr_in6 sin
, cin
;
2178 return make_udp_common(factory
, fdescs
, argc
, argv
,
2180 tcp6_init_addr
, sizeof(sin
),
2181 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2184 static void raw6_init_addr(struct sockaddr
*addr
, bool remote_addr
)
2186 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2187 memset(in6
, 0, sizeof(*in6
));
2188 in6
->sin6_family
= AF_INET6
;
2189 in6
->sin6_flowinfo
= 0;
2192 /* ::ffff:127.0.0.1 */
2193 in6
->sin6_addr
.s6_addr16
[5] = 0xffff;
2194 in6
->sin6_addr
.s6_addr32
[3] = htonl(INADDR_LOOPBACK
);
2196 in6
->sin6_addr
= in6addr_loopback
;
2199 static void *make_raw6(const struct factory
*factory
, struct fdesc fdescs
[],
2200 int argc
, char ** argv
)
2202 struct sockaddr_in6 sin
;
2203 return make_raw_common(factory
, fdescs
, argc
, argv
,
2205 raw6_init_addr
, sizeof(sin
),
2206 (struct sockaddr
*)&sin
);
2209 static void ping6_init_addr(struct sockaddr
*addr
, unsigned short id
)
2211 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2212 memset(in6
, 0, sizeof(*in6
));
2213 in6
->sin6_family
= AF_INET6
;
2214 in6
->sin6_port
= htons(id
);
2215 in6
->sin6_addr
= in6addr_loopback
;
2218 static void *make_ping6(const struct factory
*factory
, struct fdesc fdescs
[],
2219 int argc
, char ** argv
)
2221 struct sockaddr_in6 in6
;
2222 return make_ping_common(factory
, fdescs
, argc
, argv
,
2223 AF_INET6
, IPPROTO_ICMPV6
,
2226 (struct sockaddr
*)&in6
);
2230 static void *make_netns(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2231 int argc _U_
, char ** argv _U_
)
2233 int sd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
2235 err(EXIT_FAILURE
, "failed in socket()");
2237 int ns
= ioctl(sd
, SIOCGSKNS
);
2239 err_nosys(EXIT_FAILURE
, "failed in ioctl(SIOCGSKNS)");
2242 if (ns
!= fdescs
[0].fd
) {
2243 if (dup2(ns
, fdescs
[0].fd
) < 0) {
2247 err(EXIT_FAILURE
, "failed to dup %d -> %d", ns
, fdescs
[0].fd
);
2252 fdescs
[0] = (struct fdesc
){
2254 .close
= close_fdesc
,
2260 #endif /* SIOCGSKNS */
2262 static void *make_netlink(const struct factory
*factory
, struct fdesc fdescs
[],
2263 int argc
, char ** argv
)
2265 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
2266 int iprotocol
= ARG_INTEGER(protocol
);
2267 struct arg groups
= decode_arg("groups", factory
->params
, argc
, argv
);
2268 unsigned int ugroups
= ARG_UINTEGER(groups
);
2271 free_arg(&protocol
);
2273 sd
= socket(AF_NETLINK
, SOCK_RAW
, iprotocol
);
2275 err((errno
== EPROTONOSUPPORT
)? EXIT_EPROTONOSUPPORT
: EXIT_FAILURE
,
2276 "failed in socket()");
2278 if (sd
!= fdescs
[0].fd
) {
2279 if (dup2(sd
, fdescs
[0].fd
) < 0) {
2283 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
2288 struct sockaddr_nl nl
;
2289 memset(&nl
, 0, sizeof(nl
));
2290 nl
.nl_family
= AF_NETLINK
;
2291 nl
.nl_groups
= ugroups
;
2292 if (bind(sd
, (struct sockaddr
*)&nl
, sizeof(nl
)) < 0) {
2296 err(EXIT_FAILURE
, "failed in bind(2)");
2299 fdescs
[0] = (struct fdesc
){
2301 .close
= close_fdesc
,
2308 static void *make_eventfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2309 int argc _U_
, char ** argv _U_
)
2312 pid_t
*pid
= xcalloc(1, sizeof(*pid
));
2314 if (fdescs
[0].fd
== fdescs
[1].fd
)
2315 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2319 err(EXIT_FAILURE
, "failed in eventfd(2)");
2321 if (fd
!= fdescs
[0].fd
) {
2322 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2326 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2331 fdescs
[0] = (struct fdesc
){
2333 .close
= close_fdesc
,
2337 if (dup2(fdescs
[0].fd
, fdescs
[1].fd
) < 0) {
2339 close(fdescs
[0].fd
);
2341 err(EXIT_FAILURE
, "failed to dup %d -> %d", fdescs
[0].fd
, fdescs
[1].fd
);
2344 signal(SIGCHLD
, abort_with_child_death_message
);
2348 close(fdescs
[0].fd
);
2349 close(fdescs
[1].fd
);
2351 err(EXIT_FAILURE
, "failed in fork()");
2352 } else if (*pid
== 0) {
2356 close(fdescs
[0].fd
);
2358 signal(SIGCONT
, do_nothing
);
2359 /* Notify the parent that I'm ready. */
2360 if (write(fdescs
[1].fd
, &v
, sizeof(v
)) != sizeof(v
)) {
2361 close(fdescs
[1].fd
);
2363 "failed in write() to notify the readiness to the prent");
2365 /* Wait till the parent lets me go. */
2368 close(fdescs
[1].fd
);
2373 /* The child owns fdescs[1]. */
2374 close(fdescs
[1].fd
);
2377 /* Wait till the child is ready. */
2378 if (read(fdescs
[0].fd
, &v
, sizeof(uint64_t)) != sizeof(v
)) {
2380 close(fdescs
[0].fd
);
2382 "failed in read() the readiness notification from the child");
2384 signal(SIGCHLD
, SIG_DFL
);
2390 static void report_eventfd(const struct factory
*factory _U_
,
2391 int nth
, void *data
, FILE *fp
)
2394 pid_t
*child
= data
;
2395 fprintf(fp
, "%d", *child
);
2399 static void free_eventfd(const struct factory
* factory _U_
, void *data
)
2401 pid_t child
= *(pid_t
*)data
;
2406 kill(child
, SIGCONT
);
2407 if (waitpid(child
, &wstatus
, 0) < 0)
2408 err(EXIT_FAILURE
, "failed in waitpid()");
2410 if (WIFEXITED(wstatus
)) {
2411 int s
= WEXITSTATUS(wstatus
);
2413 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2414 } else if (WIFSIGNALED(wstatus
)) {
2415 int s
= WTERMSIG(wstatus
);
2416 if (WTERMSIG(wstatus
) != 0)
2417 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2421 struct mqueue_data
{
2427 static void mqueue_data_free(struct mqueue_data
*data
)
2430 mq_unlink(data
->path
);
2431 free((void *)data
->path
);
2435 static void report_mqueue(const struct factory
*factory _U_
,
2436 int nth
, void *data
, FILE *fp
)
2439 fprintf(fp
, "%d", ((struct mqueue_data
*)data
)->pid
);
2443 static void close_mqueue(int fd
, void *data _U_
)
2448 static void free_mqueue(const struct factory
* factory _U_
, void *data
)
2450 struct mqueue_data
*mqueue_data
= data
;
2451 pid_t child
= mqueue_data
->pid
;
2454 mqueue_data_free(mqueue_data
);
2456 kill(child
, SIGCONT
);
2457 if (waitpid(child
, &wstatus
, 0) < 0)
2458 err(EXIT_FAILURE
, "failed in waitpid()");
2460 if (WIFEXITED(wstatus
)) {
2461 int s
= WEXITSTATUS(wstatus
);
2463 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2464 } else if (WIFSIGNALED(wstatus
)) {
2465 int s
= WTERMSIG(wstatus
);
2466 if (WTERMSIG(wstatus
) != 0)
2467 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2471 static void *make_mqueue(const struct factory
*factory
, struct fdesc fdescs
[],
2472 int argc
, char ** argv
)
2474 struct mqueue_data
*mqueue_data
;
2475 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
2476 const char *spath
= ARG_STRING(path
);
2478 struct mq_attr attr
= {
2485 if (spath
[0] != '/')
2486 errx(EXIT_FAILURE
, "the path for mqueue must start with '/': %s", spath
);
2488 if (spath
[0] == '\0')
2489 err(EXIT_FAILURE
, "the path should not be empty");
2491 if (fdescs
[0].fd
== fdescs
[1].fd
)
2492 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2494 mqueue_data
= xmalloc(sizeof(*mqueue_data
));
2495 mqueue_data
->pid
= 0;
2496 mqueue_data
->path
= xstrdup(spath
);
2497 mqueue_data
->created
= false;
2501 fd
= mq_open(mqueue_data
->path
, O_CREAT
|O_EXCL
| O_RDONLY
, S_IRUSR
| S_IWUSR
, &attr
);
2503 mqueue_data_free(mqueue_data
);
2504 err(EXIT_FAILURE
, "failed in mq_open(3) for reading");
2507 mqueue_data
->created
= true;
2508 if (fd
!= fdescs
[0].fd
) {
2509 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2512 mqueue_data_free(mqueue_data
);
2514 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2519 fdescs
[0] = (struct fdesc
){
2521 .close
= close_mqueue
,
2525 fd
= mq_open(mqueue_data
->path
, O_WRONLY
, S_IRUSR
| S_IWUSR
, NULL
);
2528 mq_close(fdescs
[0].fd
);
2529 mqueue_data_free(mqueue_data
);
2531 err(EXIT_FAILURE
, "failed in mq_open(3) for writing");
2534 if (fd
!= fdescs
[1].fd
) {
2535 if (dup2(fd
, fdescs
[1].fd
) < 0) {
2538 mq_close(fdescs
[0].fd
);
2540 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[1].fd
);
2544 fdescs
[1] = (struct fdesc
){
2546 .close
= close_mqueue
,
2550 signal(SIGCHLD
, abort_with_child_death_message
);
2551 mqueue_data
->pid
= fork();
2552 if (mqueue_data
->pid
< -1) {
2554 mq_close(fdescs
[0].fd
);
2555 mq_close(fdescs
[1].fd
);
2556 mqueue_data_free(mqueue_data
);
2558 err(EXIT_FAILURE
, "failed in fork()");
2559 } else if (mqueue_data
->pid
== 0) {
2560 mqueue_data
->created
= false;
2561 mqueue_data_free(mqueue_data
);
2562 mq_close(fdescs
[0].fd
);
2564 signal(SIGCONT
, do_nothing
);
2565 /* Notify the parent that I'm ready. */
2566 if (mq_send(fdescs
[1].fd
, "", 0, 0) < 0)
2568 "failed in mq_send() to notify the readiness to the prent");
2569 /* Wait till the parent lets me go. */
2572 mq_close(fdescs
[1].fd
);
2577 /* The child owns fdescs[1]. */
2578 mq_close(fdescs
[1].fd
);
2581 /* Wait till the child is ready. */
2582 if (mq_receive(fdescs
[0].fd
, &c
, 1, NULL
) < 0) {
2583 mq_close(fdescs
[0].fd
);
2584 mqueue_data_free(mqueue_data
);
2586 "failed in mq_receive() the readiness notification from the child");
2588 signal(SIGCHLD
, SIG_DFL
);
2593 struct sysvshm_data
{
2598 static void *make_sysvshm(const struct factory
*factory _U_
, struct fdesc fdescs
[] _U_
,
2599 int argc _U_
, char ** argv _U_
)
2601 size_t pagesize
= getpagesize();
2602 struct sysvshm_data
*sysvshm_data
;
2603 int id
= shmget(IPC_PRIVATE
, pagesize
, IPC_CREAT
| 0600);
2607 err(EXIT_FAILURE
, "failed to do shmget(.., %zu, ...)",
2610 start
= shmat(id
, NULL
, SHM_RDONLY
);
2611 if (start
== (void *) -1) {
2613 shmctl(id
, IPC_RMID
, NULL
);
2615 err(EXIT_FAILURE
, "failed to do shmat(%d,...)", id
);
2618 sysvshm_data
= xmalloc(sizeof(*sysvshm_data
));
2619 sysvshm_data
->addr
= start
;
2620 sysvshm_data
->id
= id
;
2621 return sysvshm_data
;
2624 static void free_sysvshm(const struct factory
*factory _U_
, void *data
)
2626 struct sysvshm_data
*sysvshm_data
= data
;
2628 shmdt(sysvshm_data
->addr
);
2629 shmctl(sysvshm_data
->id
, IPC_RMID
, NULL
);
2632 static void *make_eventpoll(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2633 int argc _U_
, char ** argv _U_
)
2642 .file
= "DUMMY, DONT'USE THIS"
2644 .file
= "/dev/random",
2648 .file
= "/dev/random",
2654 efd
= epoll_create(1);
2656 err(EXIT_FAILURE
, "failed in epoll_create(2)");
2657 if (efd
!= fdescs
[0].fd
) {
2658 if (dup2(efd
, fdescs
[0].fd
) < 0) {
2662 err(EXIT_FAILURE
, "failed to dup %d -> %d", efd
, fdescs
[0].fd
);
2667 fdescs
[0] = (struct fdesc
){
2669 .close
= close_fdesc
,
2673 for (size_t i
= 1; i
< ARRAY_SIZE(specs
); i
++) {
2674 int fd
= open(specs
[i
].file
, specs
[i
].flag
);
2678 for (size_t j
= i
- 1; j
> 0; j
--)
2679 close(fdescs
[j
].fd
);
2681 err(EXIT_FAILURE
, "failed in open(\"%s\",...)",
2684 if (fd
!= fdescs
[i
].fd
) {
2685 if (dup2(fd
, fdescs
[i
].fd
) < 0) {
2688 for (size_t j
= i
- 1; j
> 0; j
--)
2689 close(fdescs
[j
].fd
);
2692 err(EXIT_FAILURE
, "failed to dup %d -> %d",
2697 fdescs
[i
] = (struct fdesc
) {
2699 .close
= close_fdesc
,
2702 if (epoll_ctl(efd
, EPOLL_CTL_ADD
, fdescs
[i
].fd
,
2703 &(struct epoll_event
) {
2704 .events
= specs
[i
].events
,
2705 .data
= {.ptr
= NULL
,}
2709 for (size_t j
= i
; j
> 0; j
--)
2710 close(fdescs
[j
].fd
);
2713 "failed to add fd %d to the eventpoll fd with epoll_ctl",
2721 static bool decode_clockid(const char *sclockid
, clockid_t
*clockid
)
2723 if (sclockid
== NULL
)
2725 if (sclockid
[0] == '\0')
2728 if (strcmp(sclockid
, "realtime") == 0)
2729 *clockid
= CLOCK_REALTIME
;
2730 else if (strcmp(sclockid
, "monotonic") == 0)
2731 *clockid
= CLOCK_MONOTONIC
;
2732 else if (strcmp(sclockid
, "boottime") == 0)
2733 *clockid
= CLOCK_BOOTTIME
;
2734 else if (strcmp(sclockid
, "realtime-alarm") == 0)
2735 *clockid
= CLOCK_REALTIME_ALARM
;
2736 else if (strcmp(sclockid
, "boottime-alarm") == 0)
2737 *clockid
= CLOCK_BOOTTIME_ALARM
;
2743 static void *make_timerfd(const struct factory
*factory
, struct fdesc fdescs
[],
2744 int argc
, char ** argv
)
2747 struct timespec now
;
2748 struct itimerspec tspec
;
2750 struct arg abstime
= decode_arg("abstime", factory
->params
, argc
, argv
);
2751 bool babstime
= ARG_BOOLEAN(abstime
);
2753 struct arg remaining
= decode_arg("remaining", factory
->params
, argc
, argv
);
2754 unsigned int uremaining
= ARG_UINTEGER(remaining
);
2756 struct arg interval
= decode_arg("interval", factory
->params
, argc
, argv
);
2757 unsigned int uinterval
= ARG_UINTEGER(interval
);
2759 struct arg interval_frac
= decode_arg("interval-nanofrac", factory
->params
, argc
, argv
);
2760 unsigned int uinterval_frac
= ARG_UINTEGER(interval_frac
);
2762 struct arg clockid_
= decode_arg("clockid", factory
->params
, argc
, argv
);
2763 const char *sclockid
= ARG_STRING(clockid_
);
2766 if (decode_clockid (sclockid
, &clockid
) == false)
2767 err(EXIT_FAILURE
, "unknown clockid: %s", sclockid
);
2769 free_arg(&clockid_
);
2770 free_arg(&interval_frac
);
2771 free_arg(&interval
);
2772 free_arg(&remaining
);
2776 int r
= clock_gettime(clockid
, &now
);
2778 err(EXIT_FAILURE
, "failed in clock_gettime(2)");
2781 tfd
= timerfd_create(clockid
, 0);
2783 err(EXIT_FAILURE
, "failed in timerfd_create(2)");
2785 tspec
.it_value
.tv_sec
= (babstime
? now
.tv_sec
: 0) + uremaining
;
2786 tspec
.it_value
.tv_nsec
= (babstime
? now
.tv_nsec
: 0);
2788 tspec
.it_interval
.tv_sec
= uinterval
;
2789 tspec
.it_interval
.tv_nsec
= uinterval_frac
;
2791 if (timerfd_settime(tfd
, babstime
? TFD_TIMER_ABSTIME
: 0, &tspec
, NULL
) < 0) {
2795 err(EXIT_FAILURE
, "failed in timerfd_settime(2)");
2798 if (tfd
!= fdescs
[0].fd
) {
2799 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2803 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2808 fdescs
[0] = (struct fdesc
){
2810 .close
= close_fdesc
,
2817 static void *make_signalfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2818 int argc _U_
, char ** argv _U_
)
2823 if (sigemptyset(&mask
) < 0)
2824 err(EXIT_FAILURE
, "failed in sigemptyset()");
2825 if (sigaddset(&mask
, SIGFPE
) < 0)
2826 err(EXIT_FAILURE
, "failed in sigaddset(FPE)");
2827 if (sigaddset(&mask
, SIGUSR1
) < 0)
2828 err(EXIT_FAILURE
, "failed in sigaddset(USR1)");
2829 if (sigaddset(&mask
, numsig
) < 0)
2830 err(EXIT_FAILURE
, "failed in sigaddset(%d)", numsig
);
2832 int sfd
= signalfd(-1, &mask
, 0);
2834 err(EXIT_FAILURE
, "failed in signalfd(2)");
2836 if (sfd
!= fdescs
[0].fd
) {
2837 if (dup2(sfd
, fdescs
[0].fd
) < 0) {
2841 err(EXIT_FAILURE
, "failed to dup %d -> %d", sfd
, fdescs
[0].fd
);
2846 fdescs
[0] = (struct fdesc
){
2848 .close
= close_fdesc
,
2856 /* ref. linux/Documentation/networking/tuntap.rst */
2857 static void *make_cdev_tun(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2858 int argc _U_
, char ** argv _U_
)
2860 int tfd
= open("/dev/net/tun", O_RDWR
);
2864 err(EXIT_FAILURE
, "failed in opening /dev/net/tun");
2866 memset(&ifr
, 0, sizeof(ifr
));
2868 ifr
.ifr_flags
= IFF_TUN
;
2869 strcpy(ifr
.ifr_name
, "mkfds%d");
2871 if (ioctl(tfd
, TUNSETIFF
, (void *) &ifr
) < 0) {
2875 err(EXIT_FAILURE
, "failed in setting \"lo\" to the tun device");
2878 if (tfd
!= fdescs
[0].fd
) {
2879 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2883 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2888 fdescs
[0] = (struct fdesc
){
2890 .close
= close_fdesc
,
2894 return xstrdup(ifr
.ifr_name
);
2897 static void report_cdev_tun(const struct factory
*factory _U_
,
2898 int nth
, void *data
, FILE *fp
)
2901 char *devname
= data
;
2902 fprintf(fp
, "%s", devname
);
2906 static void free_cdev_tun(const struct factory
* factory _U_
, void *data
)
2911 static void *make_bpf_prog(const struct factory
*factory
, struct fdesc fdescs
[],
2912 int argc
, char ** argv
)
2914 struct arg prog_type_id
= decode_arg("prog-type-id", factory
->params
, argc
, argv
);
2915 int iprog_type_id
= ARG_INTEGER(prog_type_id
);
2917 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
2918 const char *sname
= ARG_STRING(name
);
2921 union bpf_attr attr
;
2922 /* Just doing exit with 0. */
2923 struct bpf_insn insns
[] = {
2925 .code
= BPF_ALU64
| BPF_MOV
| BPF_K
,
2926 .dst_reg
= BPF_REG_0
, .src_reg
= 0, .off
= 0, .imm
= 0
2929 .code
= BPF_JMP
| BPF_EXIT
,
2930 .dst_reg
= 0, .src_reg
= 0, .off
= 0, .imm
= 0
2934 memset(&attr
, 0, sizeof(attr
));
2935 attr
.prog_type
= iprog_type_id
;
2936 attr
.insns
= (uint64_t)(unsigned long)insns
;
2937 attr
.insn_cnt
= ARRAY_SIZE(insns
);
2938 attr
.license
= (int64_t)(unsigned long)"GPL";
2939 strncpy(attr
.prog_name
, sname
, sizeof(attr
.prog_name
) - 1);
2942 free_arg(&prog_type_id
);
2944 bfd
= syscall(SYS_bpf
, BPF_PROG_LOAD
, &attr
, sizeof(attr
));
2946 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_PROG_LOAD)");
2948 if (bfd
!= fdescs
[0].fd
) {
2949 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
2953 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
2958 fdescs
[0] = (struct fdesc
){
2960 .close
= close_fdesc
,
2967 static void *make_some_pipes(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2968 int argc _U_
, char ** argv _U_
)
2970 /* Reserver fds before making pipes */
2971 for (int i
= 0; i
< factory
->N
; i
++) {
2972 close(fdescs
[i
].fd
);
2973 if (dup2(0, fdescs
[0].fd
) < 0)
2974 err(EXIT_FAILURE
, "failed to reserve fd %d with dup2", fdescs
[0].fd
);
2977 for (int i
= 0; i
< (factory
->N
) / 2; i
++) {
2982 mode
= 1 << (i
% 3);
2983 if (mode
== MX_WRITE
) {
2989 err(EXIT_FAILURE
, "failed to make pipe");
2991 if (dup2(pd
[0], fdescs
[2 * i
+ r
].fd
) < 0)
2992 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[0], fdescs
[2 * i
+ r
].fd
);
2994 fdescs
[2 * 1 + r
].close
= close_fdesc
;
2996 if (dup2(pd
[1], fdescs
[2 * i
+ w
].fd
) < 0)
2997 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[1], fdescs
[2 * i
+ 2].fd
);
2999 fdescs
[2 * 1 + w
].close
= close_fdesc
;
3001 fdescs
[2 * i
].mx_modes
|= mode
;
3003 /* Make the pipe for writing full. */
3004 if (fdescs
[2 * i
].mx_modes
& MX_WRITE
) {
3005 int n
= fcntl(fdescs
[2 * i
].fd
, F_GETPIPE_SZ
);
3009 err(EXIT_FAILURE
, "failed to get PIPE BUFFER SIZE from %d", fdescs
[2 * i
].fd
);
3012 if (write(fdescs
[2 * i
].fd
, buf
, n
) != n
)
3013 err(EXIT_FAILURE
, "failed to fill the pipe buffer specified with %d",
3023 static void *make_bpf_map(const struct factory
*factory
, struct fdesc fdescs
[],
3024 int argc
, char ** argv
)
3026 struct arg map_type_id
= decode_arg("map-type-id", factory
->params
, argc
, argv
);
3027 int imap_type_id
= ARG_INTEGER(map_type_id
);
3029 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
3030 const char *sname
= ARG_STRING(name
);
3033 union bpf_attr attr
= {
3034 .map_type
= imap_type_id
,
3040 strncpy(attr
.map_name
, sname
, sizeof(attr
.map_name
) - 1);
3043 free_arg(&map_type_id
);
3045 bfd
= syscall(SYS_bpf
, BPF_MAP_CREATE
, &attr
, sizeof(attr
));
3047 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_MAP_CREATE)");
3049 if (bfd
!= fdescs
[0].fd
) {
3050 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
3054 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
3059 fdescs
[0] = (struct fdesc
){
3061 .close
= close_fdesc
,
3068 static void *make_pty(const struct factory
*factory _U_
, struct fdesc fdescs
[],
3069 int argc _U_
, char ** argv _U_
)
3074 int ptmx_fd
= posix_openpt(O_RDWR
);
3076 err(EXIT_FAILURE
, "failed in opening /dev/ptmx");
3078 if (unlockpt(ptmx_fd
) < 0) {
3082 err(EXIT_FAILURE
, "failed in unlockpt()");
3085 if (ioctl(ptmx_fd
, TIOCGPTN
, &index
) < 0) {
3089 err(EXIT_FAILURE
, "failed in ioctl(TIOCGPTN)");
3092 pts
= ptsname(ptmx_fd
);
3097 err(EXIT_FAILURE
, "failed in ptsname()");
3100 if (ptmx_fd
!= fdescs
[0].fd
) {
3101 if (dup2(ptmx_fd
, fdescs
[0].fd
) < 0) {
3105 err(EXIT_FAILURE
, "failed to dup %d -> %d", ptmx_fd
, fdescs
[0].fd
);
3108 ptmx_fd
= fdescs
[0].fd
;
3111 pts_fd
= open(pts
, O_RDONLY
);
3116 err(EXIT_FAILURE
, "failed in opening %s", pts
);
3119 if (pts_fd
!= fdescs
[1].fd
) {
3120 if (dup2(pts_fd
, fdescs
[1].fd
) < 0) {
3125 err(EXIT_FAILURE
, "failed to dup %d -> %d", pts_fd
, fdescs
[1].fd
);
3128 pts_fd
= fdescs
[1].fd
;
3131 fdescs
[0] = (struct fdesc
){
3133 .close
= close_fdesc
,
3136 fdescs
[1] = (struct fdesc
){
3138 .close
= close_fdesc
,
3142 indexp
= xmalloc(sizeof(index
));
3147 static void report_pty(const struct factory
*factory _U_
,
3148 int nth
, void *data
, FILE *fp
)
3152 fprintf(fp
, "%d", *index
);
3156 static void free_pty(const struct factory
* factory _U_
, void *data
)
3161 #define PARAM_END { .name = NULL, }
3162 static const struct factory factories
[] = {
3164 .name
= "ro-regular-file",
3165 .desc
= "read-only regular file",
3169 .make
= open_ro_regular_file
,
3170 .params
= (struct parameter
[]) {
3173 .type
= PTYPE_STRING
,
3174 .desc
= "file to be opened",
3175 .defv
.string
= "/etc/passwd",
3179 .type
= PTYPE_INTEGER
,
3180 .desc
= "seek bytes after open with SEEK_CUR",
3184 .name
= "read-lease",
3185 .type
= PTYPE_BOOLEAN
,
3186 .desc
= "taking out read lease for the file",
3187 .defv
.boolean
= false,
3193 .name
= "make-regular-file",
3194 .desc
= "regular file for writing",
3198 .make
= make_w_regular_file
,
3199 .free
= free_after_closing_duplicated_fd
,
3200 .params
= (struct parameter
[]) {
3203 .type
= PTYPE_STRING
,
3204 .desc
= "file to be made",
3205 .defv
.string
= "./test_mkfds_make_regular_file",
3209 .type
= PTYPE_BOOLEAN
,
3210 .desc
= "delete the file just after making it",
3211 .defv
.boolean
= false,
3214 .name
= "write-bytes",
3215 .type
= PTYPE_INTEGER
,
3216 .desc
= "write something (> 0)",
3221 .type
= PTYPE_BOOLEAN
,
3222 .desc
= "open the new file readable way",
3223 .defv
.string
= false,
3227 .type
= PTYPE_STRING
,
3228 .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",
3229 .defv
.string
= "none",
3233 .type
= PTYPE_INTEGER
,
3234 .desc
= "the number for the fd duplicated from the original fd",
3241 .name
= "pipe-no-fork",
3242 .desc
= "making pair of fds with pipe(2)",
3247 .params
= (struct parameter
[]) {
3250 .type
= PTYPE_STRING
,
3251 .desc
= "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")",
3252 .defv
.string
= "--",
3256 .type
= PTYPE_INTEGER
,
3257 .desc
= "file descriptor for duplicating the pipe input",
3262 .type
= PTYPE_INTEGER
,
3263 .desc
= "file descriptor for duplicating the pipe output",
3270 .name
= "directory",
3271 .desc
= "directory",
3275 .make
= open_directory
,
3276 .params
= (struct parameter
[]) {
3279 .type
= PTYPE_STRING
,
3280 .desc
= "directory to be opened",
3285 .type
= PTYPE_INTEGER
,
3286 .desc
= "read the number of dentries after open with readdir(3)",
3293 .name
= "rw-character-device",
3294 .desc
= "character device with O_RDWR flag",
3298 .make
= open_rw_chrdev
,
3299 .params
= (struct parameter
[]) {
3302 .type
= PTYPE_STRING
,
3303 .desc
= "character device node to be opened",
3304 .defv
.string
= "/dev/zero",
3310 .name
= "socketpair",
3311 .desc
= "AF_UNIX socket pair created with socketpair(2)",
3315 .make
= make_socketpair
,
3316 .params
= (struct parameter
[]) {
3319 .type
= PTYPE_STRING
,
3320 .desc
= "STREAM, DGRAM, or SEQPACKET",
3321 .defv
.string
= "STREAM",
3324 .name
= "halfclose",
3325 .type
= PTYPE_BOOLEAN
,
3326 .desc
= "Shutdown the read end of the 1st socket, the write end of the 2nd socket",
3327 .defv
.boolean
= false,
3334 .desc
= "symbolic link itself opened with O_PATH",
3338 .make
= open_with_opath
,
3339 .params
= (struct parameter
[]) {
3342 .type
= PTYPE_STRING
,
3343 .desc
= "path to a symbolic link",
3344 .defv
.string
= "/dev/stdin",
3350 .name
= "ro-block-device",
3351 .desc
= "block device with O_RDONLY flag",
3355 .make
= open_ro_blkdev
,
3356 .params
= (struct parameter
[]) {
3359 .type
= PTYPE_STRING
,
3360 .desc
= "block device node to be opened",
3361 .defv
.string
= "/dev/nullb0",
3367 .name
= "mapped-packet-socket",
3368 .desc
= "mmap'ed AF_PACKET socket",
3372 .make
= make_mmapped_packet_socket
,
3373 .params
= (struct parameter
[]) {
3376 .type
= PTYPE_STRING
,
3377 .desc
= "DGRAM or RAW",
3378 .defv
.string
= "RAW",
3381 .name
= "interface",
3382 .type
= PTYPE_STRING
,
3383 .desc
= "a name of network interface like eth0 or lo",
3384 .defv
.string
= "lo",
3391 .desc
= "pidfd returned from pidfd_open(2)",
3396 .params
= (struct parameter
[]) {
3398 .name
= "target-pid",
3399 .type
= PTYPE_INTEGER
,
3400 .desc
= "the pid of the target process",
3408 .desc
= "inotify fd returned from inotify_init(2)",
3412 .make
= make_inotify_fd
,
3413 .params
= (struct parameter
[]) {
3416 .type
= PTYPE_STRING
,
3417 .desc
= "the directory that the inotify monitors",
3422 .type
= PTYPE_STRING
,
3423 .desc
= "the file that the inotify monitors",
3424 .defv
.string
= "/etc/fstab",
3430 .name
= "unix-stream",
3431 .desc
= "AF_UNIX+SOCK_STREAM sockets",
3435 .make
= make_unix_stream
,
3436 .params
= (struct parameter
[]) {
3439 .type
= PTYPE_STRING
,
3440 .desc
= "path for listening-socket bound to",
3441 .defv
.string
= "/tmp/test_mkfds-unix-stream",
3445 .type
= PTYPE_INTEGER
,
3446 .desc
= "backlog passed to listen(2)",
3451 .type
= PTYPE_BOOLEAN
,
3452 .desc
= "use PATH as an abstract socket address",
3453 .defv
.boolean
= false,
3456 .name
= "server-shutdown",
3457 .type
= PTYPE_INTEGER
,
3458 .desc
= "shutdown the accepted socket; 1: R, 2: W, 3: RW",
3462 .name
= "client-shutdown",
3463 .type
= PTYPE_INTEGER
,
3464 .desc
= "shutdown the client socket; 1: R, 2: W, 3: RW",
3469 .type
= PTYPE_STRING
,
3470 .desc
= "stream or seqpacket",
3471 .defv
.string
= "stream",
3477 .name
= "unix-dgram",
3478 .desc
= "AF_UNIX+SOCK_DGRAM sockets",
3482 .make
= make_unix_dgram
,
3483 .params
= (struct parameter
[]) {
3486 .type
= PTYPE_STRING
,
3487 .desc
= "path for unix non-stream bound to",
3488 .defv
.string
= "/tmp/test_mkfds-unix-dgram",
3492 .type
= PTYPE_BOOLEAN
,
3493 .desc
= "use PATH as an abstract socket address",
3494 .defv
.boolean
= false,
3500 .name
= "unix-in-netns",
3501 .desc
= "make a unix socket in a new network namespace",
3505 .make
= make_unix_in_new_netns
,
3506 .params
= (struct parameter
[]) {
3509 .type
= PTYPE_STRING
,
3510 .desc
= "dgram, stream, or seqpacket",
3511 .defv
.string
= "stream",
3515 .type
= PTYPE_STRING
,
3516 .desc
= "path for unix non-stream bound to",
3517 .defv
.string
= "/tmp/test_mkfds-unix-in-netns",
3521 .type
= PTYPE_BOOLEAN
,
3522 .desc
= "use PATH as an abstract socket address",
3523 .defv
.boolean
= false,
3530 .desc
= "AF_INET+SOCK_STREAM sockets",
3535 .params
= (struct parameter
[]) {
3537 .name
= "server-port",
3538 .type
= PTYPE_INTEGER
,
3539 .desc
= "TCP port the server may listen",
3540 .defv
.integer
= 12345,
3543 .name
= "client-port",
3544 .type
= PTYPE_INTEGER
,
3545 .desc
= "TCP port the client may bind",
3546 .defv
.integer
= 23456,
3553 .desc
= "AF_INET+SOCK_DGRAM sockets",
3558 .params
= (struct parameter
[]) {
3561 .type
= PTYPE_BOOLEAN
,
3562 .desc
= "Use UDPLITE instead of UDP",
3563 .defv
.boolean
= false,
3566 .name
= "server-port",
3567 .type
= PTYPE_INTEGER
,
3568 .desc
= "UDP port the server may listen",
3569 .defv
.integer
= 12345,
3572 .name
= "client-port",
3573 .type
= PTYPE_INTEGER
,
3574 .desc
= "UDP port the client may bind",
3575 .defv
.integer
= 23456,
3578 .name
= "server-do-bind",
3579 .type
= PTYPE_BOOLEAN
,
3580 .desc
= "call bind with the server socket",
3581 .defv
.boolean
= true,
3584 .name
= "client-do-bind",
3585 .type
= PTYPE_BOOLEAN
,
3586 .desc
= "call bind with the client socket",
3587 .defv
.boolean
= true,
3590 .name
= "client-do-connect",
3591 .type
= PTYPE_BOOLEAN
,
3592 .desc
= "call connect with the client socket",
3593 .defv
.boolean
= true,
3600 .desc
= "AF_INET+SOCK_RAW sockets",
3605 .params
= (struct parameter
[]) {
3608 .type
= PTYPE_INTEGER
,
3609 .desc
= "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
3610 .defv
.integer
= IPPROTO_IPIP
,
3618 .desc
= "AF_INET+SOCK_DGRAM+IPPROTO_ICMP sockets",
3623 .params
= (struct parameter
[]) {
3626 .type
= PTYPE_BOOLEAN
,
3627 .desc
= "call connect(2) with the socket",
3628 .defv
.boolean
= true,
3632 .type
= PTYPE_BOOLEAN
,
3633 .desc
= "call bind(2) with the socket",
3634 .defv
.boolean
= true,
3638 .type
= PTYPE_INTEGER
,
3639 .desc
= "ICMP echo request id",
3647 .desc
= "AF_INET6+SOCK_STREAM sockets",
3652 .params
= (struct parameter
[]) {
3654 .name
= "server-port",
3655 .type
= PTYPE_INTEGER
,
3656 .desc
= "TCP port the server may listen",
3657 .defv
.integer
= 12345,
3660 .name
= "client-port",
3661 .type
= PTYPE_INTEGER
,
3662 .desc
= "TCP port the client may bind",
3663 .defv
.integer
= 23456,
3670 .desc
= "AF_INET6+SOCK_DGRAM sockets",
3675 .params
= (struct parameter
[]) {
3678 .type
= PTYPE_BOOLEAN
,
3679 .desc
= "Use UDPLITE instead of UDP",
3680 .defv
.boolean
= false,
3683 .name
= "server-port",
3684 .type
= PTYPE_INTEGER
,
3685 .desc
= "UDP port the server may listen",
3686 .defv
.integer
= 12345,
3689 .name
= "client-port",
3690 .type
= PTYPE_INTEGER
,
3691 .desc
= "UDP port the client may bind",
3692 .defv
.integer
= 23456,
3695 .name
= "server-do-bind",
3696 .type
= PTYPE_BOOLEAN
,
3697 .desc
= "call bind with the server socket",
3698 .defv
.boolean
= true,
3701 .name
= "client-do-bind",
3702 .type
= PTYPE_BOOLEAN
,
3703 .desc
= "call bind with the client socket",
3704 .defv
.boolean
= true,
3707 .name
= "client-do-connect",
3708 .type
= PTYPE_BOOLEAN
,
3709 .desc
= "call connect with the client socket",
3710 .defv
.boolean
= true,
3717 .desc
= "AF_INET6+SOCK_RAW sockets",
3722 .params
= (struct parameter
[]) {
3725 .type
= PTYPE_INTEGER
,
3726 .desc
= "protocol passed to socket(AF_INET6, SOCK_RAW, protocol)",
3727 .defv
.integer
= IPPROTO_IPIP
,
3735 .desc
= "AF_INET6+SOCK_DGRAM+IPPROTO_ICMPV6 sockets",
3740 .params
= (struct parameter
[]) {
3743 .type
= PTYPE_BOOLEAN
,
3744 .desc
= "call connect(2) with the socket",
3745 .defv
.boolean
= true,
3749 .type
= PTYPE_BOOLEAN
,
3750 .desc
= "call bind(2) with the socket",
3751 .defv
.boolean
= true,
3755 .type
= PTYPE_INTEGER
,
3756 .desc
= "ICMP echo request id",
3765 .desc
= "open a file specifying a netns",
3770 .params
= (struct parameter
[]) {
3777 .desc
= "AF_NETLINK sockets",
3781 .make
= make_netlink
,
3782 .params
= (struct parameter
[]) {
3785 .type
= PTYPE_INTEGER
,
3786 .desc
= "protocol passed to socket(AF_NETLINK, SOCK_RAW, protocol)",
3787 .defv
.integer
= NETLINK_USERSOCK
,
3791 .type
= PTYPE_UINTEGER
,
3792 .desc
= "multicast groups of netlink communication (requires CAP_NET_ADMIN)",
3800 .desc
= "make an eventfd connecting two processes",
3805 .make
= make_eventfd
,
3806 .report
= report_eventfd
,
3807 .free
= free_eventfd
,
3808 .params
= (struct parameter
[]) {
3814 .desc
= "make a mqueue connecting two processes",
3819 .make
= make_mqueue
,
3820 .report
= report_mqueue
,
3821 .free
= free_mqueue
,
3822 .params
= (struct parameter
[]) {
3825 .type
= PTYPE_STRING
,
3826 .desc
= "path for mqueue",
3827 .defv
.string
= "/test_mkfds-mqueue",
3834 .desc
= "shared memory mapped with SYSVIPC shmem syscalls",
3838 .make
= make_sysvshm
,
3839 .free
= free_sysvshm
,
3840 .params
= (struct parameter
[]) {
3845 .name
= "eventpoll",
3846 .desc
= "make eventpoll (epoll) file",
3850 .make
= make_eventpoll
,
3851 .params
= (struct parameter
[]) {
3857 .desc
= "make timerfd",
3861 .make
= make_timerfd
,
3862 .params
= (struct parameter
[]) {
3865 .type
= PTYPE_STRING
,
3866 .desc
= "ID: realtime, monotonic, boottime, realtime-alarm, or boottime-alarm",
3867 .defv
.string
= "realtime",
3871 .type
= PTYPE_BOOLEAN
,
3872 .desc
= "use TFD_TIMER_ABSTIME flag",
3873 .defv
.boolean
= false,
3876 .name
= "remaining",
3877 .type
= PTYPE_UINTEGER
,
3878 .desc
= "remaining seconds for expiration",
3879 .defv
.uinteger
= 99,
3883 .type
= PTYPE_UINTEGER
,
3884 .desc
= "inteval in seconds",
3885 .defv
.uinteger
= 10,
3888 .name
= "interval-nanofrac",
3889 .type
= PTYPE_UINTEGER
,
3890 .desc
= "nsec part of inteval",
3899 .desc
= "make signalfd",
3903 .make
= make_signalfd
,
3904 .params
= (struct parameter
[]) {
3910 .desc
= "open /dev/net/tun",
3915 .make
= make_cdev_tun
,
3916 .report
= report_cdev_tun
,
3917 .free
= free_cdev_tun
,
3918 .params
= (struct parameter
[]) {
3924 .desc
= "make bpf-prog",
3928 .make
= make_bpf_prog
,
3929 .params
= (struct parameter
[]) {
3931 .name
= "prog-type-id",
3932 .type
= PTYPE_INTEGER
,
3933 .desc
= "program type by id",
3938 .type
= PTYPE_STRING
,
3939 .desc
= "name assigned to bpf prog object",
3940 .defv
.string
= "mkfds_bpf_prog",
3946 .name
= "multiplexing",
3947 .desc
= "making pipes monitored by multiplexers",
3951 .make
= make_some_pipes
,
3952 .params
= (struct parameter
[]) {
3958 .desc
= "make bpf-map",
3962 .make
= make_bpf_map
,
3963 .params
= (struct parameter
[]) {
3965 .name
= "map-type-id",
3966 .type
= PTYPE_INTEGER
,
3967 .desc
= "map type by id",
3972 .type
= PTYPE_STRING
,
3973 .desc
= "name assigned to the bpf map object",
3974 .defv
.string
= "mkfds_bpf_map",
3981 .desc
= "make a pair of ptmx and pts",
3987 .report
= report_pty
,
3989 .params
= (struct parameter
[]) {
3995 static int count_parameters(const struct factory
*factory
)
3998 const struct parameter
*p
= factory
->params
;
4003 return p
- factory
->params
;
4006 static void print_factory(const struct factory
*factory
)
4008 printf("%-20s %4s %5d %7d %6d %s\n",
4010 factory
->priv
? "yes": "no",
4013 count_parameters(factory
),
4017 static void list_factories(void)
4019 printf("%-20s PRIV COUNT NRETURN NPARAM DESCRIPTION\n", "FACTORY");
4020 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4021 print_factory(factories
+ i
);
4024 static const struct factory
*find_factory(const char *name
)
4026 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4027 if (strcmp(factories
[i
].name
, name
) == 0)
4028 return factories
+ i
;
4032 static void list_parameters(const char *factory_name
)
4034 const struct factory
*factory
= find_factory(factory_name
);
4035 const char *fmt
= "%-15s %-8s %15s %s\n";
4038 errx(EXIT_FAILURE
, "no such factory: %s", factory_name
);
4040 if (!factory
->params
)
4043 printf(fmt
, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION");
4044 for (const struct parameter
*p
= factory
->params
; p
->name
!= NULL
; p
++) {
4045 char *defv
= ptype_classes
[p
->type
].sprint(&p
->defv
);
4046 printf(fmt
, p
->name
, ptype_classes
[p
->type
].name
, defv
, p
->desc
);
4051 static void rename_self(const char *comm
)
4053 if (prctl(PR_SET_NAME
, (unsigned long)comm
, 0, 0, 0) < 0)
4054 err(EXIT_FAILURE
, "failed to rename self via prctl: %s", comm
);
4057 static void do_nothing(int signum _U_
)
4061 #ifdef __NR_pidfd_open
4064 pidfd_open(pid_t pid
, unsigned int flags
)
4066 return syscall(__NR_pidfd_open
, pid
, flags
);
4070 pidfd_open(pid_t pid _U_
, unsigned int flags _U_
)
4080 struct multiplexer
{
4082 void (*fn
)(bool, struct fdesc
*fdescs
, size_t n_fdescs
);
4085 #if defined(__NR_select) || defined(__NR_poll)
4086 static void sighandler_nop(int si _U_
)
4092 #define DEFUN_WAIT_EVENT_SELECT(NAME,SYSCALL,XDECLS,SETUP_SIG_HANDLER,SYSCALL_INVOCATION) \
4093 static void wait_event_##NAME(bool add_stdin, struct fdesc *fdescs, size_t n_fdescs) \
4101 FD_ZERO(&readfds); \
4102 FD_ZERO(&writefds); \
4103 FD_ZERO(&exceptfds); \
4104 /* Monitor the standard input only when the process \
4105 * is in foreground. */ \
4108 FD_SET(0, &readfds); \
4111 for (size_t i = 0; i < n_fdescs; i++) { \
4112 if (fdescs[i].mx_modes & MX_READ) { \
4113 n = max(n, fdescs[i].fd + 1); \
4114 FD_SET(fdescs[i].fd, &readfds); \
4116 if (fdescs[i].mx_modes & MX_WRITE) { \
4117 n = max(n, fdescs[i].fd + 1); \
4118 FD_SET(fdescs[i].fd, &writefds); \
4120 if (fdescs[i].mx_modes & MX_EXCEPT) { \
4121 n = max(n, fdescs[i].fd + 1); \
4122 FD_SET(fdescs[i].fd, &exceptfds); \
4128 if (SYSCALL_INVOCATION < 0 \
4129 && errno != EINTR) \
4130 err(EXIT_FAILURE, "failed in " SYSCALL); \
4133 DEFUN_WAIT_EVENT_SELECT(default,
4136 sigemptyset(&sigset
);,
4137 pselect(n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4139 #ifdef __NR_pselect6
4140 DEFUN_WAIT_EVENT_SELECT(pselect6
,
4143 sigemptyset(&sigset
);,
4144 syscall(__NR_pselect6
, n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4148 DEFUN_WAIT_EVENT_SELECT(select
,
4151 signal(SIGCONT
,sighandler_nop
);,
4152 syscall(__NR_select
, n
, &readfds
, &writefds
, &exceptfds
, NULL
))
4156 static DEFUN_WAIT_EVENT_POLL(poll
,
4159 signal(SIGCONT
,sighandler_nop
);,
4160 syscall(__NR_poll
, pfds
, n
, -1))
4163 #define DEFAULT_MULTIPLEXER 0
4164 static struct multiplexer multiplexers
[] = {
4167 .fn
= wait_event_default
,
4169 #ifdef __NR_pselect6
4172 .fn
= wait_event_pselect6
,
4178 .fn
= wait_event_select
,
4184 .fn
= wait_event_poll
,
4190 .fn
= wait_event_ppoll
,
4195 static struct multiplexer
*lookup_multiplexer(const char *name
)
4197 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4198 if (strcmp(name
, multiplexers
[i
].name
) == 0)
4199 return multiplexers
+ i
;
4203 static void list_multiplexers(void)
4206 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4207 puts(multiplexers
[i
].name
);
4210 static bool is_available(const char *factory
)
4212 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4213 if (strcmp(factories
[i
].name
, factory
) == 0)
4219 int main(int argc
, char **argv
)
4222 const struct factory
*factory
;
4223 struct fdesc fdescs
[MAX_N
];
4227 bool monitor_stdin
= true;
4229 struct multiplexer
*wait_event
= NULL
;
4231 static const struct option longopts
[] = {
4232 { "is-available",required_argument
,NULL
, 'a' },
4233 { "list", no_argument
, NULL
, 'l' },
4234 { "parameters", required_argument
, NULL
, 'I' },
4235 { "comm", required_argument
, NULL
, 'r' },
4236 { "quiet", no_argument
, NULL
, 'q' },
4237 { "dont-monitor-stdin", no_argument
, NULL
, 'X' },
4238 { "dont-puase", no_argument
, NULL
, 'c' },
4239 { "wait-with", required_argument
, NULL
, 'w' },
4240 { "multiplexers",no_argument
,NULL
, 'W' },
4241 { "help", no_argument
, NULL
, 'h' },
4242 { NULL
, 0, NULL
, 0 },
4245 while ((c
= getopt_long(argc
, argv
, "a:lhqcI:r:w:WX", longopts
, NULL
)) != -1) {
4248 usage(stdout
, EXIT_SUCCESS
);
4250 exit(is_available(optarg
)? 0: 1);
4255 list_parameters(optarg
);
4264 wait_event
= lookup_multiplexer(optarg
);
4265 if (wait_event
== NULL
)
4266 errx(EXIT_FAILURE
, "unknown multiplexer: %s", optarg
);
4269 list_multiplexers();
4272 rename_self(optarg
);
4275 monitor_stdin
= false;
4278 usage(stderr
, EXIT_FAILURE
);
4283 errx(EXIT_FAILURE
, "no file descriptor specification given");
4285 if (cont
&& wait_event
)
4286 errx(EXIT_FAILURE
, "don't specify both -c/--dont-puase and -w/--wait-with options");
4287 if (wait_event
== NULL
)
4288 wait_event
= multiplexers
+ DEFAULT_MULTIPLEXER
;
4290 factory
= find_factory(argv
[optind
]);
4292 errx(EXIT_FAILURE
, "no such factory: %s", argv
[optind
]);
4293 assert(factory
->N
+ factory
->EX_N
< MAX_N
);
4296 if ((optind
+ factory
->N
) > argc
)
4297 errx(EXIT_FAILURE
, "not enough file descriptors given for %s",
4300 if (factory
->priv
&& getuid() != 0)
4301 errx(EXIT_FAILURE
, "%s factory requires root privilege", factory
->name
);
4303 for (int i
= 0; i
< MAX_N
; i
++) {
4305 fdescs
[i
].mx_modes
= 0;
4306 fdescs
[i
].close
= NULL
;
4309 for (int i
= 0; i
< factory
->N
; i
++) {
4310 char *str
= argv
[optind
+ i
];
4315 fd
= strtol(str
, &ep
, 10);
4317 err(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4319 errx(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4321 errx(EXIT_FAILURE
, "garbage at the end of number: %s", str
);
4323 errx(EXIT_FAILURE
, "fd number should not be negative: %s", str
);
4325 errx(EXIT_FAILURE
, "fd 0, 1, 2 are reserved: %s", str
);
4328 optind
+= factory
->N
;
4330 data
= factory
->make(factory
, fdescs
, argc
- optind
, argv
+ optind
);
4332 signal(SIGCONT
, do_nothing
);
4335 printf("%d", getpid());
4336 if (factory
->report
) {
4337 for (int i
= 0; i
< factory
->EX_R
; i
++) {
4339 factory
->report(factory
, i
, data
, stdout
);
4347 wait_event
->fn(monitor_stdin
,
4348 fdescs
, factory
->N
+ factory
->EX_N
);
4350 for (int i
= 0; i
< factory
->N
+ factory
->EX_N
; i
++)
4351 if (fdescs
[i
].fd
>= 0 && fdescs
[i
].close
)
4352 fdescs
[i
].close(fdescs
[i
].fd
, fdescs
[i
].data
);
4355 factory
->free (factory
, data
);