Skip to content

Instantly share code, notes, and snippets.

@mshroyer
Last active December 10, 2015 03:48
Show Gist options
  • Select an option

  • Save mshroyer/4377173 to your computer and use it in GitHub Desktop.

Select an option

Save mshroyer/4377173 to your computer and use it in GitHub Desktop.
This fails on OpenBSD 5.2
/**
* ptycheck.c - Demonstrate possible problem in OpenBSD's ptcwrite
*
* Opens a pseudoterminal pair in "raw" mode, then forks off a child
* process which attempts to write MESSAGE_LEN random bytes to the pty
* master; meanwhile the parent process tries to read the same number of
* bytes from the slave. Once the parent has received the expected number
* of bytes, it compares the message received against the original to
* ensure that all data shuffled across the pseudoterminal successfully.
*
* On OpenBSD 5.2 i386 and amd64, this fails with the parent process
* blocking indefinitely after reading only 4088 bytes (out of 4096
* expected) from the pty slave. The same behavior is observed on 4.7 and
* 4.8 i386, and can be seen when MESSAGE_LEN is 1024 or larger.
*
* Compile with `gcc -o ptycheck ptycheck.c -lutil`.
*
* Mark Shroyer
* Tue Dec 25 20:04:48 EST 2012
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include <util.h>
/* Number of pseudorandom bytes to try sending */
#define MESSAGE_LEN 4096
int
main(int argc, char *argv)
{
int fd, sfd, pid;
char *send_buf, *recv_buf;
ssize_t n;
size_t i;
struct termios t;
if ((send_buf = malloc(MESSAGE_LEN)) == NULL)
return 1;
if ((recv_buf = malloc(MESSAGE_LEN)) == NULL)
return 1;
for (i = 0; i < MESSAGE_LEN; i++)
send_buf[i] = random() % 256;
if (openpty(&fd, &sfd, NULL, NULL, NULL) < 0) {
perror("Failed to open PTY pair");
return 1;
}
if (tcgetattr(sfd, &t) < 0)
return 1;
cfmakeraw(&t);
if (tcsetattr(sfd, TCSAFLUSH, &t) < 0)
return 1;
i = 0;
switch (pid = fork()) {
case -1:
perror("Unable to fork child process");
return 1;
case 0:
/* Child process writes to pty master */
while (i < MESSAGE_LEN) {
if ((n = write(fd, send_buf + i, MESSAGE_LEN - i)) < 0) {
perror("Couldn't write to pty master");
return 1;
}
i += n;
printf("-> master: %zd bytes\n", i);
}
printf("Done writing.\n");
return 0;
default:
/* Parent process reads from pty slave */
while (i < MESSAGE_LEN) {
if ((n = read(sfd, recv_buf + i, MESSAGE_LEN - i)) < 0) {
perror("Couldn't read from pty slave");
return 1;
}
i += n;
printf("<- slave: %zd bytes\n", i);
}
printf("Done reading.\n");
if (memcmp(send_buf, recv_buf, MESSAGE_LEN) != 0) {
printf("Message altered in transit!\n");
return 1;
}
printf("Message transferred successfully.\n");
waitpid(pid, NULL, 0);
return 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment