4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-02 12:30:24 +08:00

Cygwin: AF_UNIX: update tests

This commit is contained in:
Ken Brown 2020-12-18 16:51:01 -05:00
parent 1b4df3a0be
commit 953308f403
16 changed files with 1080 additions and 9 deletions

View File

@ -19,14 +19,15 @@ EXE = ud_ucase_sv ud_ucase_cl \
fork_socketpair \
select_sv select_cl \
is_seqnum_v2_sv is_seqnum_v3_sv is_seqnum_v2_cl \
send_pty_slave
recv_pty_slave send_pty_slave
all:
cd lib; ${MAKE}
@ ${MAKE} ${EXE}
all: ${EXE}
${EXE}: ${AF_UNIX_LIB} # True as a rough approximation
${AF_UNIX_LIB}:
cd lib; ${MAKE}
*.o: ${AF_UNIX_HDR}
scm_cred_recv.o scm_cred_send.o: scm_cred.h
@ -51,6 +52,8 @@ select_sv.o select_cl.o: select_test.h
is_seqnum_v2_sv.o is_seqnum_v3_sv.o is_seqnum_v2_cl.o: is_seqnum_v2.h
recv_pty_slave.o send_pty_slave.o: pty_slave.h
clean:
cd lib; ${MAKE} clean
${RM} *.exe *.o ${AF_UNIX_LIB}

View File

@ -192,10 +192,43 @@
Sequence number: 0
11. Ancillary data test (SCM_RIGHTS, pty slave descriptor).
send_pty_slave creates pty pair and a shell subprocess connected
to the slave. It sends the slave descriptor over an AF_UNIX
socket to recv_pty_slave. It then monitors its stdin and the pty
master for input. Anything it reads from stdin is written to the
pty master (and so read by the shell). Anything it reads from the
pty master is written to stdout. This is normally just the shell
output. But recv_pty_slave writes "hello" to the slave and so is
read by send_pty_slave and written to stdout as though it were
written by the shell.
In two terminals:
# Terminal 1:
$ ./recv_pty_slave.exe
Waiting for sender to connect and send descriptor...
# Terminal 2:
$ ./send_pty_slave.exe
parent sending descriptor 5 for /dev/pty3 to child
child read 6 bytes (including newline) from fd 4: hello
$ ./send_pty_slave.exe
hello
TODO: Go through the above and check if all programs work with all
options.
#Terminal 1 now shows:
$ ./recv_pty_slave.exe
Waiting for sender to connect and send descriptor...
Received descriptor 5.
Writing "hello" to that descriptor.
This should appear in the other terminal as though it were output by the shell.
Can now exit the shell in terminal 2.
To test all this when the pty is connected to a pseudo terminal,
set SHELL=cmd before running send_pty_slave. Terminal 2 then
looks like this:
$ SHELL=cmd ./send_pty_slave.exe
hello
Microsoft Windows [Version 10.0.18363.1256]
(c) 2019 Microsoft Corporation. All rights reserved.
C:\Users\kbrown\src\cygdll\af_unix\winsup\cygwin\socket_tests>exit

View File

@ -4,7 +4,7 @@ AF_UNIX_LIB = ../libafunix.a
all: ${AF_UNIX_LIB}
${AF_UNIX_LIB}: *.c ename.c.inc
${AF_UNIX_LIB}: *.c *.h ename.c.inc
${CC} -c ${CFLAGS} *.c
${RM} ${AF_UNIX_LIB}
${AR} rs ${AF_UNIX_LIB} *.o

View File

