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>
60 #include <sys/syscall.h>
61 #include <sys/timerfd.h>
62 #include <sys/types.h>
70 #define EXIT_ENOPROTOOPT 19
71 #define EXIT_EPROTONOSUPPORT 20
72 #define EXIT_EACCESS 21
74 #define _U_ __attribute__((__unused__))
76 static int pidfd_open(pid_t pid
, unsigned int flags
);
77 static void do_nothing(int signum _U_
);
79 static void __attribute__((__noreturn__
)) usage(FILE *out
, int status
)
81 fputs("\nUsage:\n", out
);
82 fprintf(out
, " %s [options] FACTORY FD... [PARAM=VAL...]\n", program_invocation_short_name
);
84 fputs("\nOptions:\n", out
);
85 fputs(" -a, --is-available <factory> exit 0 if the factory is available\n", out
);
86 fputs(" -l, --list list available file descriptor factories and exit\n", out
);
87 fputs(" -I, --parameters <factory> list parameters the factory takes\n", out
);
88 fputs(" -r, --comm <name> rename self\n", out
);
89 fputs(" -q, --quiet don't print pid(s)\n", out
);
90 fputs(" -X, --dont-monitor-stdin don't monitor stdin when pausing\n", out
);
91 fputs(" -c, --dont-pause don't pause after making fd(s)\n", out
);
92 fputs(" -w, --wait-with <multiplexer> use MULTIPLEXER for waiting events\n", out
);
93 fputs(" -W, --multiplexers list multiplexers\n", out
);
96 fputs("Examples:\n", out
);
97 fprintf(out
, "Using 3, open /etc/group:\n\n $ %s ro-regular-file 3 file=/etc/group\n\n",
98 program_invocation_short_name
);
99 fprintf(out
, "Using 3 and 4, make a pipe:\n\n $ %s pipe-no-fork 3 4\n\n",
100 program_invocation_short_name
);
108 unsigned long uinteger
;
122 /* Covert to a string representation.
123 * A caller must free the returned value with free(3) after using. */
124 char *(*sprint
)(const union value
*value
);
126 /* Convert from a string. If ARG is NULL, use DEFV instead.
127 * A caller must free the returned value with the free method
129 union value (*read
)(const char *arg
, const union value
*defv
);
131 /* Free the value returned from the read method. */
132 void (*free
)(union value value
);
135 #define ARG_STRING(A) (A.v.string)
136 #define ARG_INTEGER(A) (A.v.integer)
137 #define ARG_UINTEGER(A) (A.v.uinteger)
138 #define ARG_BOOLEAN(A) (A.v.boolean)
141 void (*free
)(union value value
);
146 const enum ptype type
;
148 union value defv
; /* Default value */
151 static char *string_sprint(const union value
*value
)
153 return xstrdup(value
->string
);
156 static union value
string_read(const char *arg
, const union value
*defv
)
158 return (union value
){ .string
= xstrdup(arg
?: defv
->string
) };
161 static void string_free(union value value
)
163 free((void *)value
.string
);
166 static char *integer_sprint(const union value
*value
)
169 xasprintf(&str
, "%ld", value
->integer
);
173 static union value
integer_read(const char *arg
, const union value
*defv
)
182 r
.integer
= strtol(arg
, &ep
, 10);
184 err(EXIT_FAILURE
, "fail to make a number from %s", arg
);
185 else if (*ep
!= '\0')
186 errx(EXIT_FAILURE
, "garbage at the end of number: %s", arg
);
190 static void integer_free(union value value _U_
)
195 static char *uinteger_sprint(const union value
*value
)
198 xasprintf(&str
, "%lu", value
->uinteger
);
202 static union value
uinteger_read(const char *arg
, const union value
*defv
)
211 r
.uinteger
= strtoul(arg
, &ep
, 10);
213 err(EXIT_FAILURE
, "fail to make a number from %s", arg
);
214 else if (*ep
!= '\0')
215 errx(EXIT_FAILURE
, "garbage at the end of number: %s", arg
);
219 static void uinteger_free(union value value _U_
)
224 static char *boolean_sprint(const union value
*value
)
226 return xstrdup(value
->boolean
? "true": "false");
229 static union value
boolean_read(const char *arg
, const union value
*defv
)
236 if (strcasecmp(arg
, "true") == 0
237 || strcmp(arg
, "1") == 0
238 || strcasecmp(arg
, "yes") == 0
239 || strcasecmp(arg
, "y") == 0)
246 static void boolean_free(union value value _U_
)
251 struct ptype_class ptype_classes
[] = {
254 .sprint
= string_sprint
,
260 .sprint
= integer_sprint
,
261 .read
= integer_read
,
262 .free
= integer_free
,
266 .sprint
= uinteger_sprint
,
267 .read
= uinteger_read
,
268 .free
= uinteger_free
,
272 .sprint
= boolean_sprint
,
273 .read
= boolean_read
,
274 .free
= boolean_free
,
278 static struct arg
decode_arg(const char *pname
,
279 const struct parameter
*parameters
,
280 int argc
, char **argv
)
283 size_t len
= strlen(pname
);
284 const struct parameter
*p
= NULL
;
287 while (parameters
->name
) {
288 if (strcmp(pname
, parameters
->name
) == 0) {
295 errx(EXIT_FAILURE
, "no such parameter: %s", pname
);
297 for (int i
= 0; i
< argc
; i
++) {
298 if (strncmp(pname
, argv
[i
], len
) == 0) {
303 } else if (*v
== '\0')
305 "no value given for \"%s\" parameter",
311 arg
.v
= ptype_classes
[p
->type
].read(v
, &p
->defv
);
312 arg
.free
= ptype_classes
[p
->type
].free
;
316 static void free_arg(struct arg
*arg
)
322 const char *name
; /* [-a-zA-Z0-9_]+ */
324 bool priv
; /* the root privilege is needed to make fd(s) */
326 int N
; /* the number of fds this factory makes */
327 int EX_N
; /* fds made optionally */
328 int EX_R
; /* the number of extra words printed to stdout. */
329 void *(*make
)(const struct factory
*, struct fdesc
[], int, char **);
330 void (*free
)(const struct factory
*, void *);
331 void (*report
)(const struct factory
*, int, void *, FILE *);
332 const struct parameter
* params
;
335 static void close_fdesc(int fd
, void *data _U_
)
340 volatile ssize_t unused_result_ok
;
341 static void abort_with_child_death_message(int signum _U_
)
343 const char msg
[] = "the child process exits unexpectedly";
344 unused_result_ok
= write(2, msg
, sizeof(msg
));
348 static void *open_ro_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
349 int argc
, char ** argv
)
351 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
352 struct arg offset
= decode_arg("offset", factory
->params
, argc
, argv
);
353 struct arg lease_r
= decode_arg("read-lease", factory
->params
, argc
, argv
);
355 int fd
= open(ARG_STRING(file
), O_RDONLY
);
357 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(file
));
360 if (ARG_INTEGER(offset
) != 0) {
361 if (lseek(fd
, (off_t
)ARG_INTEGER(offset
), SEEK_CUR
) < 0) {
365 err(EXIT_FAILURE
, "failed to seek 0 -> %ld", ARG_INTEGER(offset
));
370 if (ARG_BOOLEAN(lease_r
)) {
371 if (fcntl(fd
, F_SETLEASE
, F_RDLCK
) < 0) {
375 err(EXIT_FAILURE
, "failed to take out a read lease");
380 if (fd
!= fdescs
[0].fd
) {
381 if (dup2(fd
, fdescs
[0].fd
) < 0) {
385 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
390 fdescs
[0] = (struct fdesc
){
392 .close
= close_fdesc
,
399 static void unlink_and_close_fdesc(int fd
, void *data
)
407 typedef void (*lockFn
)(int fd
, const char *fname
, int dupfd
);
409 static void lock_fn_none(int fd _U_
, const char *fname _U_
, int dupfd _U_
)
414 static void lock_fn_flock_sh(int fd
, const char *fname
, int dupfd
)
416 if (flock(fd
, LOCK_SH
) < 0) {
423 err(EXIT_FAILURE
, "failed to lock");
427 static void lock_fn_flock_ex(int fd
, const char *fname
, int dupfd
)
429 if (flock(fd
, LOCK_EX
) < 0) {
436 err(EXIT_FAILURE
, "failed to lock");
440 static void lock_fn_posix_r_(int fd
, const char *fname
, int dupfd
)
444 .l_whence
= SEEK_SET
,
448 if (fcntl(fd
, F_SETLK
, &r
) < 0) {
455 err(EXIT_FAILURE
, "failed to lock");
459 static void lock_fn_posix__w(int fd
, const char *fname
, int dupfd
)
463 .l_whence
= SEEK_SET
,
467 if (fcntl(fd
, F_SETLK
, &w
) < 0) {
474 err(EXIT_FAILURE
, "failed to lock");
478 static void lock_fn_posix_rw(int fd
, const char *fname
, int dupfd
)
482 .l_whence
= SEEK_SET
,
488 .l_whence
= SEEK_SET
,
492 if (fcntl(fd
, F_SETLK
, &r
) < 0) {
499 err(EXIT_FAILURE
, "failed to lock(read)");
501 if (fcntl(fd
, F_SETLK
, &w
) < 0) {
508 err(EXIT_FAILURE
, "failed to lock(write)");
513 static void lock_fn_ofd_r_(int fd
, const char *fname
, int dupfd
)
517 .l_whence
= SEEK_SET
,
522 if (fcntl(fd
, F_OFD_SETLK
, &r
) < 0) {
529 err(EXIT_FAILURE
, "failed to lock");
533 static void lock_fn_ofd__w(int fd
, const char *fname
, int dupfd
)
537 .l_whence
= SEEK_SET
,
542 if (fcntl(fd
, F_OFD_SETLK
, &w
) < 0) {
549 err(EXIT_FAILURE
, "failed to lock");
553 static void lock_fn_ofd_rw(int fd
, const char *fname
, int dupfd
)
557 .l_whence
= SEEK_SET
,
564 .l_whence
= SEEK_SET
,
569 if (fcntl(fd
, F_OFD_SETLK
, &r
) < 0) {
576 err(EXIT_FAILURE
, "failed to lock(read)");
578 if (fcntl(fd
, F_OFD_SETLK
, &w
) < 0) {
585 err(EXIT_FAILURE
, "failed to lock(write)");
588 #endif /* F_OFD_SETLK */
590 static void lock_fn_lease_w(int fd
, const char *fname
, int dupfd
)
592 if (fcntl(fd
, F_SETLEASE
, F_WRLCK
) < 0) {
599 err(EXIT_FAILURE
, "failed to take out a write lease");
604 static void *make_w_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
605 int argc
, char ** argv
)
609 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
610 char *fname
= xstrdup(ARG_STRING(file
));
612 struct arg
delete = decode_arg("delete", factory
->params
, argc
, argv
);
613 bool bDelete
= ARG_BOOLEAN(delete);
615 struct arg write_bytes
= decode_arg("write-bytes", factory
->params
, argc
, argv
);
616 int iWrite_bytes
= ARG_INTEGER(write_bytes
);
618 struct arg readable
= decode_arg("readable", factory
->params
, argc
, argv
);
619 bool bReadable
= ARG_BOOLEAN(readable
);
621 struct arg lock
= decode_arg("lock", factory
->params
, argc
, argv
);
622 const char *sLock
= ARG_STRING(lock
);
625 struct arg dupfd
= decode_arg("dupfd", factory
->params
, argc
, argv
);
626 int iDupfd
= ARG_INTEGER(dupfd
);
630 if (iWrite_bytes
< 0)
631 errx(EXIT_FAILURE
, "write-bytes must be a positive number or zero.");
633 if (strcmp(sLock
, "none") == 0)
634 lock_fn
= lock_fn_none
;
635 else if (strcmp(sLock
, "flock-sh") == 0)
636 lock_fn
= lock_fn_flock_sh
;
637 else if (strcmp(sLock
, "flock-ex") == 0)
638 lock_fn
= lock_fn_flock_ex
;
639 else if (strcmp(sLock
, "posix-r-") == 0) {
641 if (iWrite_bytes
< 1)
643 lock_fn
= lock_fn_posix_r_
;
644 } else if (strcmp(sLock
, "posix--w") == 0) {
645 if (iWrite_bytes
< 1)
647 lock_fn
= lock_fn_posix__w
;
648 } else if (strcmp(sLock
, "posix-rw") == 0) {
650 if (iWrite_bytes
< 3)
652 lock_fn
= lock_fn_posix_rw
;
654 } else if (strcmp(sLock
, "ofd-r-") == 0) {
656 if (iWrite_bytes
< 1)
658 lock_fn
= lock_fn_ofd_r_
;
659 } else if (strcmp(sLock
, "ofd--w") == 0) {
660 if (iWrite_bytes
< 1)
662 lock_fn
= lock_fn_ofd__w
;
663 } else if (strcmp(sLock
, "ofd-rw") == 0) {
665 if (iWrite_bytes
< 3)
667 lock_fn
= lock_fn_ofd_rw
;
669 } else if (strcmp(sLock
, "ofd-r-") == 0
670 || strcmp(sLock
, "ofd--w") == 0
671 || strcmp(sLock
, "ofd-rw") == 0) {
672 errx(EXIT_ENOSYS
, "no availability for ofd lock");
673 #endif /* F_OFD_SETLK */
674 } else if (strcmp(sLock
, "lease-w") == 0)
675 lock_fn
= lock_fn_lease_w
;
677 errx(EXIT_FAILURE
, "unexpected value for lock parameter: %s", sLock
);
682 free_arg(&write_bytes
);
686 fd
= open(fname
, O_CREAT
|O_EXCL
|(bReadable
? O_RDWR
: O_WRONLY
), S_IWUSR
);
688 err(EXIT_FAILURE
, "failed to make: %s", fname
);
690 if (fd
!= fdescs
[0].fd
) {
691 if (dup2(fd
, fdescs
[0].fd
) < 0) {
697 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
704 if (unlink(fname
) < 0) {
708 err(EXIT_FAILURE
, "failed to unlink %s", fname
);
714 for (int i
= 0; i
< iWrite_bytes
; i
++) {
715 if (write(fd
, "z", 1) != 1) {
721 err(EXIT_FAILURE
, "failed to write");
726 if (dup2(fd
, iDupfd
) < 0) {
732 err(EXIT_FAILURE
, "failed in dup2");
734 data
= xmalloc(sizeof(iDupfd
));
735 *((int *)data
) = iDupfd
;
738 lock_fn(fd
, fname
, iDupfd
);
740 fdescs
[0] = (struct fdesc
){
742 .close
= bDelete
? close_fdesc
: unlink_and_close_fdesc
,
749 static void free_after_closing_duplicated_fd(const struct factory
* factory _U_
, void *data
)
758 static void *make_pipe(const struct factory
*factory
, struct fdesc fdescs
[],
759 int argc
, char ** argv
)
762 int nonblock_flags
[2] = {0, 0};
763 struct arg nonblock
= decode_arg("nonblock", factory
->params
, argc
, argv
);
764 if (strlen(ARG_STRING(nonblock
)) != 2) {
765 errx(EXIT_FAILURE
, "string value for %s has unexpected length: %s",
766 "nonblock", ARG_STRING(nonblock
));
769 /* Make extra pipe descriptors for making pipe objects connected
770 * with fds more than 2.
771 * See https://github.com/util-linux/util-linux/pull/1622
772 * about the background of the requirement. */
773 struct arg rdup
= decode_arg("rdup", factory
->params
, argc
, argv
);
774 struct arg wdup
= decode_arg("wdup", factory
->params
, argc
, argv
);
776 xpd
[0] = ARG_INTEGER(rdup
);
777 xpd
[1] = ARG_INTEGER(wdup
);
779 for (int i
= 0; i
< 2; i
++) {
780 if (ARG_STRING(nonblock
)[i
] == '-')
782 if ((i
== 0 && ARG_STRING(nonblock
)[i
] == 'r')
783 || (i
== 1 && ARG_STRING(nonblock
)[i
] == 'w'))
784 nonblock_flags
[i
] = 1;
786 errx(EXIT_FAILURE
, "unexpected value %c for the %s fd of %s",
787 ARG_STRING(nonblock
)[i
],
788 (i
== 0)? "read": "write",
794 err(EXIT_FAILURE
, "failed to make pipe");
796 for (int i
= 0; i
< 2; i
++) {
797 if (nonblock_flags
[i
]) {
798 int flags
= fcntl(pd
[i
], F_GETFL
);
799 if (fcntl(pd
[i
], F_SETFL
, flags
|O_NONBLOCK
) < 0) {
804 errx(EXIT_FAILURE
, "failed to set NONBLOCK flag to the %s fd",
805 (i
== 0)? "read": "write");
810 for (int i
= 0; i
< 2; i
++) {
811 if (pd
[i
] != fdescs
[i
].fd
) {
812 if (dup2(pd
[i
], fdescs
[i
].fd
) < 0) {
817 err(EXIT_FAILURE
, "failed to dup %d -> %d",
818 pd
[i
], fdescs
[i
].fd
);
822 fdescs
[i
] = (struct fdesc
){
824 .close
= close_fdesc
,
829 /* Make extra pipe descriptors. */
830 for (int i
= 0; i
< 2; i
++) {
832 if (dup2(fdescs
[i
].fd
, xpd
[i
]) < 0) {
836 if (i
> 0 && xpd
[0] >= 0)
839 err(EXIT_FAILURE
, "failed to dup %d -> %d",
840 fdescs
[i
].fd
, xpd
[i
]);
842 fdescs
[i
+ 2] = (struct fdesc
){
844 .close
= close_fdesc
,
853 static void close_dir(int fd
, void *data
)
859 close_fdesc(fd
, NULL
);
862 static void *open_directory(const struct factory
*factory
, struct fdesc fdescs
[],
863 int argc
, char ** argv
)
865 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
866 struct arg dentries
= decode_arg("dentries", factory
->params
, argc
, argv
);
869 int fd
= open(ARG_STRING(dir
), O_RDONLY
|O_DIRECTORY
);
871 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(dir
));
874 if (fd
!= fdescs
[0].fd
) {
875 if (dup2(fd
, fdescs
[0].fd
) < 0) {
879 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
884 if (ARG_INTEGER(dentries
) > 0) {
885 dp
= fdopendir(fdescs
[0].fd
);
890 err(EXIT_FAILURE
, "failed to make DIR* from fd: %s", ARG_STRING(dir
));
892 for (int i
= 0; i
< ARG_INTEGER(dentries
); i
++) {
893 struct dirent
*d
= readdir(dp
);
898 err(EXIT_FAILURE
, "failed in readdir(3)");
904 fdescs
[0] = (struct fdesc
){
913 static void *open_rw_chrdev(const struct factory
*factory
, struct fdesc fdescs
[],
914 int argc
, char ** argv
)
916 struct arg chrdev
= decode_arg("chrdev", factory
->params
, argc
, argv
);
917 int fd
= open(ARG_STRING(chrdev
), O_RDWR
);
919 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(chrdev
));
922 if (fd
!= fdescs
[0].fd
) {
923 if (dup2(fd
, fdescs
[0].fd
) < 0) {
927 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
932 fdescs
[0] = (struct fdesc
){
934 .close
= close_fdesc
,
941 static void *make_socketpair(const struct factory
*factory
, struct fdesc fdescs
[],
942 int argc
, char ** argv
)
945 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
947 struct arg halfclose
= decode_arg("halfclose", factory
->params
, argc
, argv
);
950 bhalfclose
= ARG_BOOLEAN(halfclose
);
951 free_arg(&halfclose
);
953 if (strcmp(ARG_STRING(socktype
), "STREAM") == 0)
954 isocktype
= SOCK_STREAM
;
955 else if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
956 isocktype
= SOCK_DGRAM
;
957 else if (strcmp(ARG_STRING(socktype
), "SEQPACKET") == 0)
958 isocktype
= SOCK_SEQPACKET
;
961 "unknown socket type for socketpair(AF_UNIX,...): %s",
962 ARG_STRING(socktype
));
965 if (socketpair(AF_UNIX
, isocktype
, 0, sd
) < 0)
966 err(EXIT_FAILURE
, "failed to make socket pair");
969 if (shutdown(sd
[0], SHUT_RD
) < 0)
971 "failed to shutdown the read end of the 1st socket");
972 if (shutdown(sd
[1], SHUT_WR
) < 0)
974 "failed to shutdown the write end of the 2nd socket");
977 for (int i
= 0; i
< 2; i
++) {
978 if (sd
[i
] != fdescs
[i
].fd
) {
979 if (dup2(sd
[i
], fdescs
[i
].fd
) < 0) {
984 err(EXIT_FAILURE
, "failed to dup %d -> %d",
985 sd
[i
], fdescs
[i
].fd
);
989 fdescs
[i
] = (struct fdesc
){
991 .close
= close_fdesc
,
999 static void *open_with_opath(const struct factory
*factory
, struct fdesc fdescs
[],
1000 int argc
, char ** argv
)
1002 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1003 int fd
= open(ARG_STRING(path
), O_PATH
|O_NOFOLLOW
);
1005 err(EXIT_FAILURE
, "failed to open with O_PATH: %s", ARG_STRING(path
));
1008 if (fd
!= fdescs
[0].fd
) {
1009 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1013 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1018 fdescs
[0] = (struct fdesc
){
1020 .close
= close_fdesc
,
1027 static void *open_ro_blkdev(const struct factory
*factory
, struct fdesc fdescs
[],
1028 int argc
, char ** argv
)
1030 struct arg blkdev
= decode_arg("blkdev", factory
->params
, argc
, argv
);
1031 int fd
= open(ARG_STRING(blkdev
), O_RDONLY
);
1033 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(blkdev
));
1036 if (fd
!= fdescs
[0].fd
) {
1037 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1041 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1046 fdescs
[0] = (struct fdesc
){
1048 .close
= close_fdesc
,
1055 static int make_packet_socket(int socktype
, const char *interface
)
1058 struct sockaddr_ll addr
;
1060 sd
= socket(AF_PACKET
, socktype
, htons(ETH_P_ALL
));
1062 err(EXIT_FAILURE
, "failed to make a socket with AF_PACKET");
1064 if (interface
== NULL
)
1065 return sd
; /* Just making a socket */
1067 memset(&addr
, 0, sizeof(struct sockaddr_ll
));
1068 addr
.sll_family
= AF_PACKET
;
1069 addr
.sll_ifindex
= if_nametoindex(interface
);
1070 if (addr
.sll_ifindex
== 0) {
1075 "failed to get the interface index for %s", interface
);
1077 if (bind(sd
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_ll
)) < 0) {
1082 "failed to get the interface index for %s", interface
);
1088 struct munmap_data
{
1093 static void close_fdesc_after_munmap(int fd
, void *data
)
1095 struct munmap_data
*munmap_data
= data
;
1096 munmap(munmap_data
->ptr
, munmap_data
->len
);
1101 static void *make_mmapped_packet_socket(const struct factory
*factory
, struct fdesc fdescs
[],
1102 int argc
, char ** argv
)
1105 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
1106 struct arg interface
= decode_arg("interface", factory
->params
, argc
, argv
);
1109 const char *sinterface
;
1110 struct tpacket_req req
;
1111 struct munmap_data
*munmap_data
;
1113 if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
1114 isocktype
= SOCK_DGRAM
;
1115 else if (strcmp(ARG_STRING(socktype
), "RAW") == 0)
1116 isocktype
= SOCK_RAW
;
1119 "unknown socket type for socket(AF_PACKET,...): %s",
1120 ARG_STRING(socktype
));
1121 free_arg(&socktype
);
1123 sinterface
= ARG_STRING(interface
);
1124 sd
= make_packet_socket(isocktype
, sinterface
);
1125 free_arg(&interface
);
1127 /* Specify the spec of ring buffers.
1130 * - linux/Documentation/networking/packet_mmap.rst
1131 * - https://sites.google.com/site/packetmmap/home
1133 req
.tp_block_size
= getpagesize();
1134 req
.tp_frame_size
= getpagesize();
1135 req
.tp_block_nr
= 1;
1136 req
.tp_frame_nr
= 1;
1137 if (setsockopt(sd
, SOL_PACKET
, PACKET_TX_RING
, (char *)&req
, sizeof(req
)) < 0) {
1141 err((errno
== ENOPROTOOPT
? EXIT_ENOPROTOOPT
: EXIT_FAILURE
),
1142 "failed to specify a buffer spec to a packet socket");
1145 munmap_data
= xmalloc(sizeof(*munmap_data
));
1146 munmap_data
->len
= (size_t) req
.tp_block_size
* req
.tp_block_nr
;
1147 munmap_data
->ptr
= mmap(NULL
, munmap_data
->len
, PROT_WRITE
, MAP_SHARED
, sd
, 0);
1148 if (munmap_data
->ptr
== MAP_FAILED
) {
1153 err(EXIT_FAILURE
, "failed to do mmap a packet socket");
1156 if (sd
!= fdescs
[0].fd
) {
1157 if (dup2(sd
, fdescs
[0].fd
) < 0) {
1160 munmap(munmap_data
->ptr
, munmap_data
->len
);
1163 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
1168 fdescs
[0] = (struct fdesc
){
1170 .close
= close_fdesc_after_munmap
,
1171 .data
= munmap_data
,
1177 static void *make_pidfd(const struct factory
*factory
, struct fdesc fdescs
[],
1178 int argc
, char ** argv
)
1180 struct arg target_pid
= decode_arg("target-pid", factory
->params
, argc
, argv
);
1181 pid_t pid
= ARG_INTEGER(target_pid
);
1183 int fd
= pidfd_open(pid
, 0);
1185 err_nosys(EXIT_FAILURE
, "failed in pidfd_open(%d)", (int)pid
);
1186 free_arg(&target_pid
);
1188 if (fd
!= fdescs
[0].fd
) {
1189 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1193 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1198 fdescs
[0] = (struct fdesc
){
1200 .close
= close_fdesc
,
1207 static void *make_inotify_fd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
1208 int argc _U_
, char ** argv _U_
)
1210 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
1211 const char *sdir
= ARG_STRING(dir
);
1212 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
1213 const char *sfile
= ARG_STRING(file
);
1215 int fd
= inotify_init();
1217 err(EXIT_FAILURE
, "failed in inotify_init()");
1219 if (inotify_add_watch(fd
, sdir
, IN_DELETE
) < 0) {
1223 err(EXIT_FAILURE
, "failed in inotify_add_watch(\"%s\")", sdir
);
1227 if (inotify_add_watch(fd
, sfile
, IN_DELETE
) < 0) {
1231 err(EXIT_FAILURE
, "failed in inotify_add_watch(\"%s\")", sfile
);
1235 if (fd
!= fdescs
[0].fd
) {
1236 if (dup2(fd
, fdescs
[0].fd
) < 0) {
1240 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
1245 fdescs
[0] = (struct fdesc
){
1247 .close
= close_fdesc
,
1254 static void close_unix_socket(int fd
, void *data
)
1264 static void *make_unix_stream_core(const struct factory
*factory
, struct fdesc fdescs
[],
1265 int argc
, char ** argv
, int type
, const char *typestr
)
1267 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1268 const char *spath
= ARG_STRING(path
);
1270 struct arg backlog
= decode_arg("backlog", factory
->params
, argc
, argv
);
1271 int ibacklog
= ARG_INTEGER(path
);
1273 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1274 bool babstract
= ARG_BOOLEAN(abstract
);
1276 struct arg server_shutdown
= decode_arg("server-shutdown", factory
->params
, argc
, argv
);
1277 int iserver_shutdown
= ARG_INTEGER(server_shutdown
);
1278 struct arg client_shutdown
= decode_arg("client-shutdown", factory
->params
, argc
, argv
);
1279 int iclient_shutdown
= ARG_INTEGER(client_shutdown
);
1281 int ssd
, csd
, asd
; /* server, client, and accepted socket descriptors */
1282 struct sockaddr_un un
;
1283 size_t un_len
= sizeof(un
);
1285 memset(&un
, 0, sizeof(un
));
1286 un
.sun_family
= AF_UNIX
;
1288 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1289 size_t pathlen
= strlen(spath
);
1290 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1291 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1293 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1295 free_arg(&client_shutdown
);
1296 free_arg(&server_shutdown
);
1297 free_arg(&abstract
);
1301 if (iserver_shutdown
< 0 || iserver_shutdown
> 3)
1302 errx(EXIT_FAILURE
, "the server shudown specification in unexpected range");
1303 if (iclient_shutdown
< 0 || iclient_shutdown
> 3)
1304 errx(EXIT_FAILURE
, "the client shudown specification in unexpected range");
1306 ssd
= socket(AF_UNIX
, type
, 0);
1309 "failed to make a socket with AF_UNIX + SOCK_%s (server side)", typestr
);
1310 if (ssd
!= fdescs
[0].fd
) {
1311 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1315 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1321 fdescs
[0] = (struct fdesc
){
1323 .close
= close_unix_socket
,
1328 unlink(un
.sun_path
);
1329 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1333 err(EXIT_FAILURE
, "failed to bind a socket for listening");
1337 fdescs
[0].data
= xstrdup(un
.sun_path
);
1338 if (listen(ssd
, ibacklog
) < 0) {
1340 close_unix_socket(ssd
, fdescs
[0].data
);
1342 err(EXIT_FAILURE
, "failed to listen a socket");
1345 csd
= socket(AF_UNIX
, type
, 0);
1348 "failed to make a socket with AF_UNIX + SOCK_%s (client side)", typestr
);
1349 if (csd
!= fdescs
[1].fd
) {
1350 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1353 close_unix_socket(ssd
, fdescs
[0].data
);
1355 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1361 fdescs
[1] = (struct fdesc
){
1363 .close
= close_fdesc
,
1367 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1369 close_fdesc(csd
, NULL
);
1370 close_unix_socket(ssd
, fdescs
[0].data
);
1372 err(EXIT_FAILURE
, "failed to connect a socket to the listening socket");
1376 unlink(un
.sun_path
);
1378 asd
= accept(ssd
, NULL
, NULL
);
1381 close_fdesc(csd
, NULL
);
1382 close_unix_socket(ssd
, fdescs
[0].data
);
1384 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1386 if (asd
!= fdescs
[2].fd
) {
1387 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1390 close_fdesc(csd
, NULL
);
1391 close_unix_socket(ssd
, fdescs
[0].data
);
1393 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1399 if (iserver_shutdown
& (1 << 0))
1400 shutdown(asd
, SHUT_RD
);
1401 if (iserver_shutdown
& (1 << 1))
1402 shutdown(asd
, SHUT_WR
);
1403 if (iclient_shutdown
& (1 << 0))
1404 shutdown(csd
, SHUT_RD
);
1405 if (iclient_shutdown
& (1 << 1))
1406 shutdown(csd
, SHUT_WR
);
1411 static void *make_unix_stream(const struct factory
*factory
, struct fdesc fdescs
[],
1412 int argc
, char ** argv
)
1414 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1415 const char *stype
= ARG_STRING(type
);
1418 const char *typestr
;
1420 if (strcmp(stype
, "stream") == 0) {
1421 typesym
= SOCK_STREAM
;
1423 } else if (strcmp(stype
, "seqpacket") == 0) {
1424 typesym
= SOCK_SEQPACKET
;
1425 typestr
= "SEQPACKET";
1427 errx(EXIT_FAILURE
, "unknown unix socket type: %s", stype
);
1431 return make_unix_stream_core(factory
, fdescs
, argc
, argv
, typesym
, typestr
);
1434 static void *make_unix_dgram(const struct factory
*factory
, struct fdesc fdescs
[],
1435 int argc
, char ** argv
)
1437 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1438 const char *spath
= ARG_STRING(path
);
1440 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1441 bool babstract
= ARG_BOOLEAN(abstract
);
1443 int ssd
, csd
; /* server and client socket descriptors */
1445 struct sockaddr_un un
;
1446 size_t un_len
= sizeof(un
);
1448 memset(&un
, 0, sizeof(un
));
1449 un
.sun_family
= AF_UNIX
;
1451 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1452 size_t pathlen
= strlen(spath
);
1453 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1454 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1456 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1458 free_arg(&abstract
);
1461 ssd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1464 "failed to make a socket with AF_UNIX + SOCK_DGRAM (server side)");
1465 if (ssd
!= fdescs
[0].fd
) {
1466 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1470 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1476 fdescs
[0] = (struct fdesc
){
1478 .close
= close_unix_socket
,
1483 unlink(un
.sun_path
);
1484 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1488 err(EXIT_FAILURE
, "failed to bind a socket for server");
1492 fdescs
[0].data
= xstrdup(un
.sun_path
);
1493 csd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1496 "failed to make a socket with AF_UNIX + SOCK_DGRAM (client side)");
1497 if (csd
!= fdescs
[1].fd
) {
1498 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1501 close_unix_socket(ssd
, fdescs
[0].data
);
1503 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1509 fdescs
[1] = (struct fdesc
){
1511 .close
= close_fdesc
,
1515 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1517 close_fdesc(csd
, NULL
);
1518 close_unix_socket(ssd
, fdescs
[0].data
);
1520 err(EXIT_FAILURE
, "failed to connect a socket to the server socket");
1524 unlink(un
.sun_path
);
1529 static void *make_unix_in_new_netns(const struct factory
*factory
, struct fdesc fdescs
[],
1530 int argc
, char ** argv
)
1532 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1533 const char *stype
= ARG_STRING(type
);
1535 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1536 const char *spath
= ARG_STRING(path
);
1538 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1539 bool babstract
= ARG_BOOLEAN(abstract
);
1542 const char *typestr
;
1544 struct sockaddr_un un
;
1545 size_t un_len
= sizeof(un
);
1547 int self_netns
, tmp_netns
, sd
;
1549 if (strcmp(stype
, "stream") == 0) {
1550 typesym
= SOCK_STREAM
;
1552 } else if (strcmp(stype
, "seqpacket") == 0) {
1553 typesym
= SOCK_SEQPACKET
;
1554 typestr
= "SEQPACKET";
1555 } else if (strcmp(stype
, "dgram") == 0) {
1556 typesym
= SOCK_DGRAM
;
1559 free_arg(&abstract
);
1562 errx(EXIT_FAILURE
, "unknown unix socket type: %s", stype
);
1565 memset(&un
, 0, sizeof(un
));
1566 un
.sun_family
= AF_UNIX
;
1568 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1569 size_t pathlen
= strlen(spath
);
1570 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1571 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1573 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1575 free_arg(&abstract
);
1579 self_netns
= open("/proc/self/ns/net", O_RDONLY
);
1581 err(EXIT_FAILURE
, "failed to open /proc/self/ns/net");
1582 if (self_netns
!= fdescs
[0].fd
) {
1583 if (dup2(self_netns
, fdescs
[0].fd
) < 0) {
1587 err(EXIT_FAILURE
, "failed to dup %d -> %d", self_netns
, fdescs
[0].fd
);
1590 self_netns
= fdescs
[0].fd
;
1593 fdescs
[0] = (struct fdesc
){
1595 .close
= close_fdesc
,
1599 if (unshare(CLONE_NEWNET
) < 0) {
1601 close_fdesc(self_netns
, NULL
);
1603 err((errno
== EPERM
? EXIT_EPERM
: EXIT_FAILURE
),
1604 "failed in unshare");
1607 tmp_netns
= open("/proc/self/ns/net", O_RDONLY
);
1608 if (tmp_netns
< 0) {
1610 close_fdesc(self_netns
, NULL
);
1612 err(EXIT_FAILURE
, "failed to open /proc/self/ns/net for the new netns");
1614 if (tmp_netns
!= fdescs
[1].fd
) {
1615 if (dup2(tmp_netns
, fdescs
[1].fd
) < 0) {
1617 close_fdesc(self_netns
, NULL
);
1620 err(EXIT_FAILURE
, "failed to dup %d -> %d", tmp_netns
, fdescs
[1].fd
);
1623 tmp_netns
= fdescs
[1].fd
;
1626 fdescs
[1] = (struct fdesc
){
1628 .close
= close_fdesc
,
1632 sd
= socket(AF_UNIX
, typesym
, 0);
1635 close_fdesc(self_netns
, NULL
);
1636 close_fdesc(tmp_netns
, NULL
);
1639 "failed to make a socket with AF_UNIX + SOCK_%s",
1643 if (sd
!= fdescs
[2].fd
) {
1644 if (dup2(sd
, fdescs
[2].fd
) < 0) {
1646 close_fdesc(self_netns
, NULL
);
1647 close_fdesc(tmp_netns
, NULL
);
1650 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[2].fd
);
1656 fdescs
[2] = (struct fdesc
){
1658 .close
= close_unix_socket
,
1663 unlink(un
.sun_path
);
1664 if (bind(sd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1666 close_fdesc(self_netns
, NULL
);
1667 close_fdesc(tmp_netns
, NULL
);
1668 close_unix_socket(sd
, NULL
);
1670 err(EXIT_FAILURE
, "failed to bind a socket");
1674 fdescs
[2].data
= xstrdup(un
.sun_path
);
1676 if (typesym
!= SOCK_DGRAM
) {
1677 if (listen(sd
, 1) < 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 listen a socket");
1687 if (setns(self_netns
, CLONE_NEWNET
) < 0) {
1689 close_fdesc(self_netns
, NULL
);
1690 close_fdesc(tmp_netns
, NULL
);
1691 close_unix_socket(sd
, fdescs
[2].data
);
1693 err(EXIT_FAILURE
, "failed to swich back to the original net namespace");
1699 static void *make_tcp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1700 int argc
, char ** argv
,
1702 void (*init_addr
)(struct sockaddr
*, unsigned short),
1704 struct sockaddr
* sin
, struct sockaddr
* cin
)
1706 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1707 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1708 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1709 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1715 free_arg(&server_port
);
1716 free_arg(&client_port
);
1718 ssd
= socket(family
, SOCK_STREAM
, 0);
1721 "failed to make a tcp socket for listening");
1723 if (setsockopt(ssd
, SOL_SOCKET
,
1724 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1728 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1731 if (ssd
!= fdescs
[0].fd
) {
1732 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1736 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1742 init_addr(sin
, iserver_port
);
1743 if (bind(ssd
, sin
, addr_size
) < 0) {
1747 err(EXIT_FAILURE
, "failed to bind a listening socket");
1750 if (listen(ssd
, 1) < 0) {
1754 err(EXIT_FAILURE
, "failed to listen a socket");
1757 csd
= socket(family
, SOCK_STREAM
, 0);
1763 "failed to make a tcp client socket");
1766 if (setsockopt(csd
, SOL_SOCKET
,
1767 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1772 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1775 if (csd
!= fdescs
[1].fd
) {
1776 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1781 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1787 init_addr(cin
, iclient_port
);
1788 if (bind(csd
, cin
, addr_size
) < 0) {
1793 err(EXIT_FAILURE
, "failed to bind a client socket");
1796 if (connect(csd
, sin
, addr_size
) < 0) {
1801 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1804 asd
= accept(ssd
, NULL
, NULL
);
1810 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1812 if (asd
!= fdescs
[2].fd
) {
1813 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1818 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1824 fdescs
[0] = (struct fdesc
) {
1826 .close
= close_fdesc
,
1829 fdescs
[1] = (struct fdesc
) {
1831 .close
= close_fdesc
,
1834 fdescs
[2] = (struct fdesc
) {
1836 .close
= close_fdesc
,
1843 static void tcp_init_addr(struct sockaddr
*addr
, unsigned short port
)
1845 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
1846 memset(in
, 0, sizeof(*in
));
1847 in
->sin_family
= AF_INET
;
1848 in
->sin_port
= htons(port
);
1849 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1852 static void *make_tcp(const struct factory
*factory
, struct fdesc fdescs
[],
1853 int argc
, char ** argv
)
1855 struct sockaddr_in sin
, cin
;
1856 return make_tcp_common(factory
, fdescs
, argc
, argv
,
1858 tcp_init_addr
, sizeof(sin
),
1859 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1862 static void *make_udp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1863 int argc
, char ** argv
,
1865 void (*init_addr
)(struct sockaddr
*, unsigned short),
1867 struct sockaddr
* sin
, struct sockaddr
* cin
)
1869 struct arg lite
= decode_arg("lite", factory
->params
, argc
, argv
);
1870 bool blite
= ARG_BOOLEAN(lite
);
1872 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1873 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1874 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1875 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1877 struct arg server_do_bind
= decode_arg("server-do-bind", factory
->params
, argc
, argv
);
1878 bool bserver_do_bind
= ARG_BOOLEAN(server_do_bind
);
1879 struct arg client_do_bind
= decode_arg("client-do-bind", factory
->params
, argc
, argv
);
1880 bool bclient_do_bind
= ARG_BOOLEAN(client_do_bind
);
1881 struct arg client_do_connect
= decode_arg("client-do-connect", factory
->params
, argc
, argv
);
1882 bool bclient_do_connect
= ARG_BOOLEAN(client_do_connect
);
1888 free_arg(&client_do_connect
);
1889 free_arg(&client_do_bind
);
1890 free_arg(&server_do_bind
);
1891 free_arg(&server_port
);
1892 free_arg(&client_port
);
1895 ssd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1898 "failed to make a udp socket for server");
1900 if (setsockopt(ssd
, SOL_SOCKET
,
1901 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1905 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1908 if (ssd
!= fdescs
[0].fd
) {
1909 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1913 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1919 init_addr(sin
, iserver_port
);
1920 if (bserver_do_bind
) {
1921 if (bind(ssd
, sin
, addr_size
) < 0) {
1925 err(EXIT_FAILURE
, "failed to bind a server socket");
1929 csd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1935 "failed to make a udp client socket");
1938 if (setsockopt(csd
, SOL_SOCKET
,
1939 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1944 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1947 if (csd
!= fdescs
[1].fd
) {
1948 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1953 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1959 if (bclient_do_bind
) {
1960 init_addr(cin
, iclient_port
);
1961 if (bind(csd
, cin
, addr_size
) < 0) {
1966 err(EXIT_FAILURE
, "failed to bind a client socket");
1970 if (bclient_do_connect
) {
1971 if (connect(csd
, sin
, addr_size
) < 0) {
1976 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1980 fdescs
[0] = (struct fdesc
) {
1982 .close
= close_fdesc
,
1985 fdescs
[1] = (struct fdesc
) {
1987 .close
= close_fdesc
,
1994 static void *make_udp(const struct factory
*factory
, struct fdesc fdescs
[],
1995 int argc
, char ** argv
)
1997 struct sockaddr_in sin
, cin
;
1998 return make_udp_common(factory
, fdescs
, argc
, argv
,
2000 tcp_init_addr
, sizeof(sin
),
2001 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2004 static void *make_raw_common(const struct factory
*factory
, struct fdesc fdescs
[],
2005 int argc
, char ** argv
,
2007 void (*init_addr
)(struct sockaddr
*, bool),
2009 struct sockaddr
* sin
)
2011 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
2012 int iprotocol
= ARG_INTEGER(protocol
);
2015 free_arg(&protocol
);
2017 ssd
= socket(family
, SOCK_RAW
, iprotocol
);
2020 "failed to make a udp socket for server");
2022 if (ssd
!= fdescs
[0].fd
) {
2023 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
2027 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
2033 init_addr(sin
, false);
2034 if (bind(ssd
, sin
, addr_size
) < 0) {
2038 err(EXIT_FAILURE
, "failed in bind(2)");
2041 init_addr(sin
, true);
2042 if (connect(ssd
, sin
, addr_size
) < 0) {
2046 err(EXIT_FAILURE
, "failed in connect(2)");
2049 fdescs
[0] = (struct fdesc
) {
2051 .close
= close_fdesc
,
2058 static void raw_init_addr(struct sockaddr
* addr
, bool remote_addr
)
2060 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
2061 memset(in
, 0, sizeof(*in
));
2062 in
->sin_family
= AF_INET
;
2063 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
+ (remote_addr
? 1: 0));
2066 static void *make_raw(const struct factory
*factory
, struct fdesc fdescs
[],
2067 int argc
, char ** argv
)
2069 struct sockaddr_in sin
;
2070 return make_raw_common(factory
, fdescs
, argc
, argv
,
2072 raw_init_addr
, sizeof(sin
),
2073 (struct sockaddr
*)&sin
);
2076 static void *make_ping_common(const struct factory
*factory
, struct fdesc fdescs
[],
2077 int argc
, char ** argv
,
2078 int family
, int protocol
,
2079 void (*init_addr
)(struct sockaddr
*, unsigned short),
2081 struct sockaddr
*sin
)
2083 struct arg connect_
= decode_arg("connect", factory
->params
, argc
, argv
);
2084 bool bconnect
= ARG_BOOLEAN(connect_
);
2086 struct arg bind_
= decode_arg("bind", factory
->params
, argc
, argv
);
2087 bool bbind
= ARG_BOOLEAN(bind_
);
2089 struct arg id
= decode_arg("id", factory
->params
, argc
, argv
);
2090 unsigned short iid
= (unsigned short)ARG_INTEGER(id
);
2096 free_arg(&connect_
);
2098 sd
= socket(family
, SOCK_DGRAM
, protocol
);
2100 err((errno
== EACCES
? EXIT_EACCESS
: EXIT_FAILURE
),
2101 "failed to make an icmp socket");
2103 if (sd
!= fdescs
[0].fd
) {
2104 if (dup2(sd
, fdescs
[0].fd
) < 0) {
2108 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
2115 init_addr(sin
, iid
);
2116 if (bind(sd
, sin
, addr_size
) < 0) {
2120 err((errno
== EACCES
? EXIT_EACCESS
: EXIT_FAILURE
),
2121 "failed in bind(2)");
2127 if (connect(sd
, sin
, addr_size
) < 0) {
2131 err(EXIT_FAILURE
, "failed in connect(2)");
2135 fdescs
[0] = (struct fdesc
) {
2137 .close
= close_fdesc
,
2144 static void ping_init_addr(struct sockaddr
*addr
, unsigned short id
)
2146 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
2147 memset(in
, 0, sizeof(*in
));
2148 in
->sin_family
= AF_INET
;
2149 in
->sin_port
= htons(id
);
2150 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2153 static void *make_ping(const struct factory
*factory
, struct fdesc fdescs
[],
2154 int argc
, char ** argv
)
2156 struct sockaddr_in in
;
2157 return make_ping_common(factory
, fdescs
, argc
, argv
,
2158 AF_INET
, IPPROTO_ICMP
,
2161 (struct sockaddr
*)&in
);
2164 static void tcp6_init_addr(struct sockaddr
*addr
, unsigned short port
)
2166 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2167 memset(in6
, 0, sizeof(*in6
));
2168 in6
->sin6_family
= AF_INET6
;
2169 in6
->sin6_flowinfo
= 0;
2170 in6
->sin6_port
= htons(port
);
2171 in6
->sin6_addr
= in6addr_loopback
;
2174 static void *make_tcp6(const struct factory
*factory
, struct fdesc fdescs
[],
2175 int argc
, char ** argv
)
2177 struct sockaddr_in6 sin
, cin
;
2178 return make_tcp_common(factory
, fdescs
, argc
, argv
,
2180 tcp6_init_addr
, sizeof(sin
),
2181 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2184 static void *make_udp6(const struct factory
*factory
, struct fdesc fdescs
[],
2185 int argc
, char ** argv
)
2187 struct sockaddr_in6 sin
, cin
;
2188 return make_udp_common(factory
, fdescs
, argc
, argv
,
2190 tcp6_init_addr
, sizeof(sin
),
2191 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
2194 static void raw6_init_addr(struct sockaddr
*addr
, bool remote_addr
)
2196 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2197 memset(in6
, 0, sizeof(*in6
));
2198 in6
->sin6_family
= AF_INET6
;
2199 in6
->sin6_flowinfo
= 0;
2202 /* ::ffff:127.0.0.1 */
2203 in6
->sin6_addr
.s6_addr16
[5] = 0xffff;
2204 in6
->sin6_addr
.s6_addr32
[3] = htonl(INADDR_LOOPBACK
);
2206 in6
->sin6_addr
= in6addr_loopback
;
2209 static void *make_raw6(const struct factory
*factory
, struct fdesc fdescs
[],
2210 int argc
, char ** argv
)
2212 struct sockaddr_in6 sin
;
2213 return make_raw_common(factory
, fdescs
, argc
, argv
,
2215 raw6_init_addr
, sizeof(sin
),
2216 (struct sockaddr
*)&sin
);
2219 static void ping6_init_addr(struct sockaddr
*addr
, unsigned short id
)
2221 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
2222 memset(in6
, 0, sizeof(*in6
));
2223 in6
->sin6_family
= AF_INET6
;
2224 in6
->sin6_port
= htons(id
);
2225 in6
->sin6_addr
= in6addr_loopback
;
2228 static void *make_ping6(const struct factory
*factory
, struct fdesc fdescs
[],
2229 int argc
, char ** argv
)
2231 struct sockaddr_in6 in6
;
2232 return make_ping_common(factory
, fdescs
, argc
, argv
,
2233 AF_INET6
, IPPROTO_ICMPV6
,
2236 (struct sockaddr
*)&in6
);
2240 static void *make_netns(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2241 int argc _U_
, char ** argv _U_
)
2243 int sd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
2245 err(EXIT_FAILURE
, "failed in socket()");
2247 int ns
= ioctl(sd
, SIOCGSKNS
);
2249 err_nosys(EXIT_FAILURE
, "failed in ioctl(SIOCGSKNS)");
2252 if (ns
!= fdescs
[0].fd
) {
2253 if (dup2(ns
, fdescs
[0].fd
) < 0) {
2257 err(EXIT_FAILURE
, "failed to dup %d -> %d", ns
, fdescs
[0].fd
);
2262 fdescs
[0] = (struct fdesc
){
2264 .close
= close_fdesc
,
2270 #endif /* SIOCGSKNS */
2272 static void *make_netlink(const struct factory
*factory
, struct fdesc fdescs
[],
2273 int argc
, char ** argv
)
2275 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
2276 int iprotocol
= ARG_INTEGER(protocol
);
2277 struct arg groups
= decode_arg("groups", factory
->params
, argc
, argv
);
2278 unsigned int ugroups
= ARG_UINTEGER(groups
);
2281 free_arg(&protocol
);
2283 sd
= socket(AF_NETLINK
, SOCK_RAW
, iprotocol
);
2285 err((errno
== EPROTONOSUPPORT
)? EXIT_EPROTONOSUPPORT
: EXIT_FAILURE
,
2286 "failed in socket()");
2288 if (sd
!= fdescs
[0].fd
) {
2289 if (dup2(sd
, fdescs
[0].fd
) < 0) {
2293 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
2298 struct sockaddr_nl nl
;
2299 memset(&nl
, 0, sizeof(nl
));
2300 nl
.nl_family
= AF_NETLINK
;
2301 nl
.nl_groups
= ugroups
;
2302 if (bind(sd
, (struct sockaddr
*)&nl
, sizeof(nl
)) < 0) {
2306 err(EXIT_FAILURE
, "failed in bind(2)");
2309 fdescs
[0] = (struct fdesc
){
2311 .close
= close_fdesc
,
2318 static void *make_eventfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2319 int argc _U_
, char ** argv _U_
)
2322 pid_t
*pid
= xcalloc(1, sizeof(*pid
));
2324 if (fdescs
[0].fd
== fdescs
[1].fd
)
2325 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2329 err(EXIT_FAILURE
, "failed in eventfd(2)");
2331 if (fd
!= fdescs
[0].fd
) {
2332 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2336 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2341 fdescs
[0] = (struct fdesc
){
2343 .close
= close_fdesc
,
2347 if (dup2(fdescs
[0].fd
, fdescs
[1].fd
) < 0) {
2349 close(fdescs
[0].fd
);
2351 err(EXIT_FAILURE
, "failed to dup %d -> %d", fdescs
[0].fd
, fdescs
[1].fd
);
2354 signal(SIGCHLD
, abort_with_child_death_message
);
2358 close(fdescs
[0].fd
);
2359 close(fdescs
[1].fd
);
2361 err(EXIT_FAILURE
, "failed in fork()");
2362 } else if (*pid
== 0) {
2366 close(fdescs
[0].fd
);
2368 signal(SIGCONT
, do_nothing
);
2369 /* Notify the parent that I'm ready. */
2370 if (write(fdescs
[1].fd
, &v
, sizeof(v
)) != sizeof(v
)) {
2371 close(fdescs
[1].fd
);
2373 "failed in write() to notify the readiness to the prent");
2375 /* Wait till the parent lets me go. */
2378 close(fdescs
[1].fd
);
2383 /* The child owns fdescs[1]. */
2384 close(fdescs
[1].fd
);
2387 /* Wait till the child is ready. */
2388 if (read(fdescs
[0].fd
, &v
, sizeof(uint64_t)) != sizeof(v
)) {
2390 close(fdescs
[0].fd
);
2392 "failed in read() the readiness notification from the child");
2394 signal(SIGCHLD
, SIG_DFL
);
2400 static void report_eventfd(const struct factory
*factory _U_
,
2401 int nth
, void *data
, FILE *fp
)
2404 pid_t
*child
= data
;
2405 fprintf(fp
, "%d", *child
);
2409 static void free_eventfd(const struct factory
* factory _U_
, void *data
)
2411 pid_t child
= *(pid_t
*)data
;
2416 kill(child
, SIGCONT
);
2417 if (waitpid(child
, &wstatus
, 0) < 0)
2418 err(EXIT_FAILURE
, "failed in waitpid()");
2420 if (WIFEXITED(wstatus
)) {
2421 int s
= WEXITSTATUS(wstatus
);
2423 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2424 } else if (WIFSIGNALED(wstatus
)) {
2425 int s
= WTERMSIG(wstatus
);
2426 if (WTERMSIG(wstatus
) != 0)
2427 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2431 struct mqueue_data
{
2437 static void mqueue_data_free(struct mqueue_data
*data
)
2440 mq_unlink(data
->path
);
2441 free((void *)data
->path
);
2445 static void report_mqueue(const struct factory
*factory _U_
,
2446 int nth
, void *data
, FILE *fp
)
2449 fprintf(fp
, "%d", ((struct mqueue_data
*)data
)->pid
);
2453 static void close_mqueue(int fd
, void *data _U_
)
2458 static void free_mqueue(const struct factory
* factory _U_
, void *data
)
2460 struct mqueue_data
*mqueue_data
= data
;
2461 pid_t child
= mqueue_data
->pid
;
2464 mqueue_data_free(mqueue_data
);
2466 kill(child
, SIGCONT
);
2467 if (waitpid(child
, &wstatus
, 0) < 0)
2468 err(EXIT_FAILURE
, "failed in waitpid()");
2470 if (WIFEXITED(wstatus
)) {
2471 int s
= WEXITSTATUS(wstatus
);
2473 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2474 } else if (WIFSIGNALED(wstatus
)) {
2475 int s
= WTERMSIG(wstatus
);
2476 if (WTERMSIG(wstatus
) != 0)
2477 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2481 static void *make_mqueue(const struct factory
*factory
, struct fdesc fdescs
[],
2482 int argc
, char ** argv
)
2484 struct mqueue_data
*mqueue_data
;
2485 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
2486 const char *spath
= ARG_STRING(path
);
2488 struct mq_attr attr
= {
2495 if (spath
[0] != '/')
2496 errx(EXIT_FAILURE
, "the path for mqueue must start with '/': %s", spath
);
2498 if (spath
[0] == '\0')
2499 err(EXIT_FAILURE
, "the path should not be empty");
2501 if (fdescs
[0].fd
== fdescs
[1].fd
)
2502 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2504 mqueue_data
= xmalloc(sizeof(*mqueue_data
));
2505 mqueue_data
->pid
= 0;
2506 mqueue_data
->path
= xstrdup(spath
);
2507 mqueue_data
->created
= false;
2511 fd
= mq_open(mqueue_data
->path
, O_CREAT
|O_EXCL
| O_RDONLY
, S_IRUSR
| S_IWUSR
, &attr
);
2513 mqueue_data_free(mqueue_data
);
2514 err(EXIT_FAILURE
, "failed in mq_open(3) for reading");
2517 mqueue_data
->created
= true;
2518 if (fd
!= fdescs
[0].fd
) {
2519 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2522 mqueue_data_free(mqueue_data
);
2524 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2529 fdescs
[0] = (struct fdesc
){
2531 .close
= close_mqueue
,
2535 fd
= mq_open(mqueue_data
->path
, O_WRONLY
, S_IRUSR
| S_IWUSR
, NULL
);
2538 mq_close(fdescs
[0].fd
);
2539 mqueue_data_free(mqueue_data
);
2541 err(EXIT_FAILURE
, "failed in mq_open(3) for writing");
2544 if (fd
!= fdescs
[1].fd
) {
2545 if (dup2(fd
, fdescs
[1].fd
) < 0) {
2548 mq_close(fdescs
[0].fd
);
2550 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[1].fd
);
2554 fdescs
[1] = (struct fdesc
){
2556 .close
= close_mqueue
,
2560 signal(SIGCHLD
, abort_with_child_death_message
);
2561 mqueue_data
->pid
= fork();
2562 if (mqueue_data
->pid
< -1) {
2564 mq_close(fdescs
[0].fd
);
2565 mq_close(fdescs
[1].fd
);
2566 mqueue_data_free(mqueue_data
);
2568 err(EXIT_FAILURE
, "failed in fork()");
2569 } else if (mqueue_data
->pid
== 0) {
2570 mqueue_data
->created
= false;
2571 mqueue_data_free(mqueue_data
);
2572 mq_close(fdescs
[0].fd
);
2574 signal(SIGCONT
, do_nothing
);
2575 /* Notify the parent that I'm ready. */
2576 if (mq_send(fdescs
[1].fd
, "", 0, 0) < 0)
2578 "failed in mq_send() to notify the readiness to the prent");
2579 /* Wait till the parent lets me go. */
2582 mq_close(fdescs
[1].fd
);
2587 /* The child owns fdescs[1]. */
2588 mq_close(fdescs
[1].fd
);
2591 /* Wait till the child is ready. */
2592 if (mq_receive(fdescs
[0].fd
, &c
, 1, NULL
) < 0) {
2593 mq_close(fdescs
[0].fd
);
2594 mqueue_data_free(mqueue_data
);
2596 "failed in mq_receive() the readiness notification from the child");
2598 signal(SIGCHLD
, SIG_DFL
);
2603 struct sysvshm_data
{
2608 static void *make_sysvshm(const struct factory
*factory _U_
, struct fdesc fdescs
[] _U_
,
2609 int argc _U_
, char ** argv _U_
)
2611 size_t pagesize
= getpagesize();
2612 struct sysvshm_data
*sysvshm_data
;
2613 int id
= shmget(IPC_PRIVATE
, pagesize
, IPC_CREAT
| 0600);
2617 err(EXIT_FAILURE
, "failed to do shmget(.., %zu, ...)",
2620 start
= shmat(id
, NULL
, SHM_RDONLY
);
2621 if (start
== (void *) -1) {
2623 shmctl(id
, IPC_RMID
, NULL
);
2625 err(EXIT_FAILURE
, "failed to do shmat(%d,...)", id
);
2628 sysvshm_data
= xmalloc(sizeof(*sysvshm_data
));
2629 sysvshm_data
->addr
= start
;
2630 sysvshm_data
->id
= id
;
2631 return sysvshm_data
;
2634 static void free_sysvshm(const struct factory
*factory _U_
, void *data
)
2636 struct sysvshm_data
*sysvshm_data
= data
;
2638 shmdt(sysvshm_data
->addr
);
2639 shmctl(sysvshm_data
->id
, IPC_RMID
, NULL
);
2642 static void *make_eventpoll(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2643 int argc _U_
, char ** argv _U_
)
2652 .file
= "DUMMY, DONT'USE THIS"
2654 .file
= "/dev/random",
2658 .file
= "/dev/random",
2664 efd
= epoll_create(1);
2666 err(EXIT_FAILURE
, "failed in epoll_create(2)");
2667 if (efd
!= fdescs
[0].fd
) {
2668 if (dup2(efd
, fdescs
[0].fd
) < 0) {
2672 err(EXIT_FAILURE
, "failed to dup %d -> %d", efd
, fdescs
[0].fd
);
2677 fdescs
[0] = (struct fdesc
){
2679 .close
= close_fdesc
,
2683 for (size_t i
= 1; i
< ARRAY_SIZE(specs
); i
++) {
2684 int fd
= open(specs
[i
].file
, specs
[i
].flag
);
2688 for (size_t j
= i
- 1; j
> 0; j
--)
2689 close(fdescs
[j
].fd
);
2691 err(EXIT_FAILURE
, "failed in open(\"%s\",...)",
2694 if (fd
!= fdescs
[i
].fd
) {
2695 if (dup2(fd
, fdescs
[i
].fd
) < 0) {
2698 for (size_t j
= i
- 1; j
> 0; j
--)
2699 close(fdescs
[j
].fd
);
2702 err(EXIT_FAILURE
, "failed to dup %d -> %d",
2707 fdescs
[i
] = (struct fdesc
) {
2709 .close
= close_fdesc
,
2712 if (epoll_ctl(efd
, EPOLL_CTL_ADD
, fdescs
[i
].fd
,
2713 &(struct epoll_event
) {
2714 .events
= specs
[i
].events
,
2715 .data
= {.ptr
= NULL
,}
2719 for (size_t j
= i
; j
> 0; j
--)
2720 close(fdescs
[j
].fd
);
2723 "failed to add fd %d to the eventpoll fd with epoll_ctl",
2731 static bool decode_clockid(const char *sclockid
, clockid_t
*clockid
)
2733 if (sclockid
== NULL
)
2735 if (sclockid
[0] == '\0')
2738 if (strcmp(sclockid
, "realtime") == 0)
2739 *clockid
= CLOCK_REALTIME
;
2740 else if (strcmp(sclockid
, "monotonic") == 0)
2741 *clockid
= CLOCK_MONOTONIC
;
2742 else if (strcmp(sclockid
, "boottime") == 0)
2743 *clockid
= CLOCK_BOOTTIME
;
2744 else if (strcmp(sclockid
, "realtime-alarm") == 0)
2745 *clockid
= CLOCK_REALTIME_ALARM
;
2746 else if (strcmp(sclockid
, "boottime-alarm") == 0)
2747 *clockid
= CLOCK_BOOTTIME_ALARM
;
2753 static void *make_timerfd(const struct factory
*factory
, struct fdesc fdescs
[],
2754 int argc
, char ** argv
)
2757 struct timespec now
;
2758 struct itimerspec tspec
;
2760 struct arg abstime
= decode_arg("abstime", factory
->params
, argc
, argv
);
2761 bool babstime
= ARG_BOOLEAN(abstime
);
2763 struct arg remaining
= decode_arg("remaining", factory
->params
, argc
, argv
);
2764 unsigned int uremaining
= ARG_UINTEGER(remaining
);
2766 struct arg interval
= decode_arg("interval", factory
->params
, argc
, argv
);
2767 unsigned int uinterval
= ARG_UINTEGER(interval
);
2769 struct arg interval_frac
= decode_arg("interval-nanofrac", factory
->params
, argc
, argv
);
2770 unsigned int uinterval_frac
= ARG_UINTEGER(interval_frac
);
2772 struct arg clockid_
= decode_arg("clockid", factory
->params
, argc
, argv
);
2773 const char *sclockid
= ARG_STRING(clockid_
);
2776 if (decode_clockid (sclockid
, &clockid
) == false)
2777 err(EXIT_FAILURE
, "unknown clockid: %s", sclockid
);
2779 free_arg(&clockid_
);
2780 free_arg(&interval_frac
);
2781 free_arg(&interval
);
2782 free_arg(&remaining
);
2786 int r
= clock_gettime(clockid
, &now
);
2788 err(EXIT_FAILURE
, "failed in clock_gettime(2)");
2791 tfd
= timerfd_create(clockid
, 0);
2793 err(EXIT_FAILURE
, "failed in timerfd_create(2)");
2795 tspec
.it_value
.tv_sec
= (babstime
? now
.tv_sec
: 0) + uremaining
;
2796 tspec
.it_value
.tv_nsec
= (babstime
? now
.tv_nsec
: 0);
2798 tspec
.it_interval
.tv_sec
= uinterval
;
2799 tspec
.it_interval
.tv_nsec
= uinterval_frac
;
2801 if (timerfd_settime(tfd
, babstime
? TFD_TIMER_ABSTIME
: 0, &tspec
, NULL
) < 0) {
2805 err(EXIT_FAILURE
, "failed in timerfd_settime(2)");
2808 if (tfd
!= fdescs
[0].fd
) {
2809 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2813 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2818 fdescs
[0] = (struct fdesc
){
2820 .close
= close_fdesc
,
2827 static void *make_signalfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2828 int argc _U_
, char ** argv _U_
)
2833 if (sigemptyset(&mask
) < 0)
2834 err(EXIT_FAILURE
, "failed in sigemptyset()");
2835 if (sigaddset(&mask
, SIGFPE
) < 0)
2836 err(EXIT_FAILURE
, "failed in sigaddset(FPE)");
2837 if (sigaddset(&mask
, SIGUSR1
) < 0)
2838 err(EXIT_FAILURE
, "failed in sigaddset(USR1)");
2839 if (sigaddset(&mask
, numsig
) < 0)
2840 err(EXIT_FAILURE
, "failed in sigaddset(%d)", numsig
);
2842 int sfd
= signalfd(-1, &mask
, 0);
2844 err(EXIT_FAILURE
, "failed in signalfd(2)");
2846 if (sfd
!= fdescs
[0].fd
) {
2847 if (dup2(sfd
, fdescs
[0].fd
) < 0) {
2851 err(EXIT_FAILURE
, "failed to dup %d -> %d", sfd
, fdescs
[0].fd
);
2856 fdescs
[0] = (struct fdesc
){
2858 .close
= close_fdesc
,
2866 /* ref. linux/Documentation/networking/tuntap.rst */
2867 static void *make_cdev_tun(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2868 int argc _U_
, char ** argv _U_
)
2870 int tfd
= open("/dev/net/tun", O_RDWR
);
2874 err(EXIT_FAILURE
, "failed in opening /dev/net/tun");
2876 memset(&ifr
, 0, sizeof(ifr
));
2878 ifr
.ifr_flags
= IFF_TUN
;
2879 strcpy(ifr
.ifr_name
, "mkfds%d");
2881 if (ioctl(tfd
, TUNSETIFF
, (void *) &ifr
) < 0) {
2885 err(EXIT_FAILURE
, "failed in setting \"lo\" to the tun device");
2888 if (tfd
!= fdescs
[0].fd
) {
2889 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2893 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2898 fdescs
[0] = (struct fdesc
){
2900 .close
= close_fdesc
,
2904 return xstrdup(ifr
.ifr_name
);
2907 static void report_cdev_tun(const struct factory
*factory _U_
,
2908 int nth
, void *data
, FILE *fp
)
2911 char *devname
= data
;
2912 fprintf(fp
, "%s", devname
);
2916 static void free_cdev_tun(const struct factory
* factory _U_
, void *data
)
2921 static void *make_bpf_prog(const struct factory
*factory
, struct fdesc fdescs
[],
2922 int argc
, char ** argv
)
2924 struct arg prog_type_id
= decode_arg("prog-type-id", factory
->params
, argc
, argv
);
2925 int iprog_type_id
= ARG_INTEGER(prog_type_id
);
2927 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
2928 const char *sname
= ARG_STRING(name
);
2931 union bpf_attr attr
;
2932 /* Just doing exit with 0. */
2933 struct bpf_insn insns
[] = {
2935 .code
= BPF_ALU64
| BPF_MOV
| BPF_K
,
2936 .dst_reg
= BPF_REG_0
, .src_reg
= 0, .off
= 0, .imm
= 0
2939 .code
= BPF_JMP
| BPF_EXIT
,
2940 .dst_reg
= 0, .src_reg
= 0, .off
= 0, .imm
= 0
2944 memset(&attr
, 0, sizeof(attr
));
2945 attr
.prog_type
= iprog_type_id
;
2946 attr
.insns
= (uint64_t)(unsigned long)insns
;
2947 attr
.insn_cnt
= ARRAY_SIZE(insns
);
2948 attr
.license
= (int64_t)(unsigned long)"GPL";
2949 strncpy(attr
.prog_name
, sname
, sizeof(attr
.prog_name
) - 1);
2952 free_arg(&prog_type_id
);
2954 bfd
= syscall(SYS_bpf
, BPF_PROG_LOAD
, &attr
, sizeof(attr
));
2956 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_PROG_LOAD)");
2958 if (bfd
!= fdescs
[0].fd
) {
2959 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
2963 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
2968 fdescs
[0] = (struct fdesc
){
2970 .close
= close_fdesc
,
2977 static void *make_some_pipes(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2978 int argc _U_
, char ** argv _U_
)
2980 /* Reserver fds before making pipes */
2981 for (int i
= 0; i
< factory
->N
; i
++) {
2982 close(fdescs
[i
].fd
);
2983 if (dup2(0, fdescs
[0].fd
) < 0)
2984 err(EXIT_FAILURE
, "failed to reserve fd %d with dup2", fdescs
[0].fd
);
2987 for (int i
= 0; i
< (factory
->N
) / 2; i
++) {
2992 mode
= 1 << (i
% 3);
2993 if (mode
== MX_WRITE
) {
2999 err(EXIT_FAILURE
, "failed to make pipe");
3001 if (dup2(pd
[0], fdescs
[2 * i
+ r
].fd
) < 0)
3002 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[0], fdescs
[2 * i
+ r
].fd
);
3004 fdescs
[2 * 1 + r
].close
= close_fdesc
;
3006 if (dup2(pd
[1], fdescs
[2 * i
+ w
].fd
) < 0)
3007 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[1], fdescs
[2 * i
+ 2].fd
);
3009 fdescs
[2 * 1 + w
].close
= close_fdesc
;
3011 fdescs
[2 * i
].mx_modes
|= mode
;
3013 /* Make the pipe for writing full. */
3014 if (fdescs
[2 * i
].mx_modes
& MX_WRITE
) {
3015 int n
= fcntl(fdescs
[2 * i
].fd
, F_GETPIPE_SZ
);
3019 err(EXIT_FAILURE
, "failed to get PIPE BUFFER SIZE from %d", fdescs
[2 * i
].fd
);
3022 if (write(fdescs
[2 * i
].fd
, buf
, n
) != n
)
3023 err(EXIT_FAILURE
, "failed to fill the pipe buffer specified with %d",
3033 static void *make_bpf_map(const struct factory
*factory
, struct fdesc fdescs
[],
3034 int argc
, char ** argv
)
3036 struct arg map_type_id
= decode_arg("map-type-id", factory
->params
, argc
, argv
);
3037 int imap_type_id
= ARG_INTEGER(map_type_id
);
3039 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
3040 const char *sname
= ARG_STRING(name
);
3043 union bpf_attr attr
= {
3044 .map_type
= imap_type_id
,
3050 strncpy(attr
.map_name
, sname
, sizeof(attr
.map_name
) - 1);
3053 free_arg(&map_type_id
);
3055 bfd
= syscall(SYS_bpf
, BPF_MAP_CREATE
, &attr
, sizeof(attr
));
3057 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_MAP_CREATE)");
3059 if (bfd
!= fdescs
[0].fd
) {
3060 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
3064 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
3069 fdescs
[0] = (struct fdesc
){
3071 .close
= close_fdesc
,
3078 static void *make_pty(const struct factory
*factory _U_
, struct fdesc fdescs
[],
3079 int argc _U_
, char ** argv _U_
)
3084 int ptmx_fd
= posix_openpt(O_RDWR
);
3086 err(EXIT_FAILURE
, "failed in opening /dev/ptmx");
3088 if (unlockpt(ptmx_fd
) < 0) {
3092 err(EXIT_FAILURE
, "failed in unlockpt()");
3095 if (ioctl(ptmx_fd
, TIOCGPTN
, &index
) < 0) {
3099 err(EXIT_FAILURE
, "failed in ioctl(TIOCGPTN)");
3102 pts
= ptsname(ptmx_fd
);
3107 err(EXIT_FAILURE
, "failed in ptsname()");
3110 if (ptmx_fd
!= fdescs
[0].fd
) {
3111 if (dup2(ptmx_fd
, fdescs
[0].fd
) < 0) {
3115 err(EXIT_FAILURE
, "failed to dup %d -> %d", ptmx_fd
, fdescs
[0].fd
);
3118 ptmx_fd
= fdescs
[0].fd
;
3121 pts_fd
= open(pts
, O_RDONLY
);
3126 err(EXIT_FAILURE
, "failed in opening %s", pts
);
3129 if (pts_fd
!= fdescs
[1].fd
) {
3130 if (dup2(pts_fd
, fdescs
[1].fd
) < 0) {
3135 err(EXIT_FAILURE
, "failed to dup %d -> %d", pts_fd
, fdescs
[1].fd
);
3138 pts_fd
= fdescs
[1].fd
;
3141 fdescs
[0] = (struct fdesc
){
3143 .close
= close_fdesc
,
3146 fdescs
[1] = (struct fdesc
){
3148 .close
= close_fdesc
,
3152 indexp
= xmalloc(sizeof(index
));
3157 static void report_pty(const struct factory
*factory _U_
,
3158 int nth
, void *data
, FILE *fp
)
3162 fprintf(fp
, "%d", *index
);
3166 static void free_pty(const struct factory
* factory _U_
, void *data
)
3176 static void *make_mmap(const struct factory
*factory
, struct fdesc fdescs
[] _U_
,
3177 int argc
, char ** argv
)
3179 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
3180 const char *sfile
= ARG_STRING(file
);
3182 int fd
= open(sfile
, O_RDONLY
);
3184 err(EXIT_FAILURE
, "failed in opening %s", sfile
);
3188 if (fstat(fd
, &sb
) < 0) {
3192 err(EXIT_FAILURE
, "failed in fstat()");
3194 char *addr
= mmap(NULL
, sb
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
3195 if (addr
== MAP_FAILED
) {
3199 err(EXIT_FAILURE
, "failed in mmap()");
3203 struct mmap_data
*data
= xmalloc(sizeof(*data
));
3205 data
->len
= sb
.st_size
;
3210 static void free_mmap(const struct factory
* factory _U_
, void *data
)
3212 munmap(((struct mmap_data
*)data
)->addr
,
3213 ((struct mmap_data
*)data
)->len
);
3216 #define PARAM_END { .name = NULL, }
3217 static const struct factory factories
[] = {
3219 .name
= "ro-regular-file",
3220 .desc
= "read-only regular file",
3224 .make
= open_ro_regular_file
,
3225 .params
= (struct parameter
[]) {
3228 .type
= PTYPE_STRING
,
3229 .desc
= "file to be opened",
3230 .defv
.string
= "/etc/passwd",
3234 .type
= PTYPE_INTEGER
,
3235 .desc
= "seek bytes after open with SEEK_CUR",
3239 .name
= "read-lease",
3240 .type
= PTYPE_BOOLEAN
,
3241 .desc
= "taking out read lease for the file",
3242 .defv
.boolean
= false,
3248 .name
= "make-regular-file",
3249 .desc
= "regular file for writing",
3253 .make
= make_w_regular_file
,
3254 .free
= free_after_closing_duplicated_fd
,
3255 .params
= (struct parameter
[]) {
3258 .type
= PTYPE_STRING
,
3259 .desc
= "file to be made",
3260 .defv
.string
= "./test_mkfds_make_regular_file",
3264 .type
= PTYPE_BOOLEAN
,
3265 .desc
= "delete the file just after making it",
3266 .defv
.boolean
= false,
3269 .name
= "write-bytes",
3270 .type
= PTYPE_INTEGER
,
3271 .desc
= "write something (> 0)",
3276 .type
= PTYPE_BOOLEAN
,
3277 .desc
= "open the new file readable way",
3278 .defv
.string
= false,
3282 .type
= PTYPE_STRING
,
3283 .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",
3284 .defv
.string
= "none",
3288 .type
= PTYPE_INTEGER
,
3289 .desc
= "the number for the fd duplicated from the original fd",
3296 .name
= "pipe-no-fork",
3297 .desc
= "making pair of fds with pipe(2)",
3302 .params
= (struct parameter
[]) {
3305 .type
= PTYPE_STRING
,
3306 .desc
= "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")",
3307 .defv
.string
= "--",
3311 .type
= PTYPE_INTEGER
,
3312 .desc
= "file descriptor for duplicating the pipe input",
3317 .type
= PTYPE_INTEGER
,
3318 .desc
= "file descriptor for duplicating the pipe output",
3325 .name
= "directory",
3326 .desc
= "directory",
3330 .make
= open_directory
,
3331 .params
= (struct parameter
[]) {
3334 .type
= PTYPE_STRING
,
3335 .desc
= "directory to be opened",
3340 .type
= PTYPE_INTEGER
,
3341 .desc
= "read the number of dentries after open with readdir(3)",
3348 .name
= "rw-character-device",
3349 .desc
= "character device with O_RDWR flag",
3353 .make
= open_rw_chrdev
,
3354 .params
= (struct parameter
[]) {
3357 .type
= PTYPE_STRING
,
3358 .desc
= "character device node to be opened",
3359 .defv
.string
= "/dev/zero",
3365 .name
= "socketpair",
3366 .desc
= "AF_UNIX socket pair created with socketpair(2)",
3370 .make
= make_socketpair
,
3371 .params
= (struct parameter
[]) {
3374 .type
= PTYPE_STRING
,
3375 .desc
= "STREAM, DGRAM, or SEQPACKET",
3376 .defv
.string
= "STREAM",
3379 .name
= "halfclose",
3380 .type
= PTYPE_BOOLEAN
,
3381 .desc
= "Shutdown the read end of the 1st socket, the write end of the 2nd socket",
3382 .defv
.boolean
= false,
3389 .desc
= "symbolic link itself opened with O_PATH",
3393 .make
= open_with_opath
,
3394 .params
= (struct parameter
[]) {
3397 .type
= PTYPE_STRING
,
3398 .desc
= "path to a symbolic link",
3399 .defv
.string
= "/dev/stdin",
3405 .name
= "ro-block-device",
3406 .desc
= "block device with O_RDONLY flag",
3410 .make
= open_ro_blkdev
,
3411 .params
= (struct parameter
[]) {
3414 .type
= PTYPE_STRING
,
3415 .desc
= "block device node to be opened",
3416 .defv
.string
= "/dev/nullb0",
3422 .name
= "mapped-packet-socket",
3423 .desc
= "mmap'ed AF_PACKET socket",
3427 .make
= make_mmapped_packet_socket
,
3428 .params
= (struct parameter
[]) {
3431 .type
= PTYPE_STRING
,
3432 .desc
= "DGRAM or RAW",
3433 .defv
.string
= "RAW",
3436 .name
= "interface",
3437 .type
= PTYPE_STRING
,
3438 .desc
= "a name of network interface like eth0 or lo",
3439 .defv
.string
= "lo",
3446 .desc
= "pidfd returned from pidfd_open(2)",
3451 .params
= (struct parameter
[]) {
3453 .name
= "target-pid",
3454 .type
= PTYPE_INTEGER
,
3455 .desc
= "the pid of the target process",
3463 .desc
= "inotify fd returned from inotify_init(2)",
3467 .make
= make_inotify_fd
,
3468 .params
= (struct parameter
[]) {
3471 .type
= PTYPE_STRING
,
3472 .desc
= "the directory that the inotify monitors",
3477 .type
= PTYPE_STRING
,
3478 .desc
= "the file that the inotify monitors",
3479 .defv
.string
= "/etc/fstab",
3485 .name
= "unix-stream",
3486 .desc
= "AF_UNIX+SOCK_STREAM sockets",
3490 .make
= make_unix_stream
,
3491 .params
= (struct parameter
[]) {
3494 .type
= PTYPE_STRING
,
3495 .desc
= "path for listening-socket bound to",
3496 .defv
.string
= "/tmp/test_mkfds-unix-stream",
3500 .type
= PTYPE_INTEGER
,
3501 .desc
= "backlog passed to listen(2)",
3506 .type
= PTYPE_BOOLEAN
,
3507 .desc
= "use PATH as an abstract socket address",
3508 .defv
.boolean
= false,
3511 .name
= "server-shutdown",
3512 .type
= PTYPE_INTEGER
,
3513 .desc
= "shutdown the accepted socket; 1: R, 2: W, 3: RW",
3517 .name
= "client-shutdown",
3518 .type
= PTYPE_INTEGER
,
3519 .desc
= "shutdown the client socket; 1: R, 2: W, 3: RW",
3524 .type
= PTYPE_STRING
,
3525 .desc
= "stream or seqpacket",
3526 .defv
.string
= "stream",
3532 .name
= "unix-dgram",
3533 .desc
= "AF_UNIX+SOCK_DGRAM sockets",
3537 .make
= make_unix_dgram
,
3538 .params
= (struct parameter
[]) {
3541 .type
= PTYPE_STRING
,
3542 .desc
= "path for unix non-stream bound to",
3543 .defv
.string
= "/tmp/test_mkfds-unix-dgram",
3547 .type
= PTYPE_BOOLEAN
,
3548 .desc
= "use PATH as an abstract socket address",
3549 .defv
.boolean
= false,
3555 .name
= "unix-in-netns",
3556 .desc
= "make a unix socket in a new network namespace",
3560 .make
= make_unix_in_new_netns
,
3561 .params
= (struct parameter
[]) {
3564 .type
= PTYPE_STRING
,
3565 .desc
= "dgram, stream, or seqpacket",
3566 .defv
.string
= "stream",
3570 .type
= PTYPE_STRING
,
3571 .desc
= "path for unix non-stream bound to",
3572 .defv
.string
= "/tmp/test_mkfds-unix-in-netns",
3576 .type
= PTYPE_BOOLEAN
,
3577 .desc
= "use PATH as an abstract socket address",
3578 .defv
.boolean
= false,
3585 .desc
= "AF_INET+SOCK_STREAM sockets",
3590 .params
= (struct parameter
[]) {
3592 .name
= "server-port",
3593 .type
= PTYPE_INTEGER
,
3594 .desc
= "TCP port the server may listen",
3595 .defv
.integer
= 12345,
3598 .name
= "client-port",
3599 .type
= PTYPE_INTEGER
,
3600 .desc
= "TCP port the client may bind",
3601 .defv
.integer
= 23456,
3608 .desc
= "AF_INET+SOCK_DGRAM sockets",
3613 .params
= (struct parameter
[]) {
3616 .type
= PTYPE_BOOLEAN
,
3617 .desc
= "Use UDPLITE instead of UDP",
3618 .defv
.boolean
= false,
3621 .name
= "server-port",
3622 .type
= PTYPE_INTEGER
,
3623 .desc
= "UDP port the server may listen",
3624 .defv
.integer
= 12345,
3627 .name
= "client-port",
3628 .type
= PTYPE_INTEGER
,
3629 .desc
= "UDP port the client may bind",
3630 .defv
.integer
= 23456,
3633 .name
= "server-do-bind",
3634 .type
= PTYPE_BOOLEAN
,
3635 .desc
= "call bind with the server socket",
3636 .defv
.boolean
= true,
3639 .name
= "client-do-bind",
3640 .type
= PTYPE_BOOLEAN
,
3641 .desc
= "call bind with the client socket",
3642 .defv
.boolean
= true,
3645 .name
= "client-do-connect",
3646 .type
= PTYPE_BOOLEAN
,
3647 .desc
= "call connect with the client socket",
3648 .defv
.boolean
= true,
3655 .desc
= "AF_INET+SOCK_RAW sockets",
3660 .params
= (struct parameter
[]) {
3663 .type
= PTYPE_INTEGER
,
3664 .desc
= "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
3665 .defv
.integer
= IPPROTO_IPIP
,
3673 .desc
= "AF_INET+SOCK_DGRAM+IPPROTO_ICMP sockets",
3678 .params
= (struct parameter
[]) {
3681 .type
= PTYPE_BOOLEAN
,
3682 .desc
= "call connect(2) with the socket",
3683 .defv
.boolean
= true,
3687 .type
= PTYPE_BOOLEAN
,
3688 .desc
= "call bind(2) with the socket",
3689 .defv
.boolean
= true,
3693 .type
= PTYPE_INTEGER
,
3694 .desc
= "ICMP echo request id",
3702 .desc
= "AF_INET6+SOCK_STREAM sockets",
3707 .params
= (struct parameter
[]) {
3709 .name
= "server-port",
3710 .type
= PTYPE_INTEGER
,
3711 .desc
= "TCP port the server may listen",
3712 .defv
.integer
= 12345,
3715 .name
= "client-port",
3716 .type
= PTYPE_INTEGER
,
3717 .desc
= "TCP port the client may bind",
3718 .defv
.integer
= 23456,
3725 .desc
= "AF_INET6+SOCK_DGRAM sockets",
3730 .params
= (struct parameter
[]) {
3733 .type
= PTYPE_BOOLEAN
,
3734 .desc
= "Use UDPLITE instead of UDP",
3735 .defv
.boolean
= false,
3738 .name
= "server-port",
3739 .type
= PTYPE_INTEGER
,
3740 .desc
= "UDP port the server may listen",
3741 .defv
.integer
= 12345,
3744 .name
= "client-port",
3745 .type
= PTYPE_INTEGER
,
3746 .desc
= "UDP port the client may bind",
3747 .defv
.integer
= 23456,
3750 .name
= "server-do-bind",
3751 .type
= PTYPE_BOOLEAN
,
3752 .desc
= "call bind with the server socket",
3753 .defv
.boolean
= true,
3756 .name
= "client-do-bind",
3757 .type
= PTYPE_BOOLEAN
,
3758 .desc
= "call bind with the client socket",
3759 .defv
.boolean
= true,
3762 .name
= "client-do-connect",
3763 .type
= PTYPE_BOOLEAN
,
3764 .desc
= "call connect with the client socket",
3765 .defv
.boolean
= true,
3772 .desc
= "AF_INET6+SOCK_RAW sockets",
3777 .params
= (struct parameter
[]) {
3780 .type
= PTYPE_INTEGER
,
3781 .desc
= "protocol passed to socket(AF_INET6, SOCK_RAW, protocol)",
3782 .defv
.integer
= IPPROTO_IPIP
,
3790 .desc
= "AF_INET6+SOCK_DGRAM+IPPROTO_ICMPV6 sockets",
3795 .params
= (struct parameter
[]) {
3798 .type
= PTYPE_BOOLEAN
,
3799 .desc
= "call connect(2) with the socket",
3800 .defv
.boolean
= true,
3804 .type
= PTYPE_BOOLEAN
,
3805 .desc
= "call bind(2) with the socket",
3806 .defv
.boolean
= true,
3810 .type
= PTYPE_INTEGER
,
3811 .desc
= "ICMP echo request id",
3820 .desc
= "open a file specifying a netns",
3825 .params
= (struct parameter
[]) {
3832 .desc
= "AF_NETLINK sockets",
3836 .make
= make_netlink
,
3837 .params
= (struct parameter
[]) {
3840 .type
= PTYPE_INTEGER
,
3841 .desc
= "protocol passed to socket(AF_NETLINK, SOCK_RAW, protocol)",
3842 .defv
.integer
= NETLINK_USERSOCK
,
3846 .type
= PTYPE_UINTEGER
,
3847 .desc
= "multicast groups of netlink communication (requires CAP_NET_ADMIN)",
3855 .desc
= "make an eventfd connecting two processes",
3860 .make
= make_eventfd
,
3861 .report
= report_eventfd
,
3862 .free
= free_eventfd
,
3863 .params
= (struct parameter
[]) {
3869 .desc
= "make a mqueue connecting two processes",
3874 .make
= make_mqueue
,
3875 .report
= report_mqueue
,
3876 .free
= free_mqueue
,
3877 .params
= (struct parameter
[]) {
3880 .type
= PTYPE_STRING
,
3881 .desc
= "path for mqueue",
3882 .defv
.string
= "/test_mkfds-mqueue",
3889 .desc
= "shared memory mapped with SYSVIPC shmem syscalls",
3893 .make
= make_sysvshm
,
3894 .free
= free_sysvshm
,
3895 .params
= (struct parameter
[]) {
3900 .name
= "eventpoll",
3901 .desc
= "make eventpoll (epoll) file",
3905 .make
= make_eventpoll
,
3906 .params
= (struct parameter
[]) {
3912 .desc
= "make timerfd",
3916 .make
= make_timerfd
,
3917 .params
= (struct parameter
[]) {
3920 .type
= PTYPE_STRING
,
3921 .desc
= "ID: realtime, monotonic, boottime, realtime-alarm, or boottime-alarm",
3922 .defv
.string
= "realtime",
3926 .type
= PTYPE_BOOLEAN
,
3927 .desc
= "use TFD_TIMER_ABSTIME flag",
3928 .defv
.boolean
= false,
3931 .name
= "remaining",
3932 .type
= PTYPE_UINTEGER
,
3933 .desc
= "remaining seconds for expiration",
3934 .defv
.uinteger
= 99,
3938 .type
= PTYPE_UINTEGER
,
3939 .desc
= "inteval in seconds",
3940 .defv
.uinteger
= 10,
3943 .name
= "interval-nanofrac",
3944 .type
= PTYPE_UINTEGER
,
3945 .desc
= "nsec part of inteval",
3954 .desc
= "make signalfd",
3958 .make
= make_signalfd
,
3959 .params
= (struct parameter
[]) {
3965 .desc
= "open /dev/net/tun",
3970 .make
= make_cdev_tun
,
3971 .report
= report_cdev_tun
,
3972 .free
= free_cdev_tun
,
3973 .params
= (struct parameter
[]) {
3979 .desc
= "make bpf-prog",
3983 .make
= make_bpf_prog
,
3984 .params
= (struct parameter
[]) {
3986 .name
= "prog-type-id",
3987 .type
= PTYPE_INTEGER
,
3988 .desc
= "program type by id",
3993 .type
= PTYPE_STRING
,
3994 .desc
= "name assigned to bpf prog object",
3995 .defv
.string
= "mkfds_bpf_prog",
4001 .name
= "multiplexing",
4002 .desc
= "make pipes monitored by multiplexers",
4006 .make
= make_some_pipes
,
4007 .params
= (struct parameter
[]) {
4013 .desc
= "make bpf-map",
4017 .make
= make_bpf_map
,
4018 .params
= (struct parameter
[]) {
4020 .name
= "map-type-id",
4021 .type
= PTYPE_INTEGER
,
4022 .desc
= "map type by id",
4027 .type
= PTYPE_STRING
,
4028 .desc
= "name assigned to the bpf map object",
4029 .defv
.string
= "mkfds_bpf_map",
4036 .desc
= "make a pair of ptmx and pts",
4042 .report
= report_pty
,
4044 .params
= (struct parameter
[]) {
4050 .desc
= "do mmap the given file",
4056 .params
= (struct parameter
[]) {
4059 .type
= PTYPE_STRING
,
4060 .desc
= "file to be opened",
4061 .defv
.string
= "/etc/passwd",
4068 static int count_parameters(const struct factory
*factory
)
4071 const struct parameter
*p
= factory
->params
;
4076 return p
- factory
->params
;
4079 static void print_factory(const struct factory
*factory
)
4081 printf("%-20s %4s %5d %7d %6d %s\n",
4083 factory
->priv
? "yes": "no",
4086 count_parameters(factory
),
4090 static void list_factories(void)
4092 printf("%-20s PRIV COUNT NRETURN NPARAM DESCRIPTION\n", "FACTORY");
4093 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4094 print_factory(factories
+ i
);
4097 static const struct factory
*find_factory(const char *name
)
4099 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4100 if (strcmp(factories
[i
].name
, name
) == 0)
4101 return factories
+ i
;
4105 static void list_parameters(const char *factory_name
)
4107 const struct factory
*factory
= find_factory(factory_name
);
4108 const char *fmt
= "%-15s %-8s %15s %s\n";
4111 errx(EXIT_FAILURE
, "no such factory: %s", factory_name
);
4113 if (!factory
->params
)
4116 printf(fmt
, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION");
4117 for (const struct parameter
*p
= factory
->params
; p
->name
!= NULL
; p
++) {
4118 char *defv
= ptype_classes
[p
->type
].sprint(&p
->defv
);
4119 printf(fmt
, p
->name
, ptype_classes
[p
->type
].name
, defv
, p
->desc
);
4124 static void rename_self(const char *comm
)
4126 if (prctl(PR_SET_NAME
, (unsigned long)comm
, 0, 0, 0) < 0)
4127 err(EXIT_FAILURE
, "failed to rename self via prctl: %s", comm
);
4130 static void do_nothing(int signum _U_
)
4134 #ifdef __NR_pidfd_open
4137 pidfd_open(pid_t pid
, unsigned int flags
)
4139 return syscall(__NR_pidfd_open
, pid
, flags
);
4143 pidfd_open(pid_t pid _U_
, unsigned int flags _U_
)
4153 struct multiplexer
{
4155 void (*fn
)(bool, struct fdesc
*fdescs
, size_t n_fdescs
);
4158 #if defined(__NR_select) || defined(__NR_poll)
4159 static void sighandler_nop(int si _U_
)
4165 #define DEFUN_WAIT_EVENT_SELECT(NAME,SYSCALL,XDECLS,SETUP_SIG_HANDLER,SYSCALL_INVOCATION) \
4166 static void wait_event_##NAME(bool add_stdin, struct fdesc *fdescs, size_t n_fdescs) \
4174 FD_ZERO(&readfds); \
4175 FD_ZERO(&writefds); \
4176 FD_ZERO(&exceptfds); \
4177 /* Monitor the standard input only when the process \
4178 * is in foreground. */ \
4181 FD_SET(0, &readfds); \
4184 for (size_t i = 0; i < n_fdescs; i++) { \
4185 if (fdescs[i].mx_modes & MX_READ) { \
4186 n = max(n, fdescs[i].fd + 1); \
4187 FD_SET(fdescs[i].fd, &readfds); \
4189 if (fdescs[i].mx_modes & MX_WRITE) { \
4190 n = max(n, fdescs[i].fd + 1); \
4191 FD_SET(fdescs[i].fd, &writefds); \
4193 if (fdescs[i].mx_modes & MX_EXCEPT) { \
4194 n = max(n, fdescs[i].fd + 1); \
4195 FD_SET(fdescs[i].fd, &exceptfds); \
4201 if (SYSCALL_INVOCATION < 0 \
4202 && errno != EINTR) \
4203 err(EXIT_FAILURE, "failed in " SYSCALL); \
4206 DEFUN_WAIT_EVENT_SELECT(default,
4209 sigemptyset(&sigset
);,
4210 pselect(n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4212 #ifdef __NR_pselect6
4213 DEFUN_WAIT_EVENT_SELECT(pselect6
,
4216 sigemptyset(&sigset
);,
4217 syscall(__NR_pselect6
, n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4221 DEFUN_WAIT_EVENT_SELECT(select
,
4224 signal(SIGCONT
,sighandler_nop
);,
4225 syscall(__NR_select
, n
, &readfds
, &writefds
, &exceptfds
, NULL
))
4229 static DEFUN_WAIT_EVENT_POLL(poll
,
4232 signal(SIGCONT
,sighandler_nop
);,
4233 syscall(__NR_poll
, pfds
, n
, -1))
4236 #define DEFAULT_MULTIPLEXER 0
4237 static struct multiplexer multiplexers
[] = {
4240 .fn
= wait_event_default
,
4242 #ifdef __NR_pselect6
4245 .fn
= wait_event_pselect6
,
4251 .fn
= wait_event_select
,
4257 .fn
= wait_event_poll
,
4263 .fn
= wait_event_ppoll
,
4268 static struct multiplexer
*lookup_multiplexer(const char *name
)
4270 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4271 if (strcmp(name
, multiplexers
[i
].name
) == 0)
4272 return multiplexers
+ i
;
4276 static void list_multiplexers(void)
4279 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4280 puts(multiplexers
[i
].name
);
4283 static bool is_available(const char *factory
)
4285 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4286 if (strcmp(factories
[i
].name
, factory
) == 0)
4292 int main(int argc
, char **argv
)
4295 const struct factory
*factory
;
4296 struct fdesc fdescs
[MAX_N
];
4300 bool monitor_stdin
= true;
4302 struct multiplexer
*wait_event
= NULL
;
4304 static const struct option longopts
[] = {
4305 { "is-available",required_argument
,NULL
, 'a' },
4306 { "list", no_argument
, NULL
, 'l' },
4307 { "parameters", required_argument
, NULL
, 'I' },
4308 { "comm", required_argument
, NULL
, 'r' },
4309 { "quiet", no_argument
, NULL
, 'q' },
4310 { "dont-monitor-stdin", no_argument
, NULL
, 'X' },
4311 { "dont-puase", no_argument
, NULL
, 'c' },
4312 { "wait-with", required_argument
, NULL
, 'w' },
4313 { "multiplexers",no_argument
,NULL
, 'W' },
4314 { "help", no_argument
, NULL
, 'h' },
4315 { NULL
, 0, NULL
, 0 },
4318 while ((c
= getopt_long(argc
, argv
, "a:lhqcI:r:w:WX", longopts
, NULL
)) != -1) {
4321 usage(stdout
, EXIT_SUCCESS
);
4323 exit(is_available(optarg
)? 0: 1);
4328 list_parameters(optarg
);
4337 wait_event
= lookup_multiplexer(optarg
);
4338 if (wait_event
== NULL
)
4339 errx(EXIT_FAILURE
, "unknown multiplexer: %s", optarg
);
4342 list_multiplexers();
4345 rename_self(optarg
);
4348 monitor_stdin
= false;
4351 usage(stderr
, EXIT_FAILURE
);
4356 errx(EXIT_FAILURE
, "no file descriptor specification given");
4358 if (cont
&& wait_event
)
4359 errx(EXIT_FAILURE
, "don't specify both -c/--dont-puase and -w/--wait-with options");
4360 if (wait_event
== NULL
)
4361 wait_event
= multiplexers
+ DEFAULT_MULTIPLEXER
;
4363 factory
= find_factory(argv
[optind
]);
4365 errx(EXIT_FAILURE
, "no such factory: %s", argv
[optind
]);
4366 assert(factory
->N
+ factory
->EX_N
< MAX_N
);
4369 if ((optind
+ factory
->N
) > argc
)
4370 errx(EXIT_FAILURE
, "not enough file descriptors given for %s",
4373 if (factory
->priv
&& getuid() != 0)
4374 errx(EXIT_FAILURE
, "%s factory requires root privilege", factory
->name
);
4376 for (int i
= 0; i
< MAX_N
; i
++) {
4378 fdescs
[i
].mx_modes
= 0;
4379 fdescs
[i
].close
= NULL
;
4382 for (int i
= 0; i
< factory
->N
; i
++) {
4383 char *str
= argv
[optind
+ i
];
4388 fd
= strtol(str
, &ep
, 10);
4390 err(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4392 errx(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4394 errx(EXIT_FAILURE
, "garbage at the end of number: %s", str
);
4396 errx(EXIT_FAILURE
, "fd number should not be negative: %s", str
);
4398 errx(EXIT_FAILURE
, "fd 0, 1, 2 are reserved: %s", str
);
4401 optind
+= factory
->N
;
4403 data
= factory
->make(factory
, fdescs
, argc
- optind
, argv
+ optind
);
4405 signal(SIGCONT
, do_nothing
);
4408 printf("%d", getpid());
4409 if (factory
->report
) {
4410 for (int i
= 0; i
< factory
->EX_R
; i
++) {
4412 factory
->report(factory
, i
, data
, stdout
);
4420 wait_event
->fn(monitor_stdin
,
4421 fdescs
, factory
->N
+ factory
->EX_N
);
4423 for (int i
= 0; i
< factory
->N
+ factory
->EX_N
; i
++)
4424 if (fdescs
[i
].fd
>= 0 && fdescs
[i
].close
)
4425 fdescs
[i
].close(fdescs
[i
].fd
, fdescs
[i
].data
);
4428 factory
->free(factory
, data
);