2 * test_lsfd - 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.
20 #include <arpa/inet.h>
26 #include <linux/if_ether.h>
27 #include <linux/if_packet.h>
28 #include <linux/sockios.h> /* SIOCGSKNS */
30 #include <netinet/in.h>
31 #include <netinet/tcp.h>
38 #include <sys/inotify.h>
39 #include <sys/ioctl.h>
41 #include <sys/prctl.h>
42 #include <sys/select.h>
43 #include <sys/socket.h>
44 #include <sys/syscall.h>
45 #include <sys/types.h>
54 #define _U_ __attribute__((__unused__))
56 static int pidfd_open(pid_t pid
, unsigned int flags
);
58 static void __attribute__((__noreturn__
)) usage(FILE *out
, int status
)
60 fputs(USAGE_HEADER
, out
);
61 fprintf(out
, _(" %s [options] FACTORY FD... [PARAM=VAL...]\n"), program_invocation_short_name
);
63 fputs(USAGE_OPTIONS
, out
);
64 fputs(_(" -l, --list list available file descriptor factories and exit\n"), out
);
65 fputs(_(" -I, --parameters <factory> list parameters the factory takes\n"), out
);
66 fputs(_(" -r, --comm <name> rename self\n"), out
);
67 fputs(_(" -q, --quiet don't print pid(s)\n"), out
);
68 fputs(_(" -c, --dont-pause don't pause after making fd(s)\n"), out
);
70 fputs(USAGE_SEPARATOR
, out
);
71 fputs(_("Examples:\n"), out
);
72 fprintf(out
, _("Using 3, open /etc/group:\n\n $ %s ro-regular-file 3 file=/etc/group\n\n"),
73 program_invocation_short_name
);
74 fprintf(out
, _("Using 3 and 4, make a pipe:\n\n $ %s pipe-no-fork 3 4\n\n"),
75 program_invocation_short_name
);
95 /* Covert to a string representation.
96 * A caller must free the returned value with free(3) after using. */
97 char *(*sprint
)(const union value
*value
);
99 /* Convert from a string. If ARG is NULL, use DEFV instead.
100 * A caller must free the returned value with the free method
102 union value (*read
)(const char *arg
, const union value
*defv
);
104 /* Free the value returned from the read method. */
105 void (*free
)(union value value
);
108 #define ARG_STRING(A) (A.v.string)
109 #define ARG_INTEGER(A) (A.v.integer)
110 #define ARG_BOOLEAN(A) (A.v.boolean)
113 void (*free
)(union value value
);
118 const enum ptype type
;
120 union value defv
; /* Default value */
123 static char *string_sprint(const union value
*value
)
125 return xstrdup(value
->string
);
128 static union value
string_read(const char *arg
, const union value
*defv
)
130 return (union value
){ .string
= xstrdup(arg
?: defv
->string
) };
133 static void string_free(union value value
)
135 free((void *)value
.string
);
138 static char *integer_sprint(const union value
*value
)
141 xasprintf(&str
, "%ld", value
->integer
);
145 static union value
integer_read(const char *arg
, const union value
*defv
)
154 r
.integer
= strtol(arg
, &ep
, 10);
156 err(EXIT_FAILURE
, _("fail to make a number from %s"), arg
);
157 else if (*ep
!= '\0')
158 errx(EXIT_FAILURE
, _("garbage at the end of number: %s"), arg
);
162 static void integer_free(union value value _U_
)
167 static char *boolean_sprint(const union value
*value
)
169 return xstrdup(value
->boolean
? "true": "false");
172 static union value
boolean_read(const char *arg
, const union value
*defv
)
179 if (strcasecmp(arg
, "true") == 0
180 || strcmp(arg
, "1") == 0
181 || strcasecmp(arg
, "yes") == 0
182 || strcasecmp(arg
, "y") == 0)
189 static void boolean_free(union value value _U_
)
194 struct ptype_class ptype_classes
[] = {
197 .sprint
= string_sprint
,
203 .sprint
= integer_sprint
,
204 .read
= integer_read
,
205 .free
= integer_free
,
209 .sprint
= boolean_sprint
,
210 .read
= boolean_read
,
211 .free
= boolean_free
,
215 static struct arg
decode_arg(const char *pname
,
216 const struct parameter
*parameters
,
217 int argc
, char **argv
)
220 size_t len
= strlen(pname
);
221 const struct parameter
*p
= NULL
;
224 while (parameters
->name
) {
225 if (strcmp(pname
, parameters
->name
) == 0) {
232 errx(EXIT_FAILURE
, _("no such parameter: %s"), pname
);
234 for (int i
= 0; i
< argc
; i
++) {
235 if (strncmp(pname
, argv
[i
], len
) == 0) {
240 } else if (*v
== '\0')
242 _("no value given for \"%s\" parameter"),
248 arg
.v
= ptype_classes
[p
->type
].read (v
, &p
->defv
);
249 arg
.free
= ptype_classes
[p
->type
].free
;
253 static void free_arg(struct arg
*arg
)
260 void (*close
)(int, void *);
265 const char *name
; /* [-a-zA-Z0-9_]+ */
267 bool priv
; /* the root privilege is needed to make fd(s) */
269 int N
; /* the number of fds this factory makes */
270 int EX_N
; /* fds made optionally */
271 void *(*make
)(const struct factory
*, struct fdesc
[], int, char **);
272 void (*free
)(const struct factory
*, void *);
273 void (*report
)(const struct factory
*, void *, FILE *);
274 const struct parameter
* params
;
277 static void close_fdesc(int fd
, void *data _U_
)
282 static void *open_ro_regular_file(const struct factory
*factory
, struct fdesc fdescs
[],
283 int argc
, char ** argv
)
285 struct arg file
= decode_arg("file", factory
->params
, argc
, argv
);
286 struct arg offset
= decode_arg("offset", factory
->params
, argc
, argv
);
288 int fd
= open(ARG_STRING(file
), O_RDONLY
);
290 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(file
));
293 if (ARG_INTEGER(offset
) != 0) {
294 if (lseek(fd
, (off_t
)ARG_INTEGER(offset
), SEEK_CUR
) < 0) {
298 err(EXIT_FAILURE
, "failed to seek 0 -> %ld", ARG_INTEGER(offset
));
303 if (fd
!= fdescs
[0].fd
) {
304 if (dup2(fd
, fdescs
[0].fd
) < 0) {
308 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
313 fdescs
[0] = (struct fdesc
){
315 .close
= close_fdesc
,
322 static void *make_pipe(const struct factory
*factory
, struct fdesc fdescs
[],
323 int argc
, char ** argv
)
326 int nonblock_flags
[2] = {0, 0};
327 struct arg nonblock
= decode_arg("nonblock", factory
->params
, argc
, argv
);
328 if (strlen(ARG_STRING(nonblock
)) != 2) {
329 errx(EXIT_FAILURE
, "string value for %s has unexpected length: %s",
330 "nonblock", ARG_STRING(nonblock
));
333 /* Make extra pipe descriptors for making pipe objects connected
334 * with fds more than 2.
335 * See https://github.com/util-linux/util-linux/pull/1622
336 * about the background of the requirement. */
337 struct arg rdup
= decode_arg("rdup", factory
->params
, argc
, argv
);
338 struct arg wdup
= decode_arg("wdup", factory
->params
, argc
, argv
);
340 xpd
[0] = ARG_INTEGER(rdup
);
341 xpd
[1] = ARG_INTEGER(wdup
);
343 for (int i
= 0; i
< 2; i
++) {
344 if (ARG_STRING(nonblock
)[i
] == '-')
346 if ((i
== 0 && ARG_STRING(nonblock
)[i
] == 'r')
347 || (i
== 1 && ARG_STRING(nonblock
)[i
] == 'w'))
348 nonblock_flags
[i
] = 1;
350 errx(EXIT_FAILURE
, "unexpected value %c for the %s fd of %s",
351 ARG_STRING(nonblock
)[i
],
352 (i
== 0)? "read": "write",
358 err(EXIT_FAILURE
, "failed to make pipe");
360 for (int i
= 0; i
< 2; i
++) {
361 if (nonblock_flags
[i
]) {
362 int flags
= fcntl(pd
[i
], F_GETFL
);
363 if (fcntl(pd
[i
], F_SETFL
, flags
|O_NONBLOCK
) < 0) {
368 errx(EXIT_FAILURE
, "failed to set NONBLOCK flag to the %s fd",
369 (i
== 0)? "read": "write");
374 for (int i
= 0; i
< 2; i
++) {
375 if (pd
[i
] != fdescs
[i
].fd
) {
376 if (dup2(pd
[i
], fdescs
[i
].fd
) < 0) {
381 err(EXIT_FAILURE
, "failed to dup %d -> %d",
382 pd
[i
], fdescs
[i
].fd
);
386 fdescs
[i
] = (struct fdesc
){
388 .close
= close_fdesc
,
393 /* Make extra pipe descriptors. */
394 for (int i
= 0; i
< 2; i
++) {
396 if (dup2(fdescs
[i
].fd
, xpd
[i
]) < 0) {
400 if (i
> 0 && xpd
[0] >= 0)
403 err(EXIT_FAILURE
, "failed to dup %d -> %d",
404 fdescs
[i
].fd
, xpd
[i
]);
406 fdescs
[i
+ 2] = (struct fdesc
){
408 .close
= close_fdesc
,
417 static void close_dir(int fd
, void *data
)
423 close_fdesc(fd
, NULL
);
426 static void *open_directory(const struct factory
*factory
, struct fdesc fdescs
[],
427 int argc
, char ** argv
)
429 struct arg dir
= decode_arg("dir", factory
->params
, argc
, argv
);
430 struct arg dentries
= decode_arg("dentries", factory
->params
, argc
, argv
);
433 int fd
= open(ARG_STRING(dir
), O_RDONLY
|O_DIRECTORY
);
435 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(dir
));
438 if (fd
!= fdescs
[0].fd
) {
439 if (dup2(fd
, fdescs
[0].fd
) < 0) {
443 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
448 if (ARG_INTEGER(dentries
) > 0) {
449 dp
= fdopendir(fdescs
[0].fd
);
454 err(EXIT_FAILURE
, "failed to make DIR* from fd: %s", ARG_STRING(dir
));
456 for (int i
= 0; i
< ARG_INTEGER(dentries
); i
++) {
457 struct dirent
*d
= readdir(dp
);
462 err(EXIT_FAILURE
, "failed in readdir(3)");
468 fdescs
[0] = (struct fdesc
){
477 static void *open_rw_chrdev(const struct factory
*factory
, struct fdesc fdescs
[],
478 int argc
, char ** argv
)
480 struct arg chrdev
= decode_arg("chrdev", factory
->params
, argc
, argv
);
481 int fd
= open(ARG_STRING(chrdev
), O_RDWR
);
483 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(chrdev
));
486 if (fd
!= fdescs
[0].fd
) {
487 if (dup2(fd
, fdescs
[0].fd
) < 0) {
491 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
496 fdescs
[0] = (struct fdesc
){
498 .close
= close_fdesc
,
505 static void *make_socketpair(const struct factory
*factory
, struct fdesc fdescs
[],
506 int argc
, char ** argv
)
509 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
511 if (strcmp(ARG_STRING(socktype
), "STREAM") == 0)
512 isocktype
= SOCK_STREAM
;
513 else if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
514 isocktype
= SOCK_DGRAM
;
515 else if (strcmp(ARG_STRING(socktype
), "SEQPACKET") == 0)
516 isocktype
= SOCK_SEQPACKET
;
519 "unknown socket type for socketpair(AF_UNIX,...): %s",
520 ARG_STRING(socktype
));
523 if (socketpair(AF_UNIX
, isocktype
, 0, sd
) < 0)
524 err(EXIT_FAILURE
, "failed to make socket pair");
526 for (int i
= 0; i
< 2; i
++) {
527 if (sd
[i
] != fdescs
[i
].fd
) {
528 if (dup2(sd
[i
], fdescs
[i
].fd
) < 0) {
533 err(EXIT_FAILURE
, "failed to dup %d -> %d",
534 sd
[i
], fdescs
[i
].fd
);
538 fdescs
[i
] = (struct fdesc
){
540 .close
= close_fdesc
,
548 static void *open_with_opath(const struct factory
*factory
, struct fdesc fdescs
[],
549 int argc
, char ** argv
)
551 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
552 int fd
= open(ARG_STRING(path
), O_PATH
|O_NOFOLLOW
);
554 err(EXIT_FAILURE
, "failed to open with O_PATH: %s", ARG_STRING(path
));
557 if (fd
!= fdescs
[0].fd
) {
558 if (dup2(fd
, fdescs
[0].fd
) < 0) {
562 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
567 fdescs
[0] = (struct fdesc
){
569 .close
= close_fdesc
,
576 static void *open_ro_blkdev(const struct factory
*factory
, struct fdesc fdescs
[],
577 int argc
, char ** argv
)
579 struct arg blkdev
= decode_arg("blkdev", factory
->params
, argc
, argv
);
580 int fd
= open(ARG_STRING(blkdev
), O_RDONLY
);
582 err(EXIT_FAILURE
, "failed to open: %s", ARG_STRING(blkdev
));
585 if (fd
!= fdescs
[0].fd
) {
586 if (dup2(fd
, fdescs
[0].fd
) < 0) {
590 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
595 fdescs
[0] = (struct fdesc
){
597 .close
= close_fdesc
,
604 static int make_packet_socket(int socktype
, const char *interface
)
607 struct sockaddr_ll addr
;
609 sd
= socket(AF_PACKET
, socktype
, htons(ETH_P_ALL
));
611 err(EXIT_FAILURE
, "failed to make a socket with AF_PACKET");
613 if (interface
== NULL
)
614 return sd
; /* Just making a socket */
616 memset(&addr
, 0, sizeof(struct sockaddr_ll
));
617 addr
.sll_family
= AF_PACKET
;
618 addr
.sll_protocol
= ETH_P_ALL
;
619 addr
.sll_ifindex
= if_nametoindex(interface
);
620 if (addr
.sll_ifindex
== 0) {
625 "failed to get the interface index for %s", interface
);
627 if (bind(sd
, (struct sockaddr
*)&addr
, sizeof(struct sockaddr_ll
)) < 0) {
632 "failed to get the interface index for %s", interface
);
643 static void close_fdesc_after_munmap(int fd
, void *data
)
645 struct munmap_data
*munmap_data
= data
;
646 munmap(munmap_data
->ptr
, munmap_data
->len
);
651 static void *make_mmapped_packet_socket(const struct factory
*factory
, struct fdesc fdescs
[],
652 int argc
, char ** argv
)
655 struct arg socktype
= decode_arg("socktype", factory
->params
, argc
, argv
);
656 struct arg interface
= decode_arg("interface", factory
->params
, argc
, argv
);
659 const char *sinterface
;
660 struct tpacket_req req
;
661 struct munmap_data
*munmap_data
;
663 if (strcmp(ARG_STRING(socktype
), "DGRAM") == 0)
664 isocktype
= SOCK_DGRAM
;
665 else if (strcmp(ARG_STRING(socktype
), "RAW") == 0)
666 isocktype
= SOCK_RAW
;
669 "unknown socket type for socket(AF_PACKET,...): %s",
670 ARG_STRING(socktype
));
673 sinterface
= ARG_STRING(interface
);
674 sd
= make_packet_socket(isocktype
, sinterface
);
675 free_arg(&interface
);
677 /* Specify the spec of ring buffers.
680 * - linux/Documentation/networking/packet_mmap.rst
681 * - https://sites.google.com/site/packetmmap/home
683 req
.tp_block_size
= getpagesize();
684 req
.tp_frame_size
= getpagesize();
687 if (setsockopt(sd
, SOL_PACKET
, PACKET_TX_RING
, (char *)&req
, sizeof(req
)) < 0) {
691 err(EXIT_FAILURE
, "failed to specify a buffer spec to a packet socket");
694 munmap_data
= malloc(sizeof (*munmap_data
));
695 if (munmap_data
== NULL
) {
697 errx(EXIT_FAILURE
, "memory exhausted");
699 munmap_data
->len
= (size_t) req
.tp_block_size
* req
.tp_block_nr
;
700 munmap_data
->ptr
= mmap(NULL
, munmap_data
->len
, PROT_WRITE
, MAP_SHARED
, sd
, 0);
701 if (munmap_data
->ptr
== MAP_FAILED
) {
706 err(EXIT_FAILURE
, "failed to do mmap a packet socket");
709 if (sd
!= fdescs
[0].fd
) {
710 if (dup2(sd
, fdescs
[0].fd
) < 0) {
713 munmap(munmap_data
->ptr
, munmap_data
->len
);
716 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[0].fd
);
721 fdescs
[0] = (struct fdesc
){
723 .close
= close_fdesc_after_munmap
,
730 static void *make_pidfd(const struct factory
*factory
, struct fdesc fdescs
[],
731 int argc
, char ** argv
)
733 struct arg target_pid
= decode_arg("target-pid", factory
->params
, argc
, argv
);
734 pid_t pid
= ARG_INTEGER(target_pid
);
736 int fd
= pidfd_open(pid
, 0);
738 err(EXIT_FAILURE
, "failed in pidfd_open(%d)", (int)pid
);
739 free_arg(&target_pid
);
741 if (fd
!= fdescs
[0].fd
) {
742 if (dup2(fd
, fdescs
[0].fd
) < 0) {
746 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
751 fdescs
[0] = (struct fdesc
){
753 .close
= close_fdesc
,
760 static void *make_inotify_fd(const struct factory
*factory _U_
, struct fdesc fdescs
[],
761 int argc _U_
, char ** argv _U_
)
763 int fd
= inotify_init();
765 err(EXIT_FAILURE
, "failed in inotify_init()");
767 if (fd
!= fdescs
[0].fd
) {
768 if (dup2(fd
, fdescs
[0].fd
) < 0) {
772 err(EXIT_FAILURE
, "failed to dup %d -> %d", fd
, fdescs
[0].fd
);
777 fdescs
[0] = (struct fdesc
){
779 .close
= close_fdesc
,
786 static void close_unix_socket(int fd
, void *data
)
796 static void *make_unix_stream_core(const struct factory
*factory
, struct fdesc fdescs
[],
797 int argc
, char ** argv
, int type
, const char *typestr
)
799 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
800 const char *spath
= ARG_STRING(path
);
802 struct arg backlog
= decode_arg("backlog", factory
->params
, argc
, argv
);
803 int ibacklog
= ARG_INTEGER(path
);
805 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
806 bool babstract
= ARG_BOOLEAN(abstract
);
808 struct arg server_shutdown
= decode_arg("server-shutdown", factory
->params
, argc
, argv
);
809 int iserver_shutdown
= ARG_INTEGER(server_shutdown
);
810 struct arg client_shutdown
= decode_arg("client-shutdown", factory
->params
, argc
, argv
);
811 int iclient_shutdown
= ARG_INTEGER(client_shutdown
);
813 int ssd
, csd
, asd
; /* server, client, and accepted socket descriptors */
814 struct sockaddr_un un
;
815 size_t un_len
= sizeof(un
);
817 memset(&un
, 0, sizeof(un
));
818 un
.sun_family
= AF_UNIX
;
820 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
821 size_t pathlen
= strlen(spath
);
822 if (sizeof(un
.sun_path
) - 1 > pathlen
)
823 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
825 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
827 free_arg(&client_shutdown
);
828 free_arg(&server_shutdown
);
833 if (iserver_shutdown
< 0 || iserver_shutdown
> 3)
834 errx(EXIT_FAILURE
, "the server shudown specification in unexpected range");
835 if (iclient_shutdown
< 0 || iclient_shutdown
> 3)
836 errx(EXIT_FAILURE
, "the client shudown specification in unexpected range");
838 ssd
= socket(AF_UNIX
, type
, 0);
841 "failed to make a socket with AF_UNIX + SOCK_%s (server side)", typestr
);
842 if (ssd
!= fdescs
[0].fd
) {
843 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
847 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
853 fdescs
[0] = (struct fdesc
){
855 .close
= close_unix_socket
,
861 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
865 err(EXIT_FAILURE
, "failed to bind a socket for listening");
869 fdescs
[0].data
= xstrdup(un
.sun_path
);
870 if (listen(ssd
, ibacklog
) < 0) {
872 close_unix_socket(ssd
, fdescs
[0].data
);
874 err(EXIT_FAILURE
, "failed to listen a socket");
877 csd
= socket(AF_UNIX
, type
, 0);
880 "failed to make a socket with AF_UNIX + SOCK_%s (client side)", typestr
);
881 if (csd
!= fdescs
[1].fd
) {
882 if (dup2(csd
, fdescs
[1].fd
) < 0) {
885 close_unix_socket(ssd
, fdescs
[0].data
);
887 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
893 fdescs
[1] = (struct fdesc
){
895 .close
= close_fdesc
,
899 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
901 close_fdesc(csd
, NULL
);
902 close_unix_socket(ssd
, fdescs
[0].data
);
904 err(EXIT_FAILURE
, "failed to connect a socket to the listening socket");
910 asd
= accept(ssd
, NULL
, NULL
);
913 close_fdesc(csd
, NULL
);
914 close_unix_socket(ssd
, fdescs
[0].data
);
916 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
918 if (asd
!= fdescs
[2].fd
) {
919 if (dup2(asd
, fdescs
[2].fd
) < 0) {
922 close_fdesc(csd
, NULL
);
923 close_unix_socket(ssd
, fdescs
[0].data
);
925 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
931 if (iserver_shutdown
& (1 << 0))
932 shutdown(asd
, SHUT_RD
);
933 if (iserver_shutdown
& (1 << 1))
934 shutdown(asd
, SHUT_WR
);
935 if (iclient_shutdown
& (1 << 0))
936 shutdown(csd
, SHUT_RD
);
937 if (iclient_shutdown
& (1 << 1))
938 shutdown(csd
, SHUT_WR
);
943 static void *make_unix_stream(const struct factory
*factory
, struct fdesc fdescs
[],
944 int argc
, char ** argv
)
946 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
947 const char *stype
= ARG_STRING(type
);
952 if (strcmp(stype
, "stream") == 0) {
953 typesym
= SOCK_STREAM
;
955 } else if (strcmp(stype
, "seqpacket") == 0) {
956 typesym
= SOCK_SEQPACKET
;
957 typestr
= "SEQPACKET";
959 errx(EXIT_FAILURE
, _("unknown unix socket type: %s"), stype
);
963 return make_unix_stream_core(factory
, fdescs
, argc
, argv
, typesym
, typestr
);
966 static void *make_unix_dgram(const struct factory
*factory
, struct fdesc fdescs
[],
967 int argc
, char ** argv
)
969 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
970 const char *spath
= ARG_STRING(path
);
972 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
973 bool babstract
= ARG_BOOLEAN(abstract
);
975 int ssd
, csd
; /* server and client socket descriptors */
977 struct sockaddr_un un
;
978 size_t un_len
= sizeof(un
);
980 memset(&un
, 0, sizeof(un
));
981 un
.sun_family
= AF_UNIX
;
983 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
984 size_t pathlen
= strlen(spath
);
985 if (sizeof(un
.sun_path
) - 1 > pathlen
)
986 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
988 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
993 ssd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
996 "failed to make a socket with AF_UNIX + SOCK_DGRAM (server side)");
997 if (ssd
!= fdescs
[0].fd
) {
998 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1002 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1008 fdescs
[0] = (struct fdesc
){
1010 .close
= close_unix_socket
,
1015 unlink(un
.sun_path
);
1016 if (bind(ssd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1020 err(EXIT_FAILURE
, "failed to bind a socket for server");
1024 fdescs
[0].data
= xstrdup(un
.sun_path
);
1025 csd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
1028 "failed to make a socket with AF_UNIX + SOCK_DGRAM (client side)");
1029 if (csd
!= fdescs
[1].fd
) {
1030 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1033 close_unix_socket(ssd
, fdescs
[0].data
);
1035 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1041 fdescs
[1] = (struct fdesc
){
1043 .close
= close_fdesc
,
1047 if (connect(csd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1049 close_fdesc(csd
, NULL
);
1050 close_unix_socket(ssd
, fdescs
[0].data
);
1052 err(EXIT_FAILURE
, "failed to connect a socket to the server socket");
1056 unlink(un
.sun_path
);
1061 static void *make_unix_in_new_netns(const struct factory
*factory
, struct fdesc fdescs
[],
1062 int argc
, char ** argv
)
1064 struct arg type
= decode_arg("type", factory
->params
, argc
, argv
);
1065 const char *stype
= ARG_STRING(type
);
1067 struct arg path
= decode_arg("path", factory
->params
, argc
, argv
);
1068 const char *spath
= ARG_STRING(path
);
1070 struct arg abstract
= decode_arg("abstract", factory
->params
, argc
, argv
);
1071 bool babstract
= ARG_BOOLEAN(abstract
);
1074 const char *typestr
;
1076 struct sockaddr_un un
;
1077 size_t un_len
= sizeof(un
);
1079 int self_netns
, tmp_netns
, sd
;
1081 if (strcmp(stype
, "stream") == 0) {
1082 typesym
= SOCK_STREAM
;
1084 } else if (strcmp(stype
, "seqpacket") == 0) {
1085 typesym
= SOCK_SEQPACKET
;
1086 typestr
= "SEQPACKET";
1087 } else if (strcmp(stype
, "dgram") == 0) {
1088 typesym
= SOCK_DGRAM
;
1091 free_arg(&abstract
);
1094 errx(EXIT_FAILURE
, _("unknown unix socket type: %s"), stype
);
1097 memset(&un
, 0, sizeof(un
));
1098 un
.sun_family
= AF_UNIX
;
1100 strncpy(un
.sun_path
+ 1, spath
, sizeof(un
.sun_path
) - 1 - 1);
1101 size_t pathlen
= strlen(spath
);
1102 if (sizeof(un
.sun_path
) - 1 > pathlen
)
1103 un_len
= sizeof(un
) - sizeof(un
.sun_path
) + 1 + pathlen
;
1105 strncpy(un
.sun_path
, spath
, sizeof(un
.sun_path
) - 1 );
1107 free_arg(&abstract
);
1111 self_netns
= open("/proc/self/ns/net", O_RDONLY
);
1113 err(EXIT_FAILURE
, _("failed to open /proc/self/ns/net"));
1114 if (self_netns
!= fdescs
[0].fd
) {
1115 if (dup2(self_netns
, fdescs
[0].fd
) < 0) {
1119 err(EXIT_FAILURE
, "failed to dup %d -> %d", self_netns
, fdescs
[0].fd
);
1122 self_netns
= fdescs
[0].fd
;
1125 fdescs
[0] = (struct fdesc
){
1127 .close
= close_fdesc
,
1131 if (unshare(CLONE_NEWNET
) < 0) {
1133 close_fdesc(self_netns
, NULL
);
1135 err(EXIT_FAILURE
, "failed in unshare");
1138 tmp_netns
= open("/proc/self/ns/net", O_RDONLY
);
1139 if (tmp_netns
< 0) {
1141 close_fdesc(self_netns
, NULL
);
1143 err(EXIT_FAILURE
, _("failed to open /proc/self/ns/net for the new netns"));
1145 if (tmp_netns
!= fdescs
[1].fd
) {
1146 if (dup2(tmp_netns
, fdescs
[1].fd
) < 0) {
1148 close_fdesc(self_netns
, NULL
);
1151 err(EXIT_FAILURE
, "failed to dup %d -> %d", tmp_netns
, fdescs
[1].fd
);
1154 tmp_netns
= fdescs
[1].fd
;
1157 fdescs
[1] = (struct fdesc
){
1159 .close
= close_fdesc
,
1163 sd
= socket(AF_UNIX
, typesym
, 0);
1166 close_fdesc(self_netns
, NULL
);
1167 close_fdesc(tmp_netns
, NULL
);
1170 _("failed to make a socket with AF_UNIX + SOCK_%s"),
1174 if (sd
!= fdescs
[2].fd
) {
1175 if (dup2(sd
, fdescs
[2].fd
) < 0) {
1177 close_fdesc(self_netns
, NULL
);
1178 close_fdesc(tmp_netns
, NULL
);
1181 err(EXIT_FAILURE
, "failed to dup %d -> %d", sd
, fdescs
[2].fd
);
1187 fdescs
[2] = (struct fdesc
){
1189 .close
= close_unix_socket
,
1194 unlink(un
.sun_path
);
1195 if (bind(sd
, (const struct sockaddr
*)&un
, un_len
) < 0) {
1197 close_fdesc(self_netns
, NULL
);
1198 close_fdesc(tmp_netns
, NULL
);
1199 close_unix_socket(sd
, NULL
);
1201 err(EXIT_FAILURE
, "failed to bind a socket");
1205 fdescs
[2].data
= xstrdup(un
.sun_path
);
1207 if (typesym
!= SOCK_DGRAM
) {
1208 if (listen(sd
, 1) < 0) {
1210 close_fdesc(self_netns
, NULL
);
1211 close_fdesc(tmp_netns
, NULL
);
1212 close_unix_socket(sd
, fdescs
[2].data
);
1214 err(EXIT_FAILURE
, "failed to listen a socket");
1218 if (setns(self_netns
, CLONE_NEWNET
) < 0) {
1220 close_fdesc(self_netns
, NULL
);
1221 close_fdesc(tmp_netns
, NULL
);
1222 close_unix_socket(sd
, fdescs
[2].data
);
1224 err(EXIT_FAILURE
, "failed to swich back to the original net namespace");
1230 static void *make_tcp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1231 int argc
, char ** argv
,
1233 void (*init_addr
)(struct sockaddr
*, unsigned short),
1235 struct sockaddr
* sin
, struct sockaddr
* cin
)
1237 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1238 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1239 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1240 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1246 free_arg(&server_port
);
1247 free_arg(&client_port
);
1249 ssd
= socket(family
, SOCK_STREAM
, 0);
1252 _("failed to make a tcp socket for listening"));
1254 if (setsockopt(ssd
, SOL_SOCKET
,
1255 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1259 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1262 if (ssd
!= fdescs
[0].fd
) {
1263 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1267 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1273 init_addr(sin
, iserver_port
);
1274 if (bind(ssd
, sin
, addr_size
) < 0) {
1278 err(EXIT_FAILURE
, "failed to bind a listening socket");
1281 if (listen(ssd
, 1) < 0) {
1285 err(EXIT_FAILURE
, "failed to listen a socket");
1288 csd
= socket(family
, SOCK_STREAM
, 0);
1294 _("failed to make a tcp client socket"));
1297 if (setsockopt(csd
, SOL_SOCKET
,
1298 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1303 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1306 if (csd
!= fdescs
[1].fd
) {
1307 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1312 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1318 init_addr(cin
, iclient_port
);
1319 if (bind(csd
, cin
, addr_size
) < 0) {
1324 err(EXIT_FAILURE
, "failed to bind a client socket");
1327 if (connect(csd
, sin
, addr_size
) < 0) {
1332 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1335 asd
= accept(ssd
, NULL
, NULL
);
1341 err(EXIT_FAILURE
, "failed to accept a socket from the listening socket");
1343 if (asd
!= fdescs
[2].fd
) {
1344 if (dup2(asd
, fdescs
[2].fd
) < 0) {
1349 err(EXIT_FAILURE
, "failed to dup %d -> %d", asd
, fdescs
[2].fd
);
1355 fdescs
[0] = (struct fdesc
) {
1357 .close
= close_fdesc
,
1360 fdescs
[1] = (struct fdesc
) {
1362 .close
= close_fdesc
,
1365 fdescs
[2] = (struct fdesc
) {
1367 .close
= close_fdesc
,
1374 static void tcp_init_addr(struct sockaddr
*addr
, unsigned short port
)
1376 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
1377 memset(in
, 0, sizeof(*in
));
1378 in
->sin_family
= AF_INET
;
1379 in
->sin_port
= htons(port
);
1380 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1383 static void *make_tcp(const struct factory
*factory
, struct fdesc fdescs
[],
1384 int argc
, char ** argv
)
1386 struct sockaddr_in sin
, cin
;
1387 return make_tcp_common(factory
, fdescs
, argc
, argv
,
1389 tcp_init_addr
, sizeof(sin
),
1390 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1393 static void *make_udp_common(const struct factory
*factory
, struct fdesc fdescs
[],
1394 int argc
, char ** argv
,
1396 void (*init_addr
)(struct sockaddr
*, unsigned short),
1398 struct sockaddr
* sin
, struct sockaddr
* cin
)
1400 struct arg lite
= decode_arg("lite", factory
->params
, argc
, argv
);
1401 bool blite
= ARG_BOOLEAN(lite
);
1403 struct arg server_port
= decode_arg("server-port", factory
->params
, argc
, argv
);
1404 unsigned short iserver_port
= (unsigned short)ARG_INTEGER(server_port
);
1405 struct arg client_port
= decode_arg("client-port", factory
->params
, argc
, argv
);
1406 unsigned short iclient_port
= (unsigned short)ARG_INTEGER(client_port
);
1408 struct arg server_do_bind
= decode_arg("server-do-bind", factory
->params
, argc
, argv
);
1409 bool bserver_do_bind
= ARG_BOOLEAN(server_do_bind
);
1410 struct arg client_do_bind
= decode_arg("client-do-bind", factory
->params
, argc
, argv
);
1411 bool bclient_do_bind
= ARG_BOOLEAN(client_do_bind
);
1412 struct arg client_do_connect
= decode_arg("client-do-connect", factory
->params
, argc
, argv
);
1413 bool bclient_do_connect
= ARG_BOOLEAN(client_do_connect
);
1419 free_arg(&client_do_connect
);
1420 free_arg(&client_do_bind
);
1421 free_arg(&server_do_bind
);
1422 free_arg(&server_port
);
1423 free_arg(&client_port
);
1426 ssd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1429 _("failed to make a udp socket for server"));
1431 if (setsockopt(ssd
, SOL_SOCKET
,
1432 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1436 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1439 if (ssd
!= fdescs
[0].fd
) {
1440 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1444 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1450 init_addr(sin
, iserver_port
);
1451 if (bserver_do_bind
) {
1452 if (bind(ssd
, sin
, addr_size
) < 0) {
1456 err(EXIT_FAILURE
, "failed to bind a server socket");
1460 csd
= socket(family
, SOCK_DGRAM
, blite
? IPPROTO_UDPLITE
: 0);
1466 _("failed to make a udp client socket"));
1469 if (setsockopt(csd
, SOL_SOCKET
,
1470 SO_REUSEADDR
, (const char *)&y
, sizeof(y
)) < 0) {
1475 err(EXIT_FAILURE
, "failed to setsockopt(SO_REUSEADDR)");
1478 if (csd
!= fdescs
[1].fd
) {
1479 if (dup2(csd
, fdescs
[1].fd
) < 0) {
1484 err(EXIT_FAILURE
, "failed to dup %d -> %d", csd
, fdescs
[1].fd
);
1490 if (bclient_do_bind
) {
1491 init_addr(cin
, iclient_port
);
1492 if (bind(csd
, cin
, addr_size
) < 0) {
1497 err(EXIT_FAILURE
, "failed to bind a client socket");
1501 if (bclient_do_connect
) {
1502 if (connect(csd
, sin
, addr_size
) < 0) {
1507 err(EXIT_FAILURE
, "failed to connect a client socket to the server socket");
1511 fdescs
[0] = (struct fdesc
) {
1513 .close
= close_fdesc
,
1516 fdescs
[1] = (struct fdesc
) {
1518 .close
= close_fdesc
,
1525 static void *make_udp(const struct factory
*factory
, struct fdesc fdescs
[],
1526 int argc
, char ** argv
)
1528 struct sockaddr_in sin
, cin
;
1529 return make_udp_common(factory
, fdescs
, argc
, argv
,
1531 tcp_init_addr
, sizeof(sin
),
1532 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1535 static void *make_raw_common(const struct factory
*factory
, struct fdesc fdescs
[],
1536 int argc
, char ** argv
,
1538 void (*init_addr
)(struct sockaddr
*, bool),
1540 struct sockaddr
* sin
)
1542 struct arg protocol
= decode_arg("protocol", factory
->params
, argc
, argv
);
1543 int iprotocol
= ARG_INTEGER(protocol
);
1546 free_arg(&protocol
);
1548 ssd
= socket(family
, SOCK_RAW
, iprotocol
);
1551 _("failed to make a udp socket for server"));
1553 if (ssd
!= fdescs
[0].fd
) {
1554 if (dup2(ssd
, fdescs
[0].fd
) < 0) {
1558 err(EXIT_FAILURE
, "failed to dup %d -> %d", ssd
, fdescs
[0].fd
);
1564 init_addr(sin
, false);
1565 if (bind(ssd
, sin
, addr_size
) < 0) {
1569 err(EXIT_FAILURE
, "failed in bind(2)");
1572 init_addr(sin
, true);
1573 if (connect(ssd
, sin
, addr_size
) < 0) {
1577 err(EXIT_FAILURE
, "failed in connect(2)");
1580 fdescs
[0] = (struct fdesc
) {
1582 .close
= close_fdesc
,
1589 static void raw_init_addr(struct sockaddr
* addr
, bool remote_addr
)
1591 struct sockaddr_in
*in
= (struct sockaddr_in
*)addr
;
1592 memset(in
, 0, sizeof(*in
));
1593 in
->sin_family
= AF_INET
;
1594 in
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
+ (remote_addr
? 1: 0));
1597 static void *make_raw(const struct factory
*factory
, struct fdesc fdescs
[],
1598 int argc
, char ** argv
)
1600 struct sockaddr_in sin
;
1601 return make_raw_common(factory
, fdescs
, argc
, argv
,
1603 raw_init_addr
, sizeof(sin
),
1604 (struct sockaddr
*)&sin
);
1607 static void tcp6_init_addr(struct sockaddr
*addr
, unsigned short port
)
1609 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
1610 memset(in6
, 0, sizeof(*in6
));
1611 in6
->sin6_family
= AF_INET6
;
1612 in6
->sin6_flowinfo
= 0;
1613 in6
->sin6_port
= htons(port
);
1614 in6
->sin6_addr
= in6addr_loopback
;
1617 static void *make_tcp6(const struct factory
*factory
, struct fdesc fdescs
[],
1618 int argc
, char ** argv
)
1620 struct sockaddr_in6 sin
, cin
;
1621 return make_tcp_common(factory
, fdescs
, argc
, argv
,
1623 tcp6_init_addr
, sizeof(sin
),
1624 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1627 static void *make_udp6(const struct factory
*factory
, struct fdesc fdescs
[],
1628 int argc
, char ** argv
)
1630 struct sockaddr_in6 sin
, cin
;
1631 return make_udp_common(factory
, fdescs
, argc
, argv
,
1633 tcp6_init_addr
, sizeof(sin
),
1634 (struct sockaddr
*)&sin
, (struct sockaddr
*)&cin
);
1637 static void raw6_init_addr(struct sockaddr
*addr
, bool remote_addr
)
1639 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)addr
;
1640 memset(in6
, 0, sizeof(*in6
));
1641 in6
->sin6_family
= AF_INET6
;
1642 in6
->sin6_flowinfo
= 0;
1645 /* ::ffff:127.0.0.1 */
1646 in6
->sin6_addr
.s6_addr16
[5] = 0xffff;
1647 in6
->sin6_addr
.s6_addr32
[3] = htonl(INADDR_LOOPBACK
);
1649 in6
->sin6_addr
= in6addr_loopback
;
1652 static void *make_raw6(const struct factory
*factory
, struct fdesc fdescs
[],
1653 int argc
, char ** argv
)
1655 struct sockaddr_in6 sin
;
1656 return make_raw_common(factory
, fdescs
, argc
, argv
,
1658 raw6_init_addr
, sizeof(sin
),
1659 (struct sockaddr
*)&sin
);
1663 static void *make_netns(const struct factory
*factory _U_
, struct fdesc fdescs
[],
1664 int argc _U_
, char ** argv _U_
)
1666 int sd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1668 err(EXIT_FAILURE
, "failed in socket()");
1670 int ns
= ioctl(sd
, SIOCGSKNS
);
1672 err(EXIT_FAILURE
, "failed in ioctl(SIOCGSKNS)");
1675 if (ns
!= fdescs
[0].fd
) {
1676 if (dup2(ns
, fdescs
[0].fd
) < 0) {
1680 err(EXIT_FAILURE
, "failed to dup %d -> %d", ns
, fdescs
[0].fd
);
1685 fdescs
[0] = (struct fdesc
){
1687 .close
= close_fdesc
,
1694 #define PARAM_END { .name = NULL, }
1695 static const struct factory factories
[] = {
1697 .name
= "ro-regular-file",
1698 .desc
= "read-only regular file",
1702 .make
= open_ro_regular_file
,
1703 .params
= (struct parameter
[]) {
1706 .type
= PTYPE_STRING
,
1707 .desc
= "file to be opened",
1708 .defv
.string
= "/etc/passwd",
1712 .type
= PTYPE_INTEGER
,
1713 .desc
= "seek bytes after open with SEEK_CUR",
1720 .name
= "pipe-no-fork",
1721 .desc
= "making pair of fds with pipe(2)",
1726 .params
= (struct parameter
[]) {
1729 .type
= PTYPE_STRING
,
1730 .desc
= "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")",
1731 .defv
.string
= "--",
1735 .type
= PTYPE_INTEGER
,
1736 .desc
= "file descriptor for duplicating the pipe input",
1741 .type
= PTYPE_INTEGER
,
1742 .desc
= "file descriptor for duplicating the pipe output",
1749 .name
= "directory",
1750 .desc
= "directory",
1754 .make
= open_directory
,
1755 .params
= (struct parameter
[]) {
1758 .type
= PTYPE_STRING
,
1759 .desc
= "directory to be opened",
1764 .type
= PTYPE_INTEGER
,
1765 .desc
= "read the number of dentries after open with readdir(3)",
1772 .name
= "rw-character-device",
1773 .desc
= "character device with O_RDWR flag",
1777 .make
= open_rw_chrdev
,
1778 .params
= (struct parameter
[]) {
1781 .type
= PTYPE_STRING
,
1782 .desc
= "character device node to be opened",
1783 .defv
.string
= "/dev/zero",
1789 .name
= "socketpair",
1790 .desc
= "AF_UNIX socket pair created with socketpair(2)",
1794 .make
= make_socketpair
,
1795 .params
= (struct parameter
[]) {
1798 .type
= PTYPE_STRING
,
1799 .desc
= "STREAM, DGRAM, or SEQPACKET",
1800 .defv
.string
= "STREAM",
1807 .desc
= "symbolic link itself opened with O_PATH",
1811 .make
= open_with_opath
,
1812 .params
= (struct parameter
[]) {
1815 .type
= PTYPE_STRING
,
1816 .desc
= "path to a symbolic link",
1817 .defv
.string
= "/dev/stdin",
1823 .name
= "ro-block-device",
1824 .desc
= "block device with O_RDONLY flag",
1828 .make
= open_ro_blkdev
,
1829 .params
= (struct parameter
[]) {
1832 .type
= PTYPE_STRING
,
1833 .desc
= "block device node to be opened",
1834 .defv
.string
= "/dev/nullb0",
1840 .name
= "mapped-packet-socket",
1841 .desc
= "mmap'ed AF_PACKET socket",
1845 .make
= make_mmapped_packet_socket
,
1846 .params
= (struct parameter
[]) {
1849 .type
= PTYPE_STRING
,
1850 .desc
= "DGRAM or RAW",
1851 .defv
.string
= "RAW",
1854 .name
= "interface",
1855 .type
= PTYPE_STRING
,
1856 .desc
= "a name of network interface like eth0 or lo",
1857 .defv
.string
= "lo",
1864 .desc
= "pidfd returned from pidfd_open(2)",
1869 .params
= (struct parameter
[]) {
1871 .name
= "target-pid",
1872 .type
= PTYPE_INTEGER
,
1873 .desc
= "the pid of the target process",
1881 .desc
= "inotify fd returned from inotify_init(2)",
1885 .make
= make_inotify_fd
,
1886 .params
= (struct parameter
[]) {
1891 .name
= "unix-stream",
1892 .desc
= "AF_UNIX+SOCK_STREAM sockets",
1896 .make
= make_unix_stream
,
1897 .params
= (struct parameter
[]) {
1900 .type
= PTYPE_STRING
,
1901 .desc
= "path for listening-socket bound to",
1902 .defv
.string
= "/tmp/test_mkfds-unix-stream",
1906 .type
= PTYPE_INTEGER
,
1907 .desc
= "backlog passed to listen(2)",
1912 .type
= PTYPE_BOOLEAN
,
1913 .desc
= "use PATH as an abstract socket address",
1914 .defv
.boolean
= false,
1917 .name
= "server-shutdown",
1918 .type
= PTYPE_INTEGER
,
1919 .desc
= "shutdown the accepted socket; 1: R, 2: W, 3: RW",
1923 .name
= "client-shutdown",
1924 .type
= PTYPE_INTEGER
,
1925 .desc
= "shutdown the client socket; 1: R, 2: W, 3: RW",
1930 .type
= PTYPE_STRING
,
1931 .desc
= "stream or seqpacket",
1932 .defv
.string
= "stream",
1938 .name
= "unix-dgram",
1939 .desc
= "AF_UNIX+SOCK_DGRAM sockets",
1943 .make
= make_unix_dgram
,
1944 .params
= (struct parameter
[]) {
1947 .type
= PTYPE_STRING
,
1948 .desc
= "path for unix non-stream bound to",
1949 .defv
.string
= "/tmp/test_mkfds-unix-dgram",
1953 .type
= PTYPE_BOOLEAN
,
1954 .desc
= "use PATH as an abstract socket address",
1955 .defv
.boolean
= false,
1961 .name
= "unix-in-netns",
1962 .desc
= "make a unix socket in a new network namespace",
1966 .make
= make_unix_in_new_netns
,
1967 .params
= (struct parameter
[]) {
1970 .type
= PTYPE_STRING
,
1971 .desc
= "dgram, stream, or seqpacket",
1972 .defv
.string
= "stream",
1976 .type
= PTYPE_STRING
,
1977 .desc
= "path for unix non-stream bound to",
1978 .defv
.string
= "/tmp/test_mkfds-unix-in-netns",
1982 .type
= PTYPE_BOOLEAN
,
1983 .desc
= "use PATH as an abstract socket address",
1984 .defv
.boolean
= false,
1991 .desc
= "AF_INET+SOCK_STREAM sockets",
1996 .params
= (struct parameter
[]) {
1998 .name
= "server-port",
1999 .type
= PTYPE_INTEGER
,
2000 .desc
= "TCP port the server may listen",
2001 .defv
.integer
= 12345,
2004 .name
= "client-port",
2005 .type
= PTYPE_INTEGER
,
2006 .desc
= "TCP port the client may bind",
2007 .defv
.integer
= 23456,
2014 .desc
= "AF_INET+SOCK_DGRAM sockets",
2019 .params
= (struct parameter
[]) {
2022 .type
= PTYPE_BOOLEAN
,
2023 .desc
= "Use UDPLITE instead of UDP",
2024 .defv
.boolean
= false,
2027 .name
= "server-port",
2028 .type
= PTYPE_INTEGER
,
2029 .desc
= "UDP port the server may listen",
2030 .defv
.integer
= 12345,
2033 .name
= "client-port",
2034 .type
= PTYPE_INTEGER
,
2035 .desc
= "UDP port the client may bind",
2036 .defv
.integer
= 23456,
2039 .name
= "server-do-bind",
2040 .type
= PTYPE_BOOLEAN
,
2041 .desc
= "call bind with the server socket",
2042 .defv
.boolean
= true,
2045 .name
= "client-do-bind",
2046 .type
= PTYPE_BOOLEAN
,
2047 .desc
= "call bind with the client socket",
2048 .defv
.boolean
= true,
2051 .name
= "client-do-connect",
2052 .type
= PTYPE_BOOLEAN
,
2053 .desc
= "call connect with the client socket",
2054 .defv
.boolean
= true,
2061 .desc
= "AF_INET+SOCK_RAW sockets",
2066 .params
= (struct parameter
[]) {
2069 .type
= PTYPE_INTEGER
,
2070 .desc
= "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
2071 .defv
.integer
= IPPROTO_IPIP
,
2079 .desc
= "AF_INET6+SOCK_STREAM sockets",
2084 .params
= (struct parameter
[]) {
2086 .name
= "server-port",
2087 .type
= PTYPE_INTEGER
,
2088 .desc
= "TCP port the server may listen",
2089 .defv
.integer
= 12345,
2092 .name
= "client-port",
2093 .type
= PTYPE_INTEGER
,
2094 .desc
= "TCP port the client may bind",
2095 .defv
.integer
= 23456,
2102 .desc
= "AF_INET6+SOCK_DGRAM sockets",
2107 .params
= (struct parameter
[]) {
2110 .type
= PTYPE_BOOLEAN
,
2111 .desc
= "Use UDPLITE instead of UDP",
2112 .defv
.boolean
= false,
2115 .name
= "server-port",
2116 .type
= PTYPE_INTEGER
,
2117 .desc
= "UDP port the server may listen",
2118 .defv
.integer
= 12345,
2121 .name
= "client-port",
2122 .type
= PTYPE_INTEGER
,
2123 .desc
= "UDP port the client may bind",
2124 .defv
.integer
= 23456,
2127 .name
= "server-do-bind",
2128 .type
= PTYPE_BOOLEAN
,
2129 .desc
= "call bind with the server socket",
2130 .defv
.boolean
= true,
2133 .name
= "client-do-bind",
2134 .type
= PTYPE_BOOLEAN
,
2135 .desc
= "call bind with the client socket",
2136 .defv
.boolean
= true,
2139 .name
= "client-do-connect",
2140 .type
= PTYPE_BOOLEAN
,
2141 .desc
= "call connect with the client socket",
2142 .defv
.boolean
= true,
2149 .desc
= "AF_INET6+SOCK_RAW sockets",
2154 .params
= (struct parameter
[]) {
2157 .type
= PTYPE_INTEGER
,
2158 .desc
= "protocol passed to socket(AF_INET6, SOCK_RAW, protocol)",
2159 .defv
.integer
= IPPROTO_IPIP
,
2167 .desc
= "open a file specifying a netns",
2172 .params
= (struct parameter
[]) {
2178 static int count_parameters(const struct factory
*factory
)
2181 const struct parameter
*p
= factory
->params
;
2186 return p
- factory
->params
;
2189 static void print_factory(const struct factory
*factory
)
2191 printf("%-20s %4s %5d %6d %s\n",
2193 factory
->priv
? "yes": "no",
2195 count_parameters(factory
),
2199 static void list_factories(void)
2201 printf("%-20s PRIV COUNT NPARAM DESCRIPTION\n", "FACTORY");
2202 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
2203 print_factory(factories
+ i
);
2206 static const struct factory
*find_factory(const char *name
)
2208 for (size_t i
= 0; i
< ARRAY_SIZE(factories
); i
++)
2209 if (strcmp(factories
[i
].name
, name
) == 0)
2210 return factories
+ i
;
2214 static void list_parameters(const char *factory_name
)
2216 const struct factory
*factory
= find_factory(factory_name
);
2217 const char *fmt
= "%-15s %-8s %15s %s\n";
2220 errx(EXIT_FAILURE
, _("no such factory: %s"), factory_name
);
2222 if (!factory
->params
)
2225 printf(fmt
, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION");
2226 for (const struct parameter
*p
= factory
->params
; p
->name
!= NULL
; p
++) {
2227 char *defv
= ptype_classes
[p
->type
].sprint(&p
->defv
);
2228 printf(fmt
, p
->name
, ptype_classes
[p
->type
].name
, defv
, p
->desc
);
2233 static void rename_self(const char *comm
)
2235 if (prctl(PR_SET_NAME
, (unsigned long)comm
, 0, 0, 0) < 0)
2236 err(EXIT_FAILURE
, _("failed to rename self via prctl: %s"), comm
);
2239 static void do_nothing(int signum _U_
)
2243 #ifdef __NR_pidfd_open
2246 pidfd_open(pid_t pid
, unsigned int flags
)
2248 return syscall(__NR_pidfd_open
, pid
, flags
);
2252 pidfd_open(pid_t pid _U_
, unsigned int flags _U_
)
2259 static void wait_event(void)
2266 /* Monitor the standard input only when the process
2267 * is in foreground. */
2268 if (tcgetpgrp(STDIN_FILENO
) == getpgrp()) {
2270 FD_SET(0, &readfds
);
2273 sigemptyset(&sigset
);
2275 if (pselect(n
, &readfds
, NULL
, NULL
, NULL
, &sigset
) < 0
2277 errx(EXIT_FAILURE
, _("failed in pselect"));
2280 int main(int argc
, char **argv
)
2283 const struct factory
*factory
;
2284 struct fdesc fdescs
[MAX_N
];
2289 static const struct option longopts
[] = {
2290 { "list", no_argument
, NULL
, 'l' },
2291 { "parameters", required_argument
, NULL
, 'I' },
2292 { "comm", required_argument
, NULL
, 'r' },
2293 { "quiet", no_argument
, NULL
, 'q' },
2294 { "dont-puase", no_argument
, NULL
, 'c' },
2295 { "help", no_argument
, NULL
, 'h' },
2296 { NULL
, 0, NULL
, 0 },
2299 while ((c
= getopt_long(argc
, argv
, "lhqcI:r:", longopts
, NULL
)) != -1) {
2302 usage(stdout
, EXIT_SUCCESS
);
2307 list_parameters(optarg
);
2316 rename_self(optarg
);
2319 usage(stderr
, EXIT_FAILURE
);
2324 errx(EXIT_FAILURE
, _("no file descriptor specification given"));
2326 factory
= find_factory(argv
[optind
]);
2328 errx(EXIT_FAILURE
, _("no such factory: %s"), argv
[optind
]);
2329 assert(factory
->N
+ factory
->EX_N
< MAX_N
);
2332 if ((optind
+ factory
->N
) > argc
)
2333 errx(EXIT_FAILURE
, _("not enough file descriptors given for %s"),
2336 if (factory
->priv
&& getuid() != 0)
2337 errx(EXIT_FAILURE
, "%s factory requires root privilege", factory
->name
);
2339 for (int i
= 0; i
< MAX_N
; i
++) {
2341 fdescs
[i
].close
= NULL
;
2344 for (int i
= 0; i
< factory
->N
; i
++) {
2345 char *str
= argv
[optind
+ i
];
2350 fd
= strtol(str
, &ep
, 10);
2352 err(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
2354 errx(EXIT_FAILURE
, "failed to convert fd number: %s", str
);
2356 errx(EXIT_FAILURE
, _("garbage at the end of number: %s"), str
);
2358 errx(EXIT_FAILURE
, "fd number should not be negative: %s", str
);
2360 errx(EXIT_FAILURE
, "fd 0, 1, 2 are reserved: %s", str
);
2363 optind
+= factory
->N
;
2365 data
= factory
->make(factory
, fdescs
, argc
- optind
, argv
+ optind
);
2367 signal(SIGCONT
, do_nothing
);
2370 printf("%d", getpid());
2372 if (factory
->report
)
2373 factory
->report(factory
, data
, stdout
);
2380 for (int i
= 0; i
< factory
->N
+ factory
->EX_N
; i
++)
2381 if (fdescs
[i
].fd
>= 0 && fdescs
[i
].close
)
2382 fdescs
[i
].close(fdescs
[i
].fd
, fdescs
[i
].data
);
2385 factory
->free (factory
, data
);