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
);
2299 struct sockaddr_nl nl
;
2300 memset(&nl
, 0, sizeof(nl
));
2301 nl
.nl_family
= AF_NETLINK
;
2302 nl
.nl_groups
= ugroups
;
2303 if (bind(sd
, (struct sockaddr
*)&nl
, sizeof(nl
)) < 0) {
2307 err(EXIT_FAILURE
, "failed in bind(2)");
2310 fdescs
[0] = (struct fdesc
){
2312 .close
= close_fdesc
,
2319 static void *make_eventfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2320 int argc _U_
, char ** argv _U_
)
2323 pid_t
*pid
= xcalloc(1, sizeof(*pid
));
2325 if (fdescs
[0].fd
== fdescs
[1].fd
)
2326 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2330 err(EXIT_FAILURE
, "failed in eventfd(2)");
2332 if (fd
!= fdescs
[0].fd
) {
2333 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2337 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2342 fdescs
[0] = (struct fdesc
){
2344 .close
= close_fdesc
,
2348 if (dup2(fdescs
[0].fd
, fdescs
[1].fd
) < 0) {
2350 close(fdescs
[0].fd
);
2352 err(EXIT_FAILURE
, "failed to dup %d -> %d", fdescs
[0].fd
, fdescs
[1].fd
);
2355 signal(SIGCHLD
, abort_with_child_death_message
);
2359 close(fdescs
[0].fd
);
2360 close(fdescs
[1].fd
);
2362 err(EXIT_FAILURE
, "failed in fork()");
2363 } else if (*pid
== 0) {
2367 close(fdescs
[0].fd
);
2369 signal(SIGCONT
, do_nothing
);
2370 /* Notify the parent that I'm ready. */
2371 if (write(fdescs
[1].fd
, &v
, sizeof(v
)) != sizeof(v
)) {
2372 close(fdescs
[1].fd
);
2374 "failed in write() to notify the readiness to the prent");
2376 /* Wait till the parent lets me go. */
2379 close(fdescs
[1].fd
);
2384 /* The child owns fdescs[1]. */
2385 close(fdescs
[1].fd
);
2388 /* Wait till the child is ready. */
2389 if (read(fdescs
[0].fd
, &v
, sizeof(uint64_t)) != sizeof(v
)) {
2391 close(fdescs
[0].fd
);
2393 "failed in read() the readiness notification from the child");
2395 signal(SIGCHLD
, SIG_DFL
);
2401 static void report_eventfd(const struct factory
*factory _U_
,
2402 int nth
, void *data
, FILE *fp
)
2405 pid_t
*child
= data
;
2406 fprintf(fp
, "%d", *child
);
2410 static void free_eventfd(const struct factory
* factory _U_
, void *data
)
2412 pid_t child
= *(pid_t
*)data
;
2417 kill(child
, SIGCONT
);
2418 if (waitpid(child
, &wstatus
, 0) < 0)
2419 err(EXIT_FAILURE
, "failed in waitpid()");
2421 if (WIFEXITED(wstatus
)) {
2422 int s
= WEXITSTATUS(wstatus
);
2424 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2425 } else if (WIFSIGNALED(wstatus
)) {
2426 int s
= WTERMSIG(wstatus
);
2427 if (WTERMSIG(wstatus
) != 0)
2428 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2432 struct mqueue_data
{
2438 static void mqueue_data_free(struct mqueue_data
*data
)
2441 mq_unlink(data
->path
);
2442 free((void *)data
->path
);
2446 static void report_mqueue(const struct factory
*factory _U_
,
2447 int nth
, void *data
, FILE *fp
)
2450 fprintf(fp
, "%d", ((struct mqueue_data
*)data
)->pid
);
2454 static void close_mqueue(int fd
, void *data _U_
)
2459 static void free_mqueue(const struct factory
* factory _U_
, void *data
)
2461 struct mqueue_data
*mqueue_data
= data
;
2462 pid_t child
= mqueue_data
->pid
;
2465 mqueue_data_free(mqueue_data
);
2467 kill(child
, SIGCONT
);
2468 if (waitpid(child
, &wstatus
, 0) < 0)
2469 err(EXIT_FAILURE
, "failed in waitpid()");
2471 if (WIFEXITED(wstatus
)) {
2472 int s
= WEXITSTATUS(wstatus
);
2474 err(EXIT_FAILURE
, "the child process got an error: %d", s
);
2475 } else if (WIFSIGNALED(wstatus
)) {
2476 int s
= WTERMSIG(wstatus
);
2477 if (WTERMSIG(wstatus
) != 0)
2478 err(EXIT_FAILURE
, "the child process got a signal: %d", s
);
2482 static void *make_mqueue(const struct factory
*factory
, struct fdesc fdescs
[],
2483 int argc
, char ** argv
)
2485 struct mqueue_data
*mqueue_data
;
2486 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
2487 const char *spath
= ARG_STRING(path
);
2489 struct mq_attr attr
= {
2496 if (spath
[0] != '/')
2497 errx(EXIT_FAILURE
, "the path for mqueue must start with '/': %s", spath
);
2499 if (spath
[0] == '\0')
2500 err(EXIT_FAILURE
, "the path should not be empty");
2502 if (fdescs
[0].fd
== fdescs
[1].fd
)
2503 errx(EXIT_FAILURE
, "specify three different numbers as file descriptors");
2505 mqueue_data
= xmalloc(sizeof(*mqueue_data
));
2506 mqueue_data
->pid
= 0;
2507 mqueue_data
->path
= xstrdup(spath
);
2508 mqueue_data
->created
= false;
2512 fd
= mq_open(mqueue_data
->path
, O_CREAT
|O_EXCL
| O_RDONLY
, S_IRUSR
| S_IWUSR
, &attr
);
2514 mqueue_data_free(mqueue_data
);
2515 err(EXIT_FAILURE
, "failed in mq_open(3) for reading");
2518 mqueue_data
->created
= true;
2519 if (fd
!= fdescs
[0].fd
) {
2520 if (dup2(fd
, fdescs
[0].fd
) < 0) {
2523 mqueue_data_free(mqueue_data
);
2525 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
2530 fdescs
[0] = (struct fdesc
){
2532 .close
= close_mqueue
,
2536 fd
= mq_open(mqueue_data
->path
, O_WRONLY
, S_IRUSR
| S_IWUSR
, NULL
);
2539 mq_close(fdescs
[0].fd
);
2540 mqueue_data_free(mqueue_data
);
2542 err(EXIT_FAILURE
, "failed in mq_open(3) for writing");
2545 if (fd
!= fdescs
[1].fd
) {
2546 if (dup2(fd
, fdescs
[1].fd
) < 0) {
2549 mq_close(fdescs
[0].fd
);
2551 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[1].fd
);
2555 fdescs
[1] = (struct fdesc
){
2557 .close
= close_mqueue
,
2561 signal(SIGCHLD
, abort_with_child_death_message
);
2562 mqueue_data
->pid
= fork();
2563 if (mqueue_data
->pid
< -1) {
2565 mq_close(fdescs
[0].fd
);
2566 mq_close(fdescs
[1].fd
);
2567 mqueue_data_free(mqueue_data
);
2569 err(EXIT_FAILURE
, "failed in fork()");
2570 } else if (mqueue_data
->pid
== 0) {
2571 mqueue_data
->created
= false;
2572 mqueue_data_free(mqueue_data
);
2573 mq_close(fdescs
[0].fd
);
2575 signal(SIGCONT
, do_nothing
);
2576 /* Notify the parent that I'm ready. */
2577 if (mq_send(fdescs
[1].fd
, "", 0, 0) < 0)
2579 "failed in mq_send() to notify the readiness to the prent");
2580 /* Wait till the parent lets me go. */
2583 mq_close(fdescs
[1].fd
);
2588 /* The child owns fdescs[1]. */
2589 mq_close(fdescs
[1].fd
);
2592 /* Wait till the child is ready. */
2593 if (mq_receive(fdescs
[0].fd
, &c
, 1, NULL
) < 0) {
2594 mq_close(fdescs
[0].fd
);
2595 mqueue_data_free(mqueue_data
);
2597 "failed in mq_receive() the readiness notification from the child");
2599 signal(SIGCHLD
, SIG_DFL
);
2604 struct sysvshm_data
{
2609 static void *make_sysvshm(const struct factory
*factory _U_
, struct fdesc fdescs
[] _U_
,
2610 int argc _U_
, char ** argv _U_
)
2612 size_t pagesize
= getpagesize();
2613 struct sysvshm_data
*sysvshm_data
;
2614 int id
= shmget(IPC_PRIVATE
, pagesize
, IPC_CREAT
| 0600);
2618 err(EXIT_FAILURE
, "failed to do shmget(.., %zu, ...)",
2621 start
= shmat(id
, NULL
, SHM_RDONLY
);
2622 if (start
== (void *) -1) {
2624 shmctl(id
, IPC_RMID
, NULL
);
2626 err(EXIT_FAILURE
, "failed to do shmat(%d,...)", id
);
2629 sysvshm_data
= xmalloc(sizeof(*sysvshm_data
));
2630 sysvshm_data
->addr
= start
;
2631 sysvshm_data
->id
= id
;
2632 return sysvshm_data
;
2635 static void free_sysvshm(const struct factory
*factory _U_
, void *data
)
2637 struct sysvshm_data
*sysvshm_data
= data
;
2639 shmdt(sysvshm_data
->addr
);
2640 shmctl(sysvshm_data
->id
, IPC_RMID
, NULL
);
2643 static void *make_eventpoll(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2644 int argc _U_
, char ** argv _U_
)
2653 .file
= "DUMMY, DONT'USE THIS"
2655 .file
= "/dev/random",
2659 .file
= "/dev/random",
2665 efd
= epoll_create(1);
2667 err(EXIT_FAILURE
, "failed in epoll_create(2)");
2668 if (efd
!= fdescs
[0].fd
) {
2669 if (dup2(efd
, fdescs
[0].fd
) < 0) {
2673 err(EXIT_FAILURE
, "failed to dup %d -> %d", efd
, fdescs
[0].fd
);
2678 fdescs
[0] = (struct fdesc
){
2680 .close
= close_fdesc
,
2684 for (size_t i
= 1; i
< ARRAY_SIZE(specs
); i
++) {
2685 int fd
= open(specs
[i
].file
, specs
[i
].flag
);
2689 for (size_t j
= i
- 1; j
> 0; j
--)
2690 close(fdescs
[j
].fd
);
2692 err(EXIT_FAILURE
, "failed in open(\"%s\",...)",
2695 if (fd
!= fdescs
[i
].fd
) {
2696 if (dup2(fd
, fdescs
[i
].fd
) < 0) {
2699 for (size_t j
= i
- 1; j
> 0; j
--)
2700 close(fdescs
[j
].fd
);
2703 err(EXIT_FAILURE
, "failed to dup %d -> %d",
2708 fdescs
[i
] = (struct fdesc
) {
2710 .close
= close_fdesc
,
2713 if (epoll_ctl(efd
, EPOLL_CTL_ADD
, fdescs
[i
].fd
,
2714 &(struct epoll_event
) {
2715 .events
= specs
[i
].events
,
2716 .data
= {.ptr
= NULL
,}
2720 for (size_t j
= i
; j
> 0; j
--)
2721 close(fdescs
[j
].fd
);
2724 "failed to add fd %d to the eventpoll fd with epoll_ctl",
2732 static bool decode_clockid(const char *sclockid
, clockid_t
*clockid
)
2734 if (sclockid
== NULL
)
2736 if (sclockid
[0] == '\0')
2739 if (strcmp(sclockid
, "realtime") == 0)
2740 *clockid
= CLOCK_REALTIME
;
2741 else if (strcmp(sclockid
, "monotonic") == 0)
2742 *clockid
= CLOCK_MONOTONIC
;
2743 else if (strcmp(sclockid
, "boottime") == 0)
2744 *clockid
= CLOCK_BOOTTIME
;
2745 else if (strcmp(sclockid
, "realtime-alarm") == 0)
2746 *clockid
= CLOCK_REALTIME_ALARM
;
2747 else if (strcmp(sclockid
, "boottime-alarm") == 0)
2748 *clockid
= CLOCK_BOOTTIME_ALARM
;
2754 static void *make_timerfd(const struct factory
*factory
, struct fdesc fdescs
[],
2755 int argc
, char ** argv
)
2758 struct timespec now
;
2759 struct itimerspec tspec
;
2761 struct arg abstime
= decode_arg("abstime", factory
->params
, argc
, argv
);
2762 bool babstime
= ARG_BOOLEAN(abstime
);
2764 struct arg remaining
= decode_arg("remaining", factory
->params
, argc
, argv
);
2765 unsigned int uremaining
= ARG_UINTEGER(remaining
);
2767 struct arg interval
= decode_arg("interval", factory
->params
, argc
, argv
);
2768 unsigned int uinterval
= ARG_UINTEGER(interval
);
2770 struct arg interval_frac
= decode_arg("interval-nanofrac", factory
->params
, argc
, argv
);
2771 unsigned int uinterval_frac
= ARG_UINTEGER(interval_frac
);
2773 struct arg clockid_
= decode_arg("clockid", factory
->params
, argc
, argv
);
2774 const char *sclockid
= ARG_STRING(clockid_
);
2777 if (decode_clockid (sclockid
, &clockid
) == false)
2778 err(EXIT_FAILURE
, "unknown clockid: %s", sclockid
);
2780 free_arg(&clockid_
);
2781 free_arg(&interval_frac
);
2782 free_arg(&interval
);
2783 free_arg(&remaining
);
2787 int r
= clock_gettime(clockid
, &now
);
2789 err(EXIT_FAILURE
, "failed in clock_gettime(2)");
2792 tfd
= timerfd_create(clockid
, 0);
2794 err(EXIT_FAILURE
, "failed in timerfd_create(2)");
2796 tspec
.it_value
.tv_sec
= (babstime
? now
.tv_sec
: 0) + uremaining
;
2797 tspec
.it_value
.tv_nsec
= (babstime
? now
.tv_nsec
: 0);
2799 tspec
.it_interval
.tv_sec
= uinterval
;
2800 tspec
.it_interval
.tv_nsec
= uinterval_frac
;
2802 if (timerfd_settime(tfd
, babstime
? TFD_TIMER_ABSTIME
: 0, &tspec
, NULL
) < 0) {
2806 err(EXIT_FAILURE
, "failed in timerfd_settime(2)");
2809 if (tfd
!= fdescs
[0].fd
) {
2810 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2814 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2819 fdescs
[0] = (struct fdesc
){
2821 .close
= close_fdesc
,
2828 static void *make_signalfd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2829 int argc _U_
, char ** argv _U_
)
2834 if (sigemptyset(&mask
) < 0)
2835 err(EXIT_FAILURE
, "failed in sigemptyset()");
2836 if (sigaddset(&mask
, SIGFPE
) < 0)
2837 err(EXIT_FAILURE
, "failed in sigaddset(FPE)");
2838 if (sigaddset(&mask
, SIGUSR1
) < 0)
2839 err(EXIT_FAILURE
, "failed in sigaddset(USR1)");
2840 if (sigaddset(&mask
, numsig
) < 0)
2841 err(EXIT_FAILURE
, "failed in sigaddset(%d)", numsig
);
2843 int sfd
= signalfd(-1, &mask
, 0);
2845 err(EXIT_FAILURE
, "failed in signalfd(2)");
2847 if (sfd
!= fdescs
[0].fd
) {
2848 if (dup2(sfd
, fdescs
[0].fd
) < 0) {
2852 err(EXIT_FAILURE
, "failed to dup %d -> %d", sfd
, fdescs
[0].fd
);
2857 fdescs
[0] = (struct fdesc
){
2859 .close
= close_fdesc
,
2867 /* ref. linux/Documentation/networking/tuntap.rst */
2868 static void *make_cdev_tun(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2869 int argc _U_
, char ** argv _U_
)
2871 int tfd
= open("/dev/net/tun", O_RDWR
);
2875 err(EXIT_FAILURE
, "failed in opening /dev/net/tun");
2877 memset(&ifr
, 0, sizeof(ifr
));
2879 ifr
.ifr_flags
= IFF_TUN
;
2880 strcpy(ifr
.ifr_name
, "mkfds%d");
2882 if (ioctl(tfd
, TUNSETIFF
, (void *) &ifr
) < 0) {
2886 err(EXIT_FAILURE
, "failed in setting \"lo\" to the tun device");
2889 if (tfd
!= fdescs
[0].fd
) {
2890 if (dup2(tfd
, fdescs
[0].fd
) < 0) {
2894 err(EXIT_FAILURE
, "failed to dup %d -> %d", tfd
, fdescs
[0].fd
);
2899 fdescs
[0] = (struct fdesc
){
2901 .close
= close_fdesc
,
2905 return xstrdup(ifr
.ifr_name
);
2908 static void report_cdev_tun(const struct factory
*factory _U_
,
2909 int nth
, void *data
, FILE *fp
)
2912 char *devname
= data
;
2913 fprintf(fp
, "%s", devname
);
2917 static void free_cdev_tun(const struct factory
* factory _U_
, void *data
)
2922 static void *make_bpf_prog(const struct factory
*factory
, struct fdesc fdescs
[],
2923 int argc
, char ** argv
)
2925 struct arg prog_type_id
= decode_arg("prog-type-id", factory
->params
, argc
, argv
);
2926 int iprog_type_id
= ARG_INTEGER(prog_type_id
);
2928 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
2929 const char *sname
= ARG_STRING(name
);
2932 union bpf_attr attr
;
2933 /* Just doing exit with 0. */
2934 struct bpf_insn insns
[] = {
2936 .code
= BPF_ALU64
| BPF_MOV
| BPF_K
,
2937 .dst_reg
= BPF_REG_0
, .src_reg
= 0, .off
= 0, .imm
= 0
2940 .code
= BPF_JMP
| BPF_EXIT
,
2941 .dst_reg
= 0, .src_reg
= 0, .off
= 0, .imm
= 0
2945 memset(&attr
, 0, sizeof(attr
));
2946 attr
.prog_type
= iprog_type_id
;
2947 attr
.insns
= (uint64_t)(unsigned long)insns
;
2948 attr
.insn_cnt
= ARRAY_SIZE(insns
);
2949 attr
.license
= (int64_t)(unsigned long)"GPL";
2950 strncpy(attr
.prog_name
, sname
, sizeof(attr
.prog_name
) - 1);
2953 free_arg(&prog_type_id
);
2955 bfd
= syscall(SYS_bpf
, BPF_PROG_LOAD
, &attr
, sizeof(attr
));
2957 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_PROG_LOAD)");
2959 if (bfd
!= fdescs
[0].fd
) {
2960 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
2964 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
2969 fdescs
[0] = (struct fdesc
){
2971 .close
= close_fdesc
,
2978 static void *make_some_pipes(const struct factory
*factory _U_
, struct fdesc fdescs
[],
2979 int argc _U_
, char ** argv _U_
)
2981 /* Reserver fds before making pipes */
2982 for (int i
= 0; i
< factory
->N
; i
++) {
2983 close(fdescs
[i
].fd
);
2984 if (dup2(0, fdescs
[0].fd
) < 0)
2985 err(EXIT_FAILURE
, "failed to reserve fd %d with dup2", fdescs
[0].fd
);
2988 for (int i
= 0; i
< (factory
->N
) / 2; i
++) {
2993 mode
= 1 << (i
% 3);
2994 if (mode
== MX_WRITE
) {
3000 err(EXIT_FAILURE
, "failed to make pipe");
3002 if (dup2(pd
[0], fdescs
[2 * i
+ r
].fd
) < 0)
3003 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[0], fdescs
[2 * i
+ r
].fd
);
3005 fdescs
[2 * 1 + r
].close
= close_fdesc
;
3007 if (dup2(pd
[1], fdescs
[2 * i
+ w
].fd
) < 0)
3008 err(EXIT_FAILURE
, "failed to dup %d -> %d", pd
[1], fdescs
[2 * i
+ 2].fd
);
3010 fdescs
[2 * 1 + w
].close
= close_fdesc
;
3012 fdescs
[2 * i
].mx_modes
|= mode
;
3014 /* Make the pipe for writing full. */
3015 if (fdescs
[2 * i
].mx_modes
& MX_WRITE
) {
3016 int n
= fcntl(fdescs
[2 * i
].fd
, F_GETPIPE_SZ
);
3020 err(EXIT_FAILURE
, "failed to get PIPE BUFFER SIZE from %d", fdescs
[2 * i
].fd
);
3023 if (write(fdescs
[2 * i
].fd
, buf
, n
) != n
)
3024 err(EXIT_FAILURE
, "failed to fill the pipe buffer specified with %d",
3034 static void *make_bpf_map(const struct factory
*factory
, struct fdesc fdescs
[],
3035 int argc
, char ** argv
)
3037 struct arg map_type_id
= decode_arg("map-type-id", factory
->params
, argc
, argv
);
3038 int imap_type_id
= ARG_INTEGER(map_type_id
);
3040 struct arg name
= decode_arg("name", factory
->params
, argc
, argv
);
3041 const char *sname
= ARG_STRING(name
);
3044 union bpf_attr attr
= {
3045 .map_type
= imap_type_id
,
3051 strncpy(attr
.map_name
, sname
, sizeof(attr
.map_name
) - 1);
3054 free_arg(&map_type_id
);
3056 bfd
= syscall(SYS_bpf
, BPF_MAP_CREATE
, &attr
, sizeof(attr
));
3058 err_nosys(EXIT_FAILURE
, "failed in bpf(BPF_MAP_CREATE)");
3060 if (bfd
!= fdescs
[0].fd
) {
3061 if (dup2(bfd
, fdescs
[0].fd
) < 0) {
3065 err(EXIT_FAILURE
, "failed to dup %d -> %d", bfd
, fdescs
[0].fd
);
3070 fdescs
[0] = (struct fdesc
){
3072 .close
= close_fdesc
,
3079 static void *make_pty(const struct factory
*factory _U_
, struct fdesc fdescs
[],
3080 int argc _U_
, char ** argv _U_
)
3085 int ptmx_fd
= posix_openpt(O_RDWR
);
3087 err(EXIT_FAILURE
, "failed in opening /dev/ptmx");
3089 if (unlockpt(ptmx_fd
) < 0) {
3093 err(EXIT_FAILURE
, "failed in unlockpt()");
3096 if (ioctl(ptmx_fd
, TIOCGPTN
, &index
) < 0) {
3100 err(EXIT_FAILURE
, "failed in ioctl(TIOCGPTN)");
3103 pts
= ptsname(ptmx_fd
);
3108 err(EXIT_FAILURE
, "failed in ptsname()");
3111 if (ptmx_fd
!= fdescs
[0].fd
) {
3112 if (dup2(ptmx_fd
, fdescs
[0].fd
) < 0) {
3116 err(EXIT_FAILURE
, "failed to dup %d -> %d", ptmx_fd
, fdescs
[0].fd
);
3119 ptmx_fd
= fdescs
[0].fd
;
3122 pts_fd
= open(pts
, O_RDONLY
);
3127 err(EXIT_FAILURE
, "failed in opening %s", pts
);
3130 if (pts_fd
!= fdescs
[1].fd
) {
3131 if (dup2(pts_fd
, fdescs
[1].fd
) < 0) {
3136 err(EXIT_FAILURE
, "failed to dup %d -> %d", pts_fd
, fdescs
[1].fd
);
3139 pts_fd
= fdescs
[1].fd
;
3142 fdescs
[0] = (struct fdesc
){
3144 .close
= close_fdesc
,
3147 fdescs
[1] = (struct fdesc
){
3149 .close
= close_fdesc
,
3153 indexp
= xmalloc(sizeof(index
));
3158 static void report_pty(const struct factory
*factory _U_
,
3159 int nth
, void *data
, FILE *fp
)
3163 fprintf(fp
, "%d", *index
);
3167 static void free_pty(const struct factory
* factory _U_
, void *data
)
3177 static void *make_mmap(const struct factory
*factory
, struct fdesc fdescs
[] _U_
,
3178 int argc
, char ** argv
)
3180 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
3181 const char *sfile
= ARG_STRING(file
);
3183 int fd
= open(sfile
, O_RDONLY
);
3185 err(EXIT_FAILURE
, "failed in opening %s", sfile
);
3189 if (fstat(fd
, &sb
) < 0) {
3193 err(EXIT_FAILURE
, "failed in fstat()");
3195 char *addr
= mmap(NULL
, sb
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
3196 if (addr
== MAP_FAILED
) {
3200 err(EXIT_FAILURE
, "failed in mmap()");
3204 struct mmap_data
*data
= xmalloc(sizeof(*data
));
3206 data
->len
= sb
.st_size
;
3211 /* Do as unshare --map-root-user. */
3212 static void map_root_user(uid_t uid
, uid_t gid
)
3219 n
= snprintf(buf
, sizeof(buf
), "0 %d 1", uid
);
3220 mapfd
= open("/proc/self/uid_map", O_WRONLY
);
3223 "failed to open /proc/self/uid_map");
3224 r
= write (mapfd
, buf
, n
);
3227 "failed to write to /proc/self/uid_map");
3230 "failed to write to /proc/self/uid_map");
3233 mapfd
= open("/proc/self/setgroups", O_WRONLY
);
3236 "failed to open /proc/self/setgroups");
3237 r
= write (mapfd
, "deny", 4);
3240 "failed to write to /proc/self/setgroups");
3243 "failed to write to /proc/self/setgroups");
3246 n
= snprintf(buf
, sizeof(buf
), "0 %d 1", gid
);
3247 mapfd
= open("/proc/self/gid_map", O_WRONLY
);
3250 "failed to open /proc/self/gid_map");
3251 r
= write (mapfd
, buf
, n
);
3254 "failed to write to /proc/self/gid_map");
3257 "failed to write to /proc/self/gid_map");
3261 static void *make_userns(const struct factory
*factory _U_
, struct fdesc fdescs
[],
3262 int argc _U_
, char ** argv _U_
)
3264 uid_t uid
= geteuid();
3265 uid_t gid
= getegid();
3267 if (unshare(CLONE_NEWUSER
) < 0)
3268 err((errno
== EPERM
? EXIT_EPERM
: EXIT_FAILURE
),
3269 "failed in the 1st unshare(2)");
3271 map_root_user(uid
, gid
);
3273 int userns
= open("/proc/self/ns/user", O_RDONLY
);
3275 err(EXIT_FAILURE
, "failed to open /proc/self/ns/user for the new user ns");
3277 if (unshare(CLONE_NEWUSER
) < 0) {
3281 err((errno
== EPERM
? EXIT_EPERM
: EXIT_FAILURE
),
3282 "failed in the 2nd unshare(2)");
3285 if (userns
!= fdescs
[0].fd
) {
3286 if (dup2(userns
, fdescs
[0].fd
) < 0) {
3290 err(EXIT_FAILURE
, "failed to dup %d -> %d", userns
, fdescs
[0].fd
);
3295 fdescs
[0] = (struct fdesc
){
3297 .close
= close_fdesc
,
3304 static void free_mmap(const struct factory
* factory _U_
, void *data
)
3306 munmap(((struct mmap_data
*)data
)->addr
,
3307 ((struct mmap_data
*)data
)->len
);
3310 #define PARAM_END { .name = NULL, }
3311 static const struct factory factories
[] = {
3313 .name
= "ro-regular-file",
3314 .desc
= "read-only regular file",
3318 .make
= open_ro_regular_file
,
3319 .params
= (struct parameter
[]) {
3322 .type
= PTYPE_STRING
,
3323 .desc
= "file to be opened",
3324 .defv
.string
= "/etc/passwd",
3328 .type
= PTYPE_INTEGER
,
3329 .desc
= "seek bytes after open with SEEK_CUR",
3333 .name
= "read-lease",
3334 .type
= PTYPE_BOOLEAN
,
3335 .desc
= "taking out read lease for the file",
3336 .defv
.boolean
= false,
3342 .name
= "make-regular-file",
3343 .desc
= "regular file for writing",
3347 .make
= make_w_regular_file
,
3348 .free
= free_after_closing_duplicated_fd
,
3349 .params
= (struct parameter
[]) {
3352 .type
= PTYPE_STRING
,
3353 .desc
= "file to be made",
3354 .defv
.string
= "./test_mkfds_make_regular_file",
3358 .type
= PTYPE_BOOLEAN
,
3359 .desc
= "delete the file just after making it",
3360 .defv
.boolean
= false,
3363 .name
= "write-bytes",
3364 .type
= PTYPE_INTEGER
,
3365 .desc
= "write something (> 0)",
3370 .type
= PTYPE_BOOLEAN
,
3371 .desc
= "open the new file readable way",
3372 .defv
.string
= false,
3376 .type
= PTYPE_STRING
,
3377 .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",
3378 .defv
.string
= "none",
3382 .type
= PTYPE_INTEGER
,
3383 .desc
= "the number for the fd duplicated from the original fd",
3390 .name
= "pipe-no-fork",
3391 .desc
= "making pair of fds with pipe(2)",
3396 .params
= (struct parameter
[]) {
3399 .type
= PTYPE_STRING
,
3400 .desc
= "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")",
3401 .defv
.string
= "--",
3405 .type
= PTYPE_INTEGER
,
3406 .desc
= "file descriptor for duplicating the pipe input",
3411 .type
= PTYPE_INTEGER
,
3412 .desc
= "file descriptor for duplicating the pipe output",
3419 .name
= "directory",
3420 .desc
= "directory",
3424 .make
= open_directory
,
3425 .params
= (struct parameter
[]) {
3428 .type
= PTYPE_STRING
,
3429 .desc
= "directory to be opened",
3434 .type
= PTYPE_INTEGER
,
3435 .desc
= "read the number of dentries after open with readdir(3)",
3442 .name
= "rw-character-device",
3443 .desc
= "character device with O_RDWR flag",
3447 .make
= open_rw_chrdev
,
3448 .params
= (struct parameter
[]) {
3451 .type
= PTYPE_STRING
,
3452 .desc
= "character device node to be opened",
3453 .defv
.string
= "/dev/zero",
3459 .name
= "socketpair",
3460 .desc
= "AF_UNIX socket pair created with socketpair(2)",
3464 .make
= make_socketpair
,
3465 .params
= (struct parameter
[]) {
3468 .type
= PTYPE_STRING
,
3469 .desc
= "STREAM, DGRAM, or SEQPACKET",
3470 .defv
.string
= "STREAM",
3473 .name
= "halfclose",
3474 .type
= PTYPE_BOOLEAN
,
3475 .desc
= "Shutdown the read end of the 1st socket, the write end of the 2nd socket",
3476 .defv
.boolean
= false,
3483 .desc
= "symbolic link itself opened with O_PATH",
3487 .make
= open_with_opath
,
3488 .params
= (struct parameter
[]) {
3491 .type
= PTYPE_STRING
,
3492 .desc
= "path to a symbolic link",
3493 .defv
.string
= "/dev/stdin",
3499 .name
= "ro-block-device",
3500 .desc
= "block device with O_RDONLY flag",
3504 .make
= open_ro_blkdev
,
3505 .params
= (struct parameter
[]) {
3508 .type
= PTYPE_STRING
,
3509 .desc
= "block device node to be opened",
3510 .defv
.string
= "/dev/nullb0",
3516 .name
= "mapped-packet-socket",
3517 .desc
= "mmap'ed AF_PACKET socket",
3521 .make
= make_mmapped_packet_socket
,
3522 .params
= (struct parameter
[]) {
3525 .type
= PTYPE_STRING
,
3526 .desc
= "DGRAM or RAW",
3527 .defv
.string
= "RAW",
3530 .name
= "interface",
3531 .type
= PTYPE_STRING
,
3532 .desc
= "a name of network interface like eth0 or lo",
3533 .defv
.string
= "lo",
3540 .desc
= "pidfd returned from pidfd_open(2)",
3545 .params
= (struct parameter
[]) {
3547 .name
= "target-pid",
3548 .type
= PTYPE_INTEGER
,
3549 .desc
= "the pid of the target process",
3557 .desc
= "inotify fd returned from inotify_init(2)",
3561 .make
= make_inotify_fd
,
3562 .params
= (struct parameter
[]) {
3565 .type
= PTYPE_STRING
,
3566 .desc
= "the directory that the inotify monitors",
3571 .type
= PTYPE_STRING
,
3572 .desc
= "the file that the inotify monitors",
3573 .defv
.string
= "/etc/fstab",
3579 .name
= "unix-stream",
3580 .desc
= "AF_UNIX+SOCK_STREAM sockets",
3584 .make
= make_unix_stream
,
3585 .params
= (struct parameter
[]) {
3588 .type
= PTYPE_STRING
,
3589 .desc
= "path for listening-socket bound to",
3590 .defv
.string
= "/tmp/test_mkfds-unix-stream",
3594 .type
= PTYPE_INTEGER
,
3595 .desc
= "backlog passed to listen(2)",
3600 .type
= PTYPE_BOOLEAN
,
3601 .desc
= "use PATH as an abstract socket address",
3602 .defv
.boolean
= false,
3605 .name
= "server-shutdown",
3606 .type
= PTYPE_INTEGER
,
3607 .desc
= "shutdown the accepted socket; 1: R, 2: W, 3: RW",
3611 .name
= "client-shutdown",
3612 .type
= PTYPE_INTEGER
,
3613 .desc
= "shutdown the client socket; 1: R, 2: W, 3: RW",
3618 .type
= PTYPE_STRING
,
3619 .desc
= "stream or seqpacket",
3620 .defv
.string
= "stream",
3626 .name
= "unix-dgram",
3627 .desc
= "AF_UNIX+SOCK_DGRAM sockets",
3631 .make
= make_unix_dgram
,
3632 .params
= (struct parameter
[]) {
3635 .type
= PTYPE_STRING
,
3636 .desc
= "path for unix non-stream bound to",
3637 .defv
.string
= "/tmp/test_mkfds-unix-dgram",
3641 .type
= PTYPE_BOOLEAN
,
3642 .desc
= "use PATH as an abstract socket address",
3643 .defv
.boolean
= false,
3649 .name
= "unix-in-netns",
3650 .desc
= "make a unix socket in a new network namespace",
3654 .make
= make_unix_in_new_netns
,
3655 .params
= (struct parameter
[]) {
3658 .type
= PTYPE_STRING
,
3659 .desc
= "dgram, stream, or seqpacket",
3660 .defv
.string
= "stream",
3664 .type
= PTYPE_STRING
,
3665 .desc
= "path for unix non-stream bound to",
3666 .defv
.string
= "/tmp/test_mkfds-unix-in-netns",
3670 .type
= PTYPE_BOOLEAN
,
3671 .desc
= "use PATH as an abstract socket address",
3672 .defv
.boolean
= false,
3679 .desc
= "AF_INET+SOCK_STREAM sockets",
3684 .params
= (struct parameter
[]) {
3686 .name
= "server-port",
3687 .type
= PTYPE_INTEGER
,
3688 .desc
= "TCP port the server may listen",
3689 .defv
.integer
= 12345,
3692 .name
= "client-port",
3693 .type
= PTYPE_INTEGER
,
3694 .desc
= "TCP port the client may bind",
3695 .defv
.integer
= 23456,
3702 .desc
= "AF_INET+SOCK_DGRAM sockets",
3707 .params
= (struct parameter
[]) {
3710 .type
= PTYPE_BOOLEAN
,
3711 .desc
= "Use UDPLITE instead of UDP",
3712 .defv
.boolean
= false,
3715 .name
= "server-port",
3716 .type
= PTYPE_INTEGER
,
3717 .desc
= "UDP port the server may listen",
3718 .defv
.integer
= 12345,
3721 .name
= "client-port",
3722 .type
= PTYPE_INTEGER
,
3723 .desc
= "UDP port the client may bind",
3724 .defv
.integer
= 23456,
3727 .name
= "server-do-bind",
3728 .type
= PTYPE_BOOLEAN
,
3729 .desc
= "call bind with the server socket",
3730 .defv
.boolean
= true,
3733 .name
= "client-do-bind",
3734 .type
= PTYPE_BOOLEAN
,
3735 .desc
= "call bind with the client socket",
3736 .defv
.boolean
= true,
3739 .name
= "client-do-connect",
3740 .type
= PTYPE_BOOLEAN
,
3741 .desc
= "call connect with the client socket",
3742 .defv
.boolean
= true,
3749 .desc
= "AF_INET+SOCK_RAW sockets",
3754 .params
= (struct parameter
[]) {
3757 .type
= PTYPE_INTEGER
,
3758 .desc
= "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
3759 .defv
.integer
= IPPROTO_IPIP
,
3767 .desc
= "AF_INET+SOCK_DGRAM+IPPROTO_ICMP sockets",
3772 .params
= (struct parameter
[]) {
3775 .type
= PTYPE_BOOLEAN
,
3776 .desc
= "call connect(2) with the socket",
3777 .defv
.boolean
= true,
3781 .type
= PTYPE_BOOLEAN
,
3782 .desc
= "call bind(2) with the socket",
3783 .defv
.boolean
= true,
3787 .type
= PTYPE_INTEGER
,
3788 .desc
= "ICMP echo request id",
3796 .desc
= "AF_INET6+SOCK_STREAM sockets",
3801 .params
= (struct parameter
[]) {
3803 .name
= "server-port",
3804 .type
= PTYPE_INTEGER
,
3805 .desc
= "TCP port the server may listen",
3806 .defv
.integer
= 12345,
3809 .name
= "client-port",
3810 .type
= PTYPE_INTEGER
,
3811 .desc
= "TCP port the client may bind",
3812 .defv
.integer
= 23456,
3819 .desc
= "AF_INET6+SOCK_DGRAM sockets",
3824 .params
= (struct parameter
[]) {
3827 .type
= PTYPE_BOOLEAN
,
3828 .desc
= "Use UDPLITE instead of UDP",
3829 .defv
.boolean
= false,
3832 .name
= "server-port",
3833 .type
= PTYPE_INTEGER
,
3834 .desc
= "UDP port the server may listen",
3835 .defv
.integer
= 12345,
3838 .name
= "client-port",
3839 .type
= PTYPE_INTEGER
,
3840 .desc
= "UDP port the client may bind",
3841 .defv
.integer
= 23456,
3844 .name
= "server-do-bind",
3845 .type
= PTYPE_BOOLEAN
,
3846 .desc
= "call bind with the server socket",
3847 .defv
.boolean
= true,
3850 .name
= "client-do-bind",
3851 .type
= PTYPE_BOOLEAN
,
3852 .desc
= "call bind with the client socket",
3853 .defv
.boolean
= true,
3856 .name
= "client-do-connect",
3857 .type
= PTYPE_BOOLEAN
,
3858 .desc
= "call connect with the client socket",
3859 .defv
.boolean
= true,
3866 .desc
= "AF_INET6+SOCK_RAW sockets",
3871 .params
= (struct parameter
[]) {
3874 .type
= PTYPE_INTEGER
,
3875 .desc
= "protocol passed to socket(AF_INET6, SOCK_RAW, protocol)",
3876 .defv
.integer
= IPPROTO_IPIP
,
3884 .desc
= "AF_INET6+SOCK_DGRAM+IPPROTO_ICMPV6 sockets",
3889 .params
= (struct parameter
[]) {
3892 .type
= PTYPE_BOOLEAN
,
3893 .desc
= "call connect(2) with the socket",
3894 .defv
.boolean
= true,
3898 .type
= PTYPE_BOOLEAN
,
3899 .desc
= "call bind(2) with the socket",
3900 .defv
.boolean
= true,
3904 .type
= PTYPE_INTEGER
,
3905 .desc
= "ICMP echo request id",
3914 .desc
= "open a file specifying a netns",
3919 .params
= (struct parameter
[]) {
3926 .desc
= "AF_NETLINK sockets",
3930 .make
= make_netlink
,
3931 .params
= (struct parameter
[]) {
3934 .type
= PTYPE_INTEGER
,
3935 .desc
= "protocol passed to socket(AF_NETLINK, SOCK_RAW, protocol)",
3936 .defv
.integer
= NETLINK_USERSOCK
,
3940 .type
= PTYPE_UINTEGER
,
3941 .desc
= "multicast groups of netlink communication (requires CAP_NET_ADMIN)",
3949 .desc
= "make an eventfd connecting two processes",
3954 .make
= make_eventfd
,
3955 .report
= report_eventfd
,
3956 .free
= free_eventfd
,
3957 .params
= (struct parameter
[]) {
3963 .desc
= "make a mqueue connecting two processes",
3968 .make
= make_mqueue
,
3969 .report
= report_mqueue
,
3970 .free
= free_mqueue
,
3971 .params
= (struct parameter
[]) {
3974 .type
= PTYPE_STRING
,
3975 .desc
= "path for mqueue",
3976 .defv
.string
= "/test_mkfds-mqueue",
3983 .desc
= "shared memory mapped with SYSVIPC shmem syscalls",
3987 .make
= make_sysvshm
,
3988 .free
= free_sysvshm
,
3989 .params
= (struct parameter
[]) {
3994 .name
= "eventpoll",
3995 .desc
= "make eventpoll (epoll) file",
3999 .make
= make_eventpoll
,
4000 .params
= (struct parameter
[]) {
4006 .desc
= "make timerfd",
4010 .make
= make_timerfd
,
4011 .params
= (struct parameter
[]) {
4014 .type
= PTYPE_STRING
,
4015 .desc
= "ID: realtime, monotonic, boottime, realtime-alarm, or boottime-alarm",
4016 .defv
.string
= "realtime",
4020 .type
= PTYPE_BOOLEAN
,
4021 .desc
= "use TFD_TIMER_ABSTIME flag",
4022 .defv
.boolean
= false,
4025 .name
= "remaining",
4026 .type
= PTYPE_UINTEGER
,
4027 .desc
= "remaining seconds for expiration",
4028 .defv
.uinteger
= 99,
4032 .type
= PTYPE_UINTEGER
,
4033 .desc
= "inteval in seconds",
4034 .defv
.uinteger
= 10,
4037 .name
= "interval-nanofrac",
4038 .type
= PTYPE_UINTEGER
,
4039 .desc
= "nsec part of inteval",
4048 .desc
= "make signalfd",
4052 .make
= make_signalfd
,
4053 .params
= (struct parameter
[]) {
4059 .desc
= "open /dev/net/tun",
4064 .make
= make_cdev_tun
,
4065 .report
= report_cdev_tun
,
4066 .free
= free_cdev_tun
,
4067 .params
= (struct parameter
[]) {
4073 .desc
= "make bpf-prog",
4077 .make
= make_bpf_prog
,
4078 .params
= (struct parameter
[]) {
4080 .name
= "prog-type-id",
4081 .type
= PTYPE_INTEGER
,
4082 .desc
= "program type by id",
4087 .type
= PTYPE_STRING
,
4088 .desc
= "name assigned to bpf prog object",
4089 .defv
.string
= "mkfds_bpf_prog",
4095 .name
= "multiplexing",
4096 .desc
= "make pipes monitored by multiplexers",
4100 .make
= make_some_pipes
,
4101 .params
= (struct parameter
[]) {
4107 .desc
= "make bpf-map",
4111 .make
= make_bpf_map
,
4112 .params
= (struct parameter
[]) {
4114 .name
= "map-type-id",
4115 .type
= PTYPE_INTEGER
,
4116 .desc
= "map type by id",
4121 .type
= PTYPE_STRING
,
4122 .desc
= "name assigned to the bpf map object",
4123 .defv
.string
= "mkfds_bpf_map",
4130 .desc
= "make a pair of ptmx and pts",
4136 .report
= report_pty
,
4138 .params
= (struct parameter
[]) {
4144 .desc
= "do mmap the given file",
4150 .params
= (struct parameter
[]) {
4153 .type
= PTYPE_STRING
,
4154 .desc
= "file to be opened",
4155 .defv
.string
= "/etc/passwd",
4162 .desc
= "open a user namespae",
4166 .make
= make_userns
,
4167 .params
= (struct parameter
[]) {
4173 static int count_parameters(const struct factory
*factory
)
4176 const struct parameter
*p
= factory
->params
;
4181 return p
- factory
->params
;
4184 static void print_factory(const struct factory
*factory
)
4186 printf("%-20s %4s %5d %7d %6d %s\n",
4188 factory
->priv
? "yes": "no",
4191 count_parameters(factory
),
4195 static void list_factories(void)
4197 printf("%-20s PRIV COUNT NRETURN NPARAM DESCRIPTION\n", "FACTORY");
4198 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4199 print_factory(factories
+ i
);
4202 static const struct factory
*find_factory(const char *name
)
4204 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4205 if (strcmp(factories
[i
].name
, name
) == 0)
4206 return factories
+ i
;
4210 static void list_parameters(const char *factory_name
)
4212 const struct factory
*factory
= find_factory(factory_name
);
4213 const char *fmt
= "%-15s %-8s %15s %s\n";
4216 errx(EXIT_FAILURE
, "no such factory: %s", factory_name
);
4218 if (!factory
->params
)
4221 printf(fmt
, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION");
4222 for (const struct parameter
*p
= factory
->params
; p
->name
!= NULL
; p
++) {
4223 char *defv
= ptype_classes
[p
->type
].sprint(&p
->defv
);
4224 printf(fmt
, p
->name
, ptype_classes
[p
->type
].name
, defv
, p
->desc
);
4229 static void rename_self(const char *comm
)
4231 if (prctl(PR_SET_NAME
, (unsigned long)comm
, 0, 0, 0) < 0)
4232 err(EXIT_FAILURE
, "failed to rename self via prctl: %s", comm
);
4235 static void do_nothing(int signum _U_
)
4239 #ifdef __NR_pidfd_open
4242 pidfd_open(pid_t pid
, unsigned int flags
)
4244 return syscall(__NR_pidfd_open
, pid
, flags
);
4248 pidfd_open(pid_t pid _U_
, unsigned int flags _U_
)
4258 struct multiplexer
{
4260 void (*fn
)(bool, struct fdesc
*fdescs
, size_t n_fdescs
);
4263 #if defined(__NR_select) || defined(__NR_poll)
4264 static void sighandler_nop(int si _U_
)
4270 #define DEFUN_WAIT_EVENT_SELECT(NAME,SYSCALL,XDECLS,SETUP_SIG_HANDLER,SYSCALL_INVOCATION) \
4271 static void wait_event_##NAME(bool add_stdin, struct fdesc *fdescs, size_t n_fdescs) \
4279 FD_ZERO(&readfds); \
4280 FD_ZERO(&writefds); \
4281 FD_ZERO(&exceptfds); \
4282 /* Monitor the standard input only when the process \
4283 * is in foreground. */ \
4286 FD_SET(0, &readfds); \
4289 for (size_t i = 0; i < n_fdescs; i++) { \
4290 if (fdescs[i].mx_modes & MX_READ) { \
4291 n = max(n, fdescs[i].fd + 1); \
4292 FD_SET(fdescs[i].fd, &readfds); \
4294 if (fdescs[i].mx_modes & MX_WRITE) { \
4295 n = max(n, fdescs[i].fd + 1); \
4296 FD_SET(fdescs[i].fd, &writefds); \
4298 if (fdescs[i].mx_modes & MX_EXCEPT) { \
4299 n = max(n, fdescs[i].fd + 1); \
4300 FD_SET(fdescs[i].fd, &exceptfds); \
4306 if (SYSCALL_INVOCATION < 0 \
4307 && errno != EINTR) \
4308 err(EXIT_FAILURE, "failed in " SYSCALL); \
4311 DEFUN_WAIT_EVENT_SELECT(default,
4314 sigemptyset(&sigset
);,
4315 pselect(n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4317 #ifdef __NR_pselect6
4318 DEFUN_WAIT_EVENT_SELECT(pselect6
,
4321 sigemptyset(&sigset
);,
4322 syscall(__NR_pselect6
, n
, &readfds
, &writefds
, &exceptfds
, NULL
, &sigset
))
4326 DEFUN_WAIT_EVENT_SELECT(select
,
4329 signal(SIGCONT
,sighandler_nop
);,
4330 syscall(__NR_select
, n
, &readfds
, &writefds
, &exceptfds
, NULL
))
4334 static DEFUN_WAIT_EVENT_POLL(poll
,
4337 signal(SIGCONT
,sighandler_nop
);,
4338 syscall(__NR_poll
, pfds
, n
, -1))
4341 #define DEFAULT_MULTIPLEXER 0
4342 static struct multiplexer multiplexers
[] = {
4345 .fn
= wait_event_default
,
4347 #ifdef __NR_pselect6
4350 .fn
= wait_event_pselect6
,
4356 .fn
= wait_event_select
,
4362 .fn
= wait_event_poll
,
4368 .fn
= wait_event_ppoll
,
4373 static struct multiplexer
*lookup_multiplexer(const char *name
)
4375 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4376 if (strcmp(name
, multiplexers
[i
].name
) == 0)
4377 return multiplexers
+ i
;
4381 static void list_multiplexers(void)
4384 for (size_t i
= 0; i
< ARRAY_SIZE(multiplexers
); i
++)
4385 puts(multiplexers
[i
].name
);
4388 static bool is_available(const char *factory
)
4390 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
4391 if (strcmp(factories
[i
].name
, factory
) == 0)
4397 int main(int argc
, char **argv
)
4400 const struct factory
*factory
;
4401 struct fdesc fdescs
[MAX_N
];
4405 bool monitor_stdin
= true;
4407 struct multiplexer
*wait_event
= NULL
;
4409 static const struct option longopts
[] = {
4410 { "is-available",required_argument
,NULL
, 'a' },
4411 { "list", no_argument
, NULL
, 'l' },
4412 { "parameters", required_argument
, NULL
, 'I' },
4413 { "comm", required_argument
, NULL
, 'r' },
4414 { "quiet", no_argument
, NULL
, 'q' },
4415 { "dont-monitor-stdin", no_argument
, NULL
, 'X' },
4416 { "dont-puase", no_argument
, NULL
, 'c' },
4417 { "wait-with", required_argument
, NULL
, 'w' },
4418 { "multiplexers",no_argument
,NULL
, 'W' },
4419 { "help", no_argument
, NULL
, 'h' },
4420 { NULL
, 0, NULL
, 0 },
4423 while ((c
= getopt_long(argc
, argv
, "a:lhqcI:r:w:WX", longopts
, NULL
)) != -1) {
4426 usage(stdout
, EXIT_SUCCESS
);
4428 exit(is_available(optarg
)? 0: 1);
4433 list_parameters(optarg
);
4442 wait_event
= lookup_multiplexer(optarg
);
4443 if (wait_event
== NULL
)
4444 errx(EXIT_FAILURE
, "unknown multiplexer: %s", optarg
);
4447 list_multiplexers();
4450 rename_self(optarg
);
4453 monitor_stdin
= false;
4456 usage(stderr
, EXIT_FAILURE
);
4461 errx(EXIT_FAILURE
, "no file descriptor specification given");
4463 if (cont
&& wait_event
)
4464 errx(EXIT_FAILURE
, "don't specify both -c/--dont-puase and -w/--wait-with options");
4465 if (wait_event
== NULL
)
4466 wait_event
= multiplexers
+ DEFAULT_MULTIPLEXER
;
4468 factory
= find_factory(argv
[optind
]);
4470 errx(EXIT_FAILURE
, "no such factory: %s", argv
[optind
]);
4471 assert(factory
->N
+ factory
->EX_N
< MAX_N
);
4474 if ((optind
+ factory
->N
) > argc
)
4475 errx(EXIT_FAILURE
, "not enough file descriptors given for %s",
4478 if (factory
->priv
&& getuid() != 0)
4479 errx(EXIT_FAILURE
, "%s factory requires root privilege", factory
->name
);
4481 for (int i
= 0; i
< MAX_N
; i
++) {
4483 fdescs
[i
].mx_modes
= 0;
4484 fdescs
[i
].close
= NULL
;
4487 for (int i
= 0; i
< factory
->N
; i
++) {
4488 char *str
= argv
[optind
+ i
];
4493 fd
= strtol(str
, &ep
, 10);
4495 err(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4497 errx(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
4499 errx(EXIT_FAILURE
, "garbage at the end of number: %s", str
);
4501 errx(EXIT_FAILURE
, "fd number should not be negative: %s", str
);
4503 errx(EXIT_FAILURE
, "fd 0, 1, 2 are reserved: %s", str
);
4506 optind
+= factory
->N
;
4508 data
= factory
->make(factory
, fdescs
, argc
- optind
, argv
+ optind
);
4510 signal(SIGCONT
, do_nothing
);
4513 printf("%d", getpid());
4514 if (factory
->report
) {
4515 for (int i
= 0; i
< factory
->EX_R
; i
++) {
4517 factory
->report(factory
, i
, data
, stdout
);
4525 wait_event
->fn(monitor_stdin
,
4526 fdescs
, factory
->N
+ factory
->EX_N
);
4528 for (int i
= 0; i
< factory
->N
+ factory
->EX_N
; i
++)
4529 if (fdescs
[i
].fd
>= 0 && fdescs
[i
].close
)
4530 fdescs
[i
].close(fdescs
[i
].fd
, fdescs
[i
].data
);
4533 factory
->free(factory
, data
);