@ -0,0 +1,117 @@
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 or (at your option) *
* any later version. This program is distributed without any warranty. *
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 64-2 */
/* pty_fork.c
Implements ptyFork(), a function that creates a child process connected to
the parent (i.e., the calling process) via a pseudoterminal (pty). The child
is placed in a new session, with the pty slave as its controlling terminal,
and its standard input, output, and error connected to the pty slave.
In the parent, 'masterFd' is used to return the file descriptor for the
pty master.
If 'slaveName' is non-NULL, then it is used to return the name of the pty
slave. If 'slaveName' is not NULL, then 'snLen' should be set to indicate
the size of the buffer pointed to by 'slaveName'.
If 'slaveTermios' and 'slaveWS' are non-NULL, then they are used respectively
to set the terminal attributes and window size of the pty slave.
Returns:
in child: 0
in parent: PID of child or -1 on error
*/
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include "pty_master_open.h"
#include "pty_fork.h" /* Declares ptyFork() */
#include "af_unix_hdr.h"
#define MAX_SNAME 1000 /* Maximum size for pty slave name */
pid_t
ptyFork(int *masterFd, char *slaveName, size_t snLen,
const struct termios *slaveTermios, const struct winsize *slaveWS)
{
int mfd, slaveFd, savedErrno;
pid_t childPid;
char slname[MAX_SNAME];
mfd = ptyMasterOpen(slname, MAX_SNAME);
if (mfd == -1)
return -1;
if (slaveName != NULL) { /* Return slave name to caller */
if (strlen(slname) < snLen) {
strncpy(slaveName, slname, snLen);
} else { /* 'slaveName' was too small */
close(mfd);
errno = EOVERFLOW;
return -1;
}
}
childPid = fork();
if (childPid == -1) { /* fork() failed */
savedErrno = errno; /* close() might change 'errno' */
close(mfd); /* Don't leak file descriptors */
errno = savedErrno;
return -1;
}
if (childPid != 0) { /* Parent */
*masterFd = mfd; /* Only parent gets master fd */
return childPid; /* Like parent of fork() */
}
/* Child falls through to here */
if (setsid() == -1) /* Start a new session */
err_exit("ptyFork:setsid");
close(mfd); /* Not needed in child */
slaveFd = open(slname, O_RDWR); /* Becomes controlling tty */
if (slaveFd == -1)
err_exit("ptyFork:open-slave");
/* #ifdef TIOCSCTTY /\* Acquire controlling tty on BSD *\/ */
/* if (ioctl(slaveFd, TIOCSCTTY, 0) == -1) */
/* err_exit("ptyFork:ioctl-TIOCSCTTY"); */
/* #endif */
if (slaveTermios != NULL) /* Set slave tty attributes */
if (tcsetattr(slaveFd, TCSANOW, slaveTermios) == -1)
err_exit("ptyFork:tcsetattr");
if (slaveWS != NULL) /* Set slave tty window size */
if (ioctl(slaveFd, TIOCSWINSZ, slaveWS) == -1)
err_exit("ptyFork:ioctl-TIOCSWINSZ");
/* Duplicate pty slave to be child's stdin, stdout, and stderr */
if (dup2(slaveFd, STDIN_FILENO) != STDIN_FILENO)
err_exit("ptyFork:dup2-STDIN_FILENO");
if (dup2(slaveFd, STDOUT_FILENO) != STDOUT_FILENO)
err_exit("ptyFork:dup2-STDOUT_FILENO");
if (dup2(slaveFd, STDERR_FILENO) != STDERR_FILENO)
err_exit("ptyFork:dup2-STDERR_FILENO");
if (slaveFd > STDERR_FILENO) /* Safety check */
close(slaveFd); /* No longer need this fd */
return 0; /* Like child of fork() */
}

View File

@ -0,0 +1,27 @@
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 or (at your option) *
* any later version. This program is distributed without any warranty. *
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Header file for Listing 64-2 */
/* pty_fork.h
Header file for pty_fork.c.
*/
#ifndef FORK_PTY_H
#define FORK_PTY_H
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/types.h>
pid_t ptyFork(int *masterFd, char *slaveName, size_t snLen,
const struct termios *slaveTermios, const struct winsize *slaveWS);
#endif

View File

@ -0,0 +1,93 @@
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 or (at your option) *
* any later version. This program is distributed without any warranty. *
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 64-1 */
/* pty_master_open.c
Implement our ptyMasterOpen() function, based on UNIX 98 pseudoterminals.
See comments below.
See also pty_master_open_bsd.c.
*/
#if ! defined(__sun)
/* Prevents ptsname() declaration being visible on Solaris 8 */
#if ! defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600
#define _XOPEN_SOURCE 600
#endif
#endif
#include <stdlib.h>
#include <fcntl.h>
#include "pty_master_open.h" /* Declares ptyMasterOpen() */
#include "af_unix_hdr.h"
/* Some implementations don't have posix_openpt() */
#if defined(__sun) /* Not on Solaris 8 */
#define NO_POSIX_OPENPT
#endif
#ifdef NO_POSIX_OPENPT
static int
posix_openpt(int flags)
{
return open("/dev/ptmx", flags);
}
#endif
/* Open a pty master, returning file descriptor, or -1 on error.
On successful completion, the name of the corresponding pty
slave is returned in 'slaveName'. 'snLen' should be set to
indicate the size of the buffer pointed to by 'slaveName'. */
int
ptyMasterOpen(char *slaveName, size_t snLen)
{
int masterFd, savedErrno;
char *p;
masterFd = posix_openpt(O_RDWR | O_NOCTTY); /* Open pty master */
if (masterFd == -1)
return -1;
if (grantpt(masterFd) == -1) { /* Grant access to slave pty */
savedErrno = errno;
close(masterFd); /* Might change 'errno' */
errno = savedErrno;
return -1;
}
if (unlockpt(masterFd) == -1) { /* Unlock slave pty */
savedErrno = errno;
close(masterFd); /* Might change 'errno' */
errno = savedErrno;
return -1;
}
p = ptsname(masterFd); /* Get slave pty name */
if (p == NULL) {
savedErrno = errno;
close(masterFd); /* Might change 'errno' */
errno = savedErrno;
return -1;
}
if (strlen(p) < snLen) {
strncpy(slaveName, p, snLen);
} else { /* Return an error if buffer too small */
close(masterFd);
errno = EOVERFLOW;
return -1;
}
return masterFd;
}

