mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-02 12:02:47 -05:00
Add a directory 'contrib/cygtermd', containing the source code for my
hacky helper program to let PuTTY act as a local pterm-oid on Cygwin-enabled Windows systems. [originally from svn r9191]
This commit is contained in:
188
contrib/cygtermd/pty.c
Normal file
188
contrib/cygtermd/pty.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* pty.c - pseudo-terminal handling
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE
|
||||
#include <features.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "pty.h"
|
||||
#include "malloc.h"
|
||||
|
||||
static char ptyname[FILENAME_MAX];
|
||||
int master = -1;
|
||||
|
||||
void pty_preinit(void)
|
||||
{
|
||||
/*
|
||||
* Allocate the pty.
|
||||
*/
|
||||
master = open("/dev/ptmx", O_RDWR);
|
||||
if (master < 0) {
|
||||
perror("/dev/ptmx: open");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (grantpt(master) < 0) {
|
||||
perror("grantpt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (unlockpt(master) < 0) {
|
||||
perror("unlockpt");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void pty_resize(int w, int h)
|
||||
{
|
||||
struct winsize sz;
|
||||
|
||||
assert(master >= 0);
|
||||
|
||||
sz.ws_row = h;
|
||||
sz.ws_col = w;
|
||||
sz.ws_xpixel = sz.ws_ypixel = 0;
|
||||
ioctl(master, TIOCSWINSZ, &sz);
|
||||
}
|
||||
|
||||
int run_program_in_pty(const struct shell_data *shdata,
|
||||
char *directory, char **program_args)
|
||||
{
|
||||
int slave, pid;
|
||||
char *fallback_args[2];
|
||||
|
||||
assert(master >= 0);
|
||||
|
||||
ptyname[FILENAME_MAX-1] = '\0';
|
||||
strncpy(ptyname, ptsname(master), FILENAME_MAX-1);
|
||||
|
||||
#if 0
|
||||
{
|
||||
struct winsize ws;
|
||||
struct termios ts;
|
||||
|
||||
/*
|
||||
* FIXME: think up some good defaults here
|
||||
*/
|
||||
|
||||
if (!ioctl(0, TIOCGWINSZ, &ws))
|
||||
ioctl(master, TIOCSWINSZ, &ws);
|
||||
if (!tcgetattr(0, &ts))
|
||||
tcsetattr(master, TCSANOW, &ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
slave = open(ptyname, O_RDWR | O_NOCTTY);
|
||||
if (slave < 0) {
|
||||
perror("slave pty: open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fork and execute the command.
|
||||
*/
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
int i, fd;
|
||||
|
||||
/*
|
||||
* We are the child.
|
||||
*/
|
||||
close(master);
|
||||
|
||||
fcntl(slave, F_SETFD, 0); /* don't close on exec */
|
||||
dup2(slave, 0);
|
||||
dup2(slave, 1);
|
||||
if (slave != 0 && slave != 1)
|
||||
close(slave);
|
||||
dup2(1, 2);
|
||||
setsid();
|
||||
setpgrp();
|
||||
i = 0;
|
||||
#ifdef TIOCNOTTY
|
||||
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
|
||||
ioctl(fd, TIOCNOTTY, &i);
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
#ifdef TIOCSCTTY
|
||||
ioctl(0, TIOCSCTTY, &i);
|
||||
#endif
|
||||
tcsetpgrp(0, getpgrp());
|
||||
|
||||
for (i = 0; i < shdata->nenvvars; i++)
|
||||
putenv(shdata->envvars[i]);
|
||||
if (shdata->termtype)
|
||||
putenv(shdata->termtype);
|
||||
|
||||
if (directory)
|
||||
chdir(directory);
|
||||
|
||||
/*
|
||||
* Use the provided shell program name, if the user gave
|
||||
* one. Failing that, use $SHELL; failing that, look up
|
||||
* the user's default shell in the password file; failing
|
||||
* _that_, revert to the bog-standard /bin/sh.
|
||||
*/
|
||||
if (!program_args) {
|
||||
char *shell;
|
||||
|
||||
shell = getenv("SHELL");
|
||||
if (!shell) {
|
||||
const char *login;
|
||||
uid_t uid;
|
||||
struct passwd *pwd;
|
||||
|
||||
/*
|
||||
* For maximum generality in the face of multiple
|
||||
* /etc/passwd entries with different login names and
|
||||
* shells but a shared uid, we start by using
|
||||
* getpwnam(getlogin()) if it's available - but we
|
||||
* insist that its uid must match our real one, or we
|
||||
* give up and fall back to getpwuid(getuid()).
|
||||
*/
|
||||
uid = getuid();
|
||||
login = getlogin();
|
||||
if (login && (pwd = getpwnam(login)) && pwd->pw_uid == uid)
|
||||
shell = pwd->pw_shell;
|
||||
else if ((pwd = getpwuid(uid)))
|
||||
shell = pwd->pw_shell;
|
||||
}
|
||||
if (!shell)
|
||||
shell = "/bin/sh";
|
||||
|
||||
fallback_args[0] = shell;
|
||||
fallback_args[1] = NULL;
|
||||
program_args = fallback_args;
|
||||
}
|
||||
|
||||
execv(program_args[0], program_args);
|
||||
|
||||
/*
|
||||
* If we're here, exec has gone badly foom.
|
||||
*/
|
||||
perror("exec");
|
||||
exit(127);
|
||||
}
|
||||
|
||||
close(slave);
|
||||
|
||||
return master;
|
||||
}
|
Reference in New Issue
Block a user