4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-08 10:09:32 +08:00

Cygwin: AF_UNIX: update tests

This commit is contained in:
Ken Brown 2021-01-07 12:22:41 -05:00
parent 6841fcb82f
commit a2e279eb68
5 changed files with 238 additions and 2 deletions

View File

@ -19,7 +19,8 @@ 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 \
recv_pty_slave send_pty_slave
recv_pty_slave send_pty_slave \
recv_pty_master send_pty_master
all: ${EXE}
@ -54,6 +55,8 @@ 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
recv_pty_master.o send_pty_master.o: pty_master.h
clean:
cd lib; ${MAKE} clean
${RM} *.exe *.o ${AF_UNIX_LIB}

View File

@ -210,7 +210,6 @@
# Terminal 2:
$ ./send_pty_slave.exe
$ ./send_pty_slave.exe
hello
#Terminal 1 now shows:
@ -232,3 +231,49 @@
(c) 2019 Microsoft Corporation. All rights reserved.
C:\Users\kbrown\src\cygdll\af_unix\winsup\cygwin\socket_tests>exit
12. Ancillary data test (SCM_RIGHTS, pty master descriptor).
send_pty_master creates pty pair and a shell subprocess connected
to the slave. It then does the same as in 11, except that it
sends the master descriptor instead of the slave descriptor.
recv_pty_master writes "ps\n" to the received master fd. The
shell created by send_pty_master reads and executes this.
In two terminals:
# Terminal 1:
$ ./recv_pty_master.exe
Waiting for sender to connect and send descriptor...
# Terminal 2:
$ ./send_pty_master.exe
ps
$ ps
PID PPID PGID WINPID TTY UID STIME COMMAND
934 933 934 138392 pty2 197609 13:47:22 /usr/bin/bash
937 934 937 109052 pty2 197609 13:47:22 /usr/bin/ps
887 886 887 51496 pty1 197609 13:11:25 /usr/bin/bash
875 874 875 30396 pty0 197609 13:11:21 /usr/bin/bash
874 1 874 23516 ? 197609 13:11:21 /usr/bin/mintty
886 1 886 118428 ? 197609 13:11:25 /usr/bin/mintty
933 887 933 59856 pty1 197609 13:47:22 /home/kbrown/src/cygdll/af_unix/winsup/cygwin/socket_tests/send_pty_master
932 875 932 115304 pty0 197609 13:46:30 /home/kbrown/src/cygdll/af_unix/winsup/cygwin/socket_tests/recv_pty_master
[Why is ps echoed twice?]
#Terminal 1 now shows:
$ ./recv_pty_master.exe
Waiting for sender to connect and send descriptor...
Received descriptor 5.
Writing "ps" to that descriptor.
This should appear in the other terminal
and be executed by the shell running there.
Waiting for sender to finish...
Can now exit the shell in terminal 2 and both programs exit.
This doesn't work if we use SHELL=cmd in terminal 2. "ps" gets
echoed but not executed. I'm not sure if we should expect it to
work.

View File

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

View File

@ -0,0 +1,40 @@
#include "af_unix_hdr.h"
#include "pty_master.h"
#define BUF_SIZE 100
int
main (int argc, char *argv[])
{
int lfd, connfd, ptyfd, junk;
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 \"ps\" to that descriptor.\n"
"This should appear in the other terminal\n"
"and be executed by the shell running there.\n");
if (write (ptyfd, "ps\n", 3) != 3)
errExit ("write");
printf ("Waiting for sender to finish...\n");
if (read (connfd, &junk, sizeof junk) < 0)
errExit ("read");
if (close (ptyfd) < 0)
errMsg ("close");
if (close (lfd) < 0)
errMsg ("close");
if (close (connfd) < 0)
errMsg ("close");
}

View File

@ -0,0 +1,143 @@
/* Adapted from Kerrisk's script.c by Ken Brown */
/*
Create a pty pair and fork/exec a shell running on the slave. Send
the master 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_master.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, connFd, junk;
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");
/* Send master fd across the socket. */
if (sendfd (connFd, masterFd) < 0)
errExit ("sendfd");
/* 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)
break;
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)
break;
if (write(STDOUT_FILENO, buf, numRead) != numRead)
fatal("partial/failed write (STDOUT_FILENO)");
}
}
/* Notify receiver that we're done. */
if (write (connFd, &junk, sizeof junk) != sizeof junk)
errMsg ("write");
if (close (connFd) < 0)
errMsg ("close");
}