View File

@ -0,0 +1,24 @@
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 or (at your option) *
* any later version. This program is distributed without any warranty. *
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Header file for Listing 64-1 */
/* pty_open.h
Header file for pty_open.c (and pty_master_open_bsd.c).
*/
#ifndef PTY_MASTER_OPEN_H
#define PTY_MASTER_OPEN_H
#include <sys/types.h>
int ptyMasterOpen(char *slaveName, size_t snLen);
#endif

View File

@ -0,0 +1,89 @@
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 or (at your option) *
* any later version. This program is distributed without any warranty. *
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 62-3 */
/* tty_functions.c
Implement ttySetCbreak() and ttySetRaw().
*/
#include <termios.h>
#include <unistd.h>
#include "tty_functions.h" /* Declares functions defined here */
/* Place terminal referred to by 'fd' in cbreak mode (noncanonical mode
with echoing turned off). This function assumes that the terminal is
currently in cooked mode (i.e., we shouldn't call it if the terminal
is currently in raw mode, since it does not undo all of the changes
made by the ttySetRaw() function below). Return 0 on success, or -1
on error. If 'prevTermios' is non-NULL, then use the buffer to which
it points to return the previous terminal settings. */
int
ttySetCbreak(int fd, struct termios *prevTermios)
{
struct termios t;
if (tcgetattr(fd, &t) == -1)
return -1;
if (prevTermios != NULL)
*prevTermios = t;
t.c_lflag &= ~(ICANON | ECHO);
t.c_lflag |= ISIG;
t.c_iflag &= ~ICRNL;
t.c_cc[VMIN] = 1; /* Character-at-a-time input */
t.c_cc[VTIME] = 0; /* with blocking */
if (tcsetattr(fd, TCSAFLUSH, &t) == -1)
return -1;
return 0;
}
/* Place terminal referred to by 'fd' in raw mode (noncanonical mode
with all input and output processing disabled). Return 0 on success,
or -1 on error. If 'prevTermios' is non-NULL, then use the buffer to
which it points to return the previous terminal settings. */
int
ttySetRaw(int fd, struct termios *prevTermios)
{
struct termios t;
if (tcgetattr(fd, &t) == -1)
return -1;
if (prevTermios != NULL)
*prevTermios = t;
t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
/* Noncanonical mode, disable signals, extended
input processing, and echoing */
t.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR |
INPCK | ISTRIP | IXON | PARMRK);
/* Disable special handling of CR, NL, and BREAK.
No 8th-bit stripping or parity error handling.
Disable START/STOP output flow control. */
t.c_oflag &= ~OPOST; /* Disable all output processing */
t.c_cc[VMIN] = 1; /* Character-at-a-time input */
t.c_cc[VTIME] = 0; /* with blocking */
if (tcsetattr(fd, TCSAFLUSH, &t) == -1)
return -1;
return 0;
}

View File

@ -0,0 +1,26 @@
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 or (at your option) *
* any later version. This program is distributed without any warranty. *
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Header file for Listing 62-3 */
/* tty_functions.h
Header file for tty_functions.c.
*/
#ifndef TTY_FUNCTIONS_H
#define TTY_FUNCTIONS_H
#include <termios.h>
int ttySetCbreak(int fd, struct termios *prevTermios);
int ttySetRaw(int fd, struct termios *prevTermios);
#endif

View File

