From a25368714f0f18c8e11ce5d1da827d1172f6b988 Mon Sep 17 00:00:00 2001 From: Nick Briggs Date: Fri, 8 Oct 2021 17:58:29 -0700 Subject: [PATCH] Use SHELL rather than /bin/csh when forking shells. Issue Interlisp/medley#384 (#400) As long as $(SHELL) names an executable that appears in /etc/shells (as determined by the getusershell() function) use that. It used to always use /bin/csh, but some modern distros do not ship with csh installed. Using the user's preferred shell seems like a better choice, while allowing the choice from /etc/shells gives some additional flexibility. --- src/unixcomm.c | 2 +- src/unixfork.c | 118 +++++++++++++++++++++++++------------------------ 2 files changed, 61 insertions(+), 59 deletions(-) diff --git a/src/unixcomm.c b/src/unixcomm.c index 78cebe2..03b8d28 100644 --- a/src/unixcomm.c +++ b/src/unixcomm.c @@ -351,7 +351,7 @@ static int FindAvailablePty(char *Slave) { /* => byte count (<= 512), NIL (no data), or T (EOF) */ /* 10 Set Window Size, Arg2 = rows, Arg3 = columns */ /* 11 Fork PTY to Shell (obsoletes command 4) */ -/* Arg1 = termtype, Arg2 = csh command string */ +/* Arg1 = termtype, Arg2 = shell command string */ /* => Job # or NIL */ /* 12 Create Unix Socket */ /* Arg1 = pathname to bind socket to (string) */ diff --git a/src/unixfork.c b/src/unixfork.c index bbbf33e..c235071 100644 --- a/src/unixfork.c +++ b/src/unixfork.c @@ -75,76 +75,78 @@ static inline ssize_t SAFEREAD(int f, char *b, int c) /* */ /************************************************************************/ -/* Creates a PTY connection to a csh */ +/* Creates a PTY connection to a shell */ static int ForkUnixShell(int slot, char *PtySlave, char *termtype, char *shellarg) { int PID, SlaveFD; struct termios tio; + char *argvec[4] = {NULL, NULL, NULL, NULL}; + char *shell = NULL; + char *userShell = NULL; PID = fork(); - if (PID == 0) { - char *argvec[4]; - - if (0 > setsid()) /* create us a new session for tty purposes */ - perror("setsid"); - -/* Open the slave side */ - SlaveFD = open(PtySlave, O_RDWR); - if (SlaveFD == -1) { - perror("Slave Open"); - perror(PtySlave); - exit(0); - } - -#ifdef OS5 - ioctl(SlaveFD, I_PUSH, "ptem"); - ioctl(SlaveFD, I_PUSH, "ldterm"); -#endif /* OS5 */ - - /* Set up as basic display terminal: canonical erase, - kill processing, echo, backspace to erase, echo ctrl - chars as ^x, kill line by backspacing */ - tcgetattr(SlaveFD, &tio); - tio.c_lflag |= ICANON | ECHO | ECHOE | ECHOCTL | ECHOKE; - tcsetattr(SlaveFD, TCSANOW, &tio); - - (void)dup2(SlaveFD, 0); - (void)dup2(SlaveFD, 1); - (void)dup2(SlaveFD, 2); - (void)close(SlaveFD); - - /* set the LDESHELL variable so the underlying .cshrc can see it and - configure the shell appropriately, though this may not be so important any more */ - setenv("LDESHELL", "YES", 1); - - if (termtype[0] != 0) { /* set the TERM environment var */ - setenv("TERM", termtype, 1); - } - /* Start up csh */ - argvec[0] = "csh"; - if (shellarg[0] != 0) { /* setup to run command */ - argvec[1] = "-c"; /* read commands from next arg */ - argvec[2] = shellarg; - argvec[3] = (char *)0; - } else - argvec[1] = (char *)0; - - execv("/bin/csh", argvec); - - /* Should never get here */ - perror("execv"); - exit(0); - } else { /* not the forked process. */ + if (PID != 0) { if (shellarg != shcom) free(shellarg); + return (PID); } - /* Set the process group so all the kids get the bullet too - if (setpgrp(PID, PID) != 0) - perror("setpgrp"); */ + if (0 > setsid()) /* create us a new session for tty purposes */ + perror("setsid"); - return (PID); + /* Open the slave side */ + SlaveFD = open(PtySlave, O_RDWR); + if (SlaveFD == -1) { + perror("Slave Open"); + perror(PtySlave); + exit(0); + } + +#ifdef OS5 + ioctl(SlaveFD, I_PUSH, "ptem"); + ioctl(SlaveFD, I_PUSH, "ldterm"); +#endif /* OS5 */ + + /* Set up as basic display terminal: canonical erase, + kill processing, echo, backspace to erase, echo ctrl + chars as ^x, kill line by backspacing */ + tcgetattr(SlaveFD, &tio); + tio.c_lflag |= ICANON | ECHO | ECHOE | ECHOCTL | ECHOKE; + tcsetattr(SlaveFD, TCSANOW, &tio); + + (void)dup2(SlaveFD, 0); + (void)dup2(SlaveFD, 1); + (void)dup2(SlaveFD, 2); + (void)close(SlaveFD); + + /* set the LDESHELL variable so the underlying shell initialization can see it and + configure the shell appropriately, though this may not be so important any more */ + setenv("LDESHELL", "YES", 1); + + if (termtype[0] != 0) { /* set the TERM environment var */ + setenv("TERM", termtype, 1); + } + /* Start up shell -- use SHELL environment variable as long as it's in /etc/shells */ + shell = getenv("SHELL"); + for (userShell = getusershell(); userShell != NULL && strcmp(shell, userShell) != 0; userShell = getusershell()); + if (userShell == NULL) { + perror("$(SHELL) not found in /etc/shells"); + exit(0); + } + + /* argvec entries initialized to NULL */ + argvec[0] = strrchr(userShell, '/') + 1; + if (shellarg[0] != 0) { /* setup to run command */ + argvec[1] = "-c"; /* read commands from next arg */ + argvec[2] = shellarg; + } + + execv(userShell, argvec); + + /* Should never get here */ + perror("execv"); + exit(0); } /* fork_Unix is the secondary process spawned right after LISP is