@ -0,0 +1,46 @@
/* Adapted from Steven, Unix Network Programming
https://github.com/unpbook/unpv13e.git */
#include "af_unix_hdr.h"
ssize_t
write_fd (int fd, void *ptr, size_t nbytes, int sendfd)
{
struct msghdr msg;
struct iovec iov[1];
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof control_un.control;
cmptr = CMSG_FIRSTHDR (&msg);
cmptr->cmsg_len = CMSG_LEN (sizeof (int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*((int *) CMSG_DATA (cmptr)) = sendfd;
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
return sendmsg (fd, &msg, 0);
}
ssize_t
Write_fd (int fd, void *ptr, size_t nbytes, int sendfd)
{
ssize_t n;
if ((n = write_fd (fd, ptr, nbytes, sendfd)) < 0)
errExit ("write_fd");
return n;
}

View File

@ -0,0 +1,322 @@
/* Adapted from Steven, Unix Network Programming
https://github.com/unpbook/unpv13e.git */
#ifndef __unp_h
#define __unp_h
/* #include "../config.h" /\* configuration options for current OS *\/ */
/* /\* "../config.h" is generated by configure *\/ */
/* If anything changes in the following list of #includes, must change
acsite.m4 also, for configure's tests. */
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h> /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <fcntl.h> /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h> /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h> /* for Unix domain sockets */
#include <sys/select.h> /* for convenience */
#include <poll.h> /* for convenience */
#include <strings.h> /* for convenience */
#include <sys/ioctl.h>
#include <pthread.h>
/* The structure returned by recvfrom_flags() */
struct unp_in_pktinfo {
struct in_addr ipi_addr; /* dst IPv4 address */
int ipi_ifindex;/* received interface index */
};
/* POSIX requires that an #include of <poll.h> DefinE INFTIM, but many
systems still DefinE it in <sys/stropts.h>. We don't want to include
all the STREAMS stuff if it's not needed, so we just DefinE INFTIM here.
This is the standard value, but there's no guarantee it is -1. */
#ifndef INFTIM
#define INFTIM (-1) /* infinite poll timeout */
/* $$.Ic INFTIM$$ */
#define INFTIM_UNPH /* tell unpxti.h we defined it */
#endif
/* Following could be derived from SOMAXCONN in <sys/socket.h>, but many
kernels still #define it as 5, while actually supporting many more */
#define LISTENQ 1024 /* 2nd argument to listen() */
/* Miscellaneous constants */
#define MAXLINE 4096 /* max text line length */
#define BUFFSIZE 8192 /* buffer size for reads and writes */
/* Define some port number that can be used for our examples */
#define SERV_PORT 9877 /* TCP and UDP */
#define SERV_PORT_STR "9877" /* TCP and UDP */
#define UNIXSTR_PATH "/tmp/unix.str" /* Unix domain stream */
#define UNIXDG_PATH "/tmp/unix.dg" /* Unix domain datagram */
/* Following shortens all the typecasts of pointer arguments: */
#define SA struct sockaddr
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/* default file access permissions for new files */
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
/* default permissions for new directories */
typedef void Sigfunc(int); /* for signal handlers */
/* prototypes for our own library functions */
/* int connect_nonb(int, const SA *, socklen_t, int); */
/* int connect_timeo(int, const SA *, socklen_t, int); */
/* int daemon_init(const char *, int); */
/* void daemon_inetd(const char *, int); */
/* void dg_cli(FILE *, int, const SA *, socklen_t); */
/* void dg_echo(int, SA *, socklen_t); */
/* int family_to_level(int); */
/* char *gf_time(void); */
/* void heartbeat_cli(int, int, int); */
/* void heartbeat_serv(int, int, int); */
/* struct addrinfo *host_serv(const char *, const char *, int, int); */
/* int inet_srcrt_add(char *); */
/* u_char *inet_srcrt_init(int); */
/* void inet_srcrt_print(u_char *, int); */
/* void inet6_srcrt_print(void *); */
/* char **my_addrs(int *); */
/* int readable_timeo(int, int); */
/* ssize_t readline(int, void *, size_t); */
/* ssize_t readn(int, void *, size_t); */
/* ssize_t read_fd(int, void *, size_t, int *); */
/* ssize_t recvfrom_flags(int, void *, size_t, int *, SA *, socklen_t *, */
/* struct unp_in_pktinfo *); */
/* Sigfunc *signal_intr(int, Sigfunc *); */
/* int sock_bind_wild(int, int); */
/* int sock_cmp_addr(const SA *, const SA *, socklen_t); */
/* int sock_cmp_port(const SA *, const SA *, socklen_t); */
/* int sock_get_port(const SA *, socklen_t); */
/* void sock_set_addr(SA *, socklen_t, const void *); */
/* void sock_set_port(SA *, socklen_t, int); */
/* void sock_set_wild(SA *, socklen_t); */
/* char *sock_ntop(const SA *, socklen_t); */
/* char *sock_ntop_host(const SA *, socklen_t); */
/* int sockfd_to_family(int); */
/* void str_echo(int); */
/* void str_cli(FILE *, int); */
/* int tcp_connect(const char *, const char *); */
/* int tcp_listen(const char *, const char *, socklen_t *); */
/* void tv_sub(struct timeval *, struct timeval *); */
/* int udp_client(const char *, const char *, SA **, socklen_t *); */
/* int udp_connect(const char *, const char *); */
/* int udp_server(const char *, const char *, socklen_t *); */
/* int writable_timeo(int, int); */
/* ssize_t writen(int, const void *, size_t); */
ssize_t write_fd(int, void *, size_t, int);
/* #ifdef MCAST */
/* int mcast_leave(int, const SA *, socklen_t); */
/* int mcast_join(int, const SA *, socklen_t, const char *, u_int); */
/* int mcast_leave_source_group(int sockfd, const SA *src, socklen_t srclen, */
/* const SA *grp, socklen_t grplen); */
/* int mcast_join_source_group(int sockfd, const SA *src, socklen_t srclen, */
/* const SA *grp, socklen_t grplen, */
/* const char *ifname, u_int ifindex); */
/* int mcast_block_source(int sockfd, const SA *src, socklen_t srclen, */
/* const SA *grp, socklen_t grplen); */
/* int mcast_unblock_source(int sockfd, const SA *src, socklen_t srclen, */
/* const SA *grp, socklen_t grplen); */
/* int mcast_get_if(int); */
/* int mcast_get_loop(int); */
/* int mcast_get_ttl(int); */
/* int mcast_set_if(int, const char *, u_int); */
/* int mcast_set_loop(int, int); */
/* int mcast_set_ttl(int, int); */
/* void Mcast_leave(int, const SA *, socklen_t); */
/* void Mcast_join(int, const SA *, socklen_t, const char *, u_int); */
/* void Mcast_leave_source_group(int sockfd, const SA *src, socklen_t srclen, */
/* const SA *grp, socklen_t grplen); */
/* void Mcast_join_source_group(int sockfd, const SA *src, socklen_t srclen, */
/* const SA *grp, socklen_t grplen, */
/* const char *ifname, u_int ifindex); */
/* void Mcast_block_source(int sockfd, const SA *src, socklen_t srclen, */
/* const SA *grp, socklen_t grplen); */
/* void Mcast_unblock_source(int sockfd, const SA *src, socklen_t srclen, */
/* const SA *grp, socklen_t grplen); */
/* int Mcast_get_if(int); */
/* int Mcast_get_loop(int); */
/* int Mcast_get_ttl(int); */
/* void Mcast_set_if(int, const char *, u_int); */
/* void Mcast_set_loop(int, int); */
/* void Mcast_set_ttl(int, int); */
/* #endif */
/* uint16_t in_cksum(uint16_t *, int); */
/* #ifndef HAVE_GETADDRINFO_PROTO */
/* int getaddrinfo(const char *, const char *, const struct addrinfo *, */
/* struct addrinfo **); */
/* void freeaddrinfo(struct addrinfo *); */
/* char *gai_strerror(int); */
/* #endif */
/* #ifndef HAVE_GETNAMEINFO_PROTO */
/* int getnameinfo(const SA *, socklen_t, char *, size_t, char *, size_t, int); */
/* #endif */
/* #ifndef HAVE_GETHOSTNAME_PROTO */
/* int gethostname(char *, int); */
/* #endif */
/* #ifndef HAVE_HSTRERROR_PROTO */
/* const char *hstrerror(int); */
/* #endif */
/* #ifndef HAVE_IF_NAMETOINDEX_PROTO */
/* unsigned int if_nametoindex(const char *); */
/* char *if_indextoname(unsigned int, char *); */
/* void if_freenameindex(struct if_nameindex *); */
/* struct if_nameindex *if_nameindex(void); */
/* #endif */
/* #ifndef HAVE_INET_PTON_PROTO */
/* int inet_pton(int, const char *, void *); */
/* const char *inet_ntop(int, const void *, char *, size_t); */
/* #endif */
/* #ifndef HAVE_INET_ATON_PROTO */
/* int inet_aton(const char *, struct in_addr *); */
/* #endif */
/* #ifndef HAVE_PSELECT_PROTO */
/* int pselect(int, fd_set *, fd_set *, fd_set *, */
/* const struct timespec *, const sigset_t *); */
/* #endif */
/* #ifndef HAVE_SOCKATMARK_PROTO */
/* int sockatmark(int); */
/* #endif */
/* #ifndef HAVE_SNPRINTF_PROTO */
/* int snprintf(char *, size_t, const char *, ...); */
/* #endif */
/* /\* prototypes for our own library wrapper functions *\/ */
/* void Connect_timeo(int, const SA *, socklen_t, int); */
/* int Family_to_level(int); */
/* struct addrinfo *Host_serv(const char *, const char *, int, int); */
/* const char *Inet_ntop(int, const void *, char *, size_t); */
/* void Inet_pton(int, const char *, void *); */
/* char *If_indextoname(unsigned int, char *); */
/* unsigned int If_nametoindex(const char *); */
/* struct if_nameindex *If_nameindex(void); */
/* char **My_addrs(int *); */
/* ssize_t Read_fd(int, void *, size_t, int *); */
/* int Readable_timeo(int, int); */
/* ssize_t Recvfrom_flags(int, void *, size_t, int *, SA *, socklen_t *, */
/* struct unp_in_pktinfo *); */
/* Sigfunc *Signal(int, Sigfunc *); */
/* Sigfunc *Signal_intr(int, Sigfunc *); */
/* int Sock_bind_wild(int, int); */
/* char *Sock_ntop(const SA *, socklen_t); */
/* char *Sock_ntop_host(const SA *, socklen_t); */
/* int Sockfd_to_family(int); */
/* int Tcp_connect(const char *, const char *); */
/* int Tcp_listen(const char *, const char *, socklen_t *); */
/* int Udp_client(const char *, const char *, SA **, socklen_t *); */
/* int Udp_connect(const char *, const char *); */
/* int Udp_server(const char *, const char *, socklen_t *); */
ssize_t Write_fd(int, void *, size_t, int);
/* int Writable_timeo(int, int); */
/* /\* prototypes for our Unix wrapper functions: see {Sec errors} *\/ */
/* void *Calloc(size_t, size_t); */
/* void Close(int); */
/* void Dup2(int, int); */
/* int Fcntl(int, int, int); */
/* void Gettimeofday(struct timeval *, void *); */
/* int Ioctl(int, int, void *); */
/* pid_t Fork(void); */
/* void *Malloc(size_t); */
/* int Mkstemp(char *); */
/* void *Mmap(void *, size_t, int, int, int, off_t); */
/* int Open(const char *, int, mode_t); */
/* void Pipe(int *fds); */
/* ssize_t Read(int, void *, size_t); */
/* void Sigaddset(sigset_t *, int); */
/* void Sigdelset(sigset_t *, int); */
/* void Sigemptyset(sigset_t *); */
/* void Sigfillset(sigset_t *); */
/* int Sigismember(const sigset_t *, int); */
/* void Sigpending(sigset_t *); */
/* void Sigprocmask(int, const sigset_t *, sigset_t *); */
/* char *Strdup(const char *); */
/* long Sysconf(int); */
/* void Sysctl(int *, u_int, void *, size_t *, void *, size_t); */
/* void Unlink(const char *); */
/* pid_t Wait(int *); */
/* pid_t Waitpid(pid_t, int *, int); */
/* void Write(int, void *, size_t); */
/* /\* prototypes for our stdio wrapper functions: see {Sec errors} *\/ */
/* void Fclose(FILE *); */
/* FILE *Fdopen(int, const char *); */
/* char *Fgets(char *, int, FILE *); */
/* FILE *Fopen(const char *, const char *); */
/* void Fputs(const char *, FILE *); */
/* /\* prototypes for our socket wrapper functions: see {Sec errors} *\/ */
/* int Accept(int, SA *, socklen_t *); */
/* void Bind(int, const SA *, socklen_t); */
/* void Connect(int, const SA *, socklen_t); */
/* void Getpeername(int, SA *, socklen_t *); */
/* void Getsockname(int, SA *, socklen_t *); */
/* void Getsockopt(int, int, int, void *, socklen_t *); */
/* #ifdef HAVE_INET6_RTH_INIT */
/* int Inet6_rth_space(int, int); */
/* void *Inet6_rth_init(void *, socklen_t, int, int); */
/* void Inet6_rth_add(void *, const struct in6_addr *); */
/* void Inet6_rth_reverse(const void *, void *); */
/* int Inet6_rth_segments(const void *); */
/* struct in6_addr *Inet6_rth_getaddr(const void *, int); */
/* #endif */
/* #ifdef HAVE_KQUEUE */
/* int Kqueue(void); */
/* int Kevent(int, const struct kevent *, int, */
/* struct kevent *, int, const struct timespec *); */
/* #endif */
/* void Listen(int, int); */
/* #ifdef HAVE_POLL */
/* int Poll(struct pollfd *, unsigned long, int); */
/* #endif */
/* ssize_t Readline(int, void *, size_t); */
/* ssize_t Readn(int, void *, size_t); */
/* ssize_t Recv(int, void *, size_t, int); */
/* ssize_t Recvfrom(int, void *, size_t, int, SA *, socklen_t *); */
/* ssize_t Recvmsg(int, struct msghdr *, int); */
/* int Select(int, fd_set *, fd_set *, fd_set *, struct timeval *); */
/* void Send(int, const void *, size_t, int); */
/* void Sendto(int, const void *, size_t, int, const SA *, socklen_t); */
/* void Sendmsg(int, const struct msghdr *, int); */
/* void Setsockopt(int, int, int, const void *, socklen_t); */
/* void Shutdown(int, int); */
/* int Sockatmark(int); */
/* int Socket(int, int, int); */
/* void Socketpair(int, int, int, int *); */
/* void Writen(int, void *, size_t); */
/* void err_dump(const char *, ...); */
/* void err_msg(const char *, ...); */
/* void err_quit(const char *, ...); */
/* void err_ret(const char *, ...); */
/* void err_sys(const char *, ...); */
#endif /* __unp_h */

View File

@ -0,0 +1,5 @@
/* pty_slave.h
Header file for send_pty_slave.c and recv_pty_slave.c
*/
#define SOCK_PATH "/tmp/pty_slave"

View File

@ -0,0 +1,3 @@
#include "af_unix_hdr.h"
#include "pty_slave.h"

View File

@ -0,0 +1,37 @@
#include "af_unix_hdr.h"
#include "pty_slave.h"
#define BUF_SIZE 100
int
main (int argc, char *argv[])
{
int lfd, connfd, ptyfd;
if (remove (SOCK_PATH) == -1 && errno != ENOENT)
errExit ("remove-%s", SOCK_PATH);
lfd = unixBind (SOCK_PATH, SOCK_STREAM);
if (lfd < 0)
errExit ("unixBind");
printf ("Waiting for sender to connect and send descriptor...\n");
if (listen (lfd, 5) < 0)
errExit ("listen");
connfd = accept (lfd, NULL, NULL);
if (connfd < 0)
errExit ("accept");
ptyfd = recvfd (connfd);
if (ptyfd < 0)
errExit ("recvfd");
printf ("Received descriptor %d.\n", ptyfd);
printf ("Writing \"hello\" to that descriptor.\n"
"This should appear in the other terminal "
"as though it were output by the shell.\n");
if (write (ptyfd, "hello\n", 6) != 6)
errExit ("write");
if (close (ptyfd) < 0)
errMsg ("close");
if (close (lfd) < 0)
errMsg ("close");
if (close (connfd) < 0)
errMsg ("close");
}

View File

@ -0,0 +1,144 @@
/* Adapted from Kerrisk's script.c by Ken Brown */
/*
Create a pty pair and fork/exec a shell running on the slave. Send
the slave fd across an AF_UNIX socket to a process running
recv_pty_slave.
*/
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2018. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 64-3 */
/* script.c
A simple version of script(1).
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <libgen.h>
#include <termios.h>
#if ! defined(__hpux)
/* HP-UX 11 doesn't have this header file */
#include <sys/select.h>
#endif
#include "pty_fork.h" /* Declaration of ptyFork() */
#include "tty_functions.h" /* Declaration of ttySetRaw() */
#include "af_unix_hdr.h"
#include "pty_slave.h"
#define BUF_SIZE 256
#define MAX_SNAME 1000
struct termios ttyOrig;
static void /* Reset terminal mode on program exit */
ttyReset(void)
{
if (tcsetattr(STDIN_FILENO, TCSANOW, &ttyOrig) == -1)
errExit("tcsetattr");
}
int
main(int argc, char *argv[])
{
char slaveName[MAX_SNAME];
char *shell;
int masterFd, slaveFd, connFd;
struct winsize ws;
fd_set inFds;
char buf[BUF_SIZE];
ssize_t numRead;
pid_t childPid;
/* Retrieve the attributes of terminal on which we are started */
if (tcgetattr(STDIN_FILENO, &ttyOrig) == -1)
errExit("tcgetattr");
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
errExit("ioctl-TIOCGWINSZ");
/* Create a child process, with parent and child connected via a
pty pair. The child is connected to the pty slave and its terminal
attributes are set to be the same as those retrieved above. */
childPid = ptyFork(&masterFd, slaveName, MAX_SNAME, &ttyOrig, &ws);
if (childPid == -1)
errExit("ptyFork");
if (childPid == 0) { /* Child: execute a shell on pty slave */
/* If the SHELL variable is set, use its value to determine
the shell execed in child. Otherwise use /bin/sh. */
shell = getenv("SHELL");
if (shell == NULL || *shell == '\0')
shell = "/bin/sh";
execlp(shell, shell, (char *) NULL);
errExit("execlp"); /* If we get here, something went wrong */
}
/* Parent */
if ((connFd = unixConnect (SOCK_PATH, SOCK_STREAM)) < 0)
errExit ("unixConnect");
/* Open slave and send its fd across the socket. */
if ((slaveFd = open (slaveName, O_RDWR | O_NOCTTY)) < 0)
errExit ("open");
if (sendfd (connFd, slaveFd) < 0)
errExit ("sendfd");
if (close (slaveFd) < 0)
errMsg ("close");
if (close (connFd) < 0)
errMsg ("close");
/* Place terminal in raw mode so that we can pass all terminal
input to the pseudoterminal master untouched */
ttySetRaw(STDIN_FILENO, &ttyOrig);
if (atexit(ttyReset) != 0)
errExit("atexit");
/* Loop monitoring terminal and pty master for input. If the
terminal is ready for input, then read some bytes and write
them to the pty master. If the pty master is ready for input,
then read some bytes and write them to the terminal. */
for (;;) {
FD_ZERO(&inFds);
FD_SET(STDIN_FILENO, &inFds);
FD_SET(masterFd, &inFds);
if (select(masterFd + 1, &inFds, NULL, NULL, NULL) == -1)
errExit("select");
if (FD_ISSET(STDIN_FILENO, &inFds)) { /* stdin --> pty */
numRead = read(STDIN_FILENO, buf, BUF_SIZE);
if (numRead <= 0)
exit(EXIT_SUCCESS);
if (write(masterFd, buf, numRead) != numRead)
fatal("partial/failed write (masterFd)");
}
if (FD_ISSET(masterFd, &inFds)) { /* pty --> stdout */
numRead = read(masterFd, buf, BUF_SIZE);
if (numRead <= 0)
exit(EXIT_SUCCESS);
if (write(STDOUT_FILENO, buf, numRead) != numRead)
fatal("partial/failed write (STDOUT_FILENO)");
}
}
}

View File

@ -0,0 +1,102 @@
/*
Fork a subprocess, open a pty pair, and send the pty slave file
descriptor to the subprocess over an AF_UNIX socket. Invoke with
--debug to allow time to attach gdb to the child.
*/
#include "af_unix_hdr.h"
#include "pty_master_open.h"
#include "read_line.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUF_SIZE 100
#define MAX_SNAME 100 /* Maximum size for pty slave name */
int
main(int argc, char *argv[])
{
Boolean debug = FALSE;
pid_t pid;
int pipefd[2];
int pfd; /* parent's end */
int cfd; /* child's end */
if (argc > 1 && strcmp (argv[1], "--debug") == 0)
debug = TRUE;
if (socketpair (AF_UNIX, SOCK_STREAM, 0, pipefd) < 0)
errExit ("socketpair");
pfd = pipefd[1];
cfd = pipefd[0];
if ((pid = fork ()) < 0)
errExit ("fork");
else if (pid > 0) /* parent */
{
int mfd, sfd, junk;
char slname[MAX_SNAME];
if (close (cfd) < 0)
errExit ("close");
if ((mfd = ptyMasterOpen (slname, MAX_SNAME)) < 0)
errExit ("ptyMasterOpen");
if ((sfd = open (slname, O_RDWR | O_NOCTTY)) < 0)
errExit ("open");
if (debug)
{
printf ("parent pid %d, child pid %d, sleeping...\n", getpid (), pid);
sleep (30);
}
printf ("parent sending descriptor %d for %s to child\n", sfd, slname);
if (sendfd (pfd, sfd) < 0)
errExit ("sendfd");
if (close (sfd) < 0)
errMsg ("close");
if (write (mfd, "hello\n", 6) < 0)
errExit ("write");
/* Wait for child. */
if (read (pfd, &junk, sizeof junk) != sizeof junk)
errMsg ("read");
if (close (pfd) < 0)
errMsg ("close");
if (close (mfd) < 0)
errMsg ("close");
}
else /* child */
{
int fd, junk;
ssize_t nr;
char buf[BUF_SIZE];
if (close (pfd) < 0)
errExit ("close");
if (debug)
sleep (30);
/* Read fd from parent. */
fd = recvfd (cfd);
if (fd < 0)
errExit ("recvfd");
/* Read a line from fd. */
if ((nr = readLine (fd, buf, BUF_SIZE)) < 0)
{
close (fd);
errExit ("readLine");
}
/* Kill newline. */
buf[nr - 1] = '\0';
printf ("child read %zd bytes (including newline) from fd %d: %s\n", nr,
fd, buf);
if (close (fd) == -1)
errMsg ("close");
/* Tell parent we're done. */
if (write (cfd, &junk, sizeof junk) != sizeof junk)
errMsg ("write");
if (close (cfd) < 0)
errExit ("close");
}
}