/*
* open.c open a vt to run a new command (or shell).
*
* Copyright (c) 1994 by Jon Tombs <jon@gtex02.us.es>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include "open.h"
const char *OPENversion = "open: 1.4 (c) Jon Tombs 1994";
#ifndef VTNAME
#error vt device name must be defined in open.h
#endif
int
main(int argc, char *argv[])
{
int fd = 0;
int opt, pid;
#if defined(__FreeBSD__)
int vt_active;
#else
struct vt_stat vt;
#define vt_active vt.v_active
#endif
struct passwd *pwnam=NULL;
int vtno = -1;
char show = FALSE;
char login = FALSE;
char verbose = FALSE;
char do_wait = FALSE;
char as_user= FALSE;
char vtname[sizeof VTNAME + 2]; /* allow 999 possible VTs */
char *cmd = NULL, *def_cmd = NULL;
/*
* I don't like using getopt for this, but otherwise this gets messy.
* POSIX/Gnu getopt forces the use of -- to separate child/program
* options. RTFM.
*/
while ((opt = getopt(argc, argv, "c:lsvuw")) != -1) {
switch (opt) {
case 'c':
vtno = (int) atol(optarg);
#if defined(__FreeBSD__)
if (vtno <= 0 || vtno > 99) {
#else
if (vtno < 0 || vtno > 99) {
#endif
fprintf(stderr, "open: %s illegal vt number\n", optarg);
return 5;
}
/* close security holes - until we can do this safely */
(void) setuid(getuid());
break;
case 'l':
login = TRUE;
break;
case 's':
show = TRUE;
break;
case 'v':
verbose = TRUE;
break;
case 'w':
do_wait = TRUE;
break;
case 'u':
/* we'll let 'em get away with the meaningless -ul combo */
if(getuid()) {
fprintf(stderr,"%s: only root can use the -u flag.\n",argv[0]);
exit(1);
}
as_user = TRUE;
break;
default:
usage(1);
}
}
if (vtno == -1) {
if ((fd = open("/dev/console",O_WRONLY,0)) < 0) {
perror("open: Failed to open /dev/console\n");
return(2);
}
if ((ioctl(fd, VT_OPENQRY, &vtno) < 0) || (vtno == -1)) {
perror("open: Cannot find a free VT\n");
close(fd);
return(3);
}
#if defined(__FreeBSD__)
if (ioctl(fd, VT_GETACTIVE, &vt_active) < 0) {
perror("open: can't get active VT\n");
#else
if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
perror("open: can't get VTstate\n");
#endif
close(fd);
return(4);
}
}
#if defined(__FreeBSD__)
sprintf(vtname, VTNAME, vtno - 1);
#else
sprintf(vtname, VTNAME, vtno);
#endif
/* support for Spawn_Console; running from init
added by Joshua Spoerri, Thu Jul 18 21:13:16 EDT 1996 */
if (as_user) {
DIR *dp;
struct dirent *dentp;
struct stat buf;
dev_t console_dev;
ino_t console_ino;
uid_t console_uid;
char filename[sizeof VTNAME + 2];
if (!(dp=opendir("/proc"))) {
perror("/proc");
exit(1);
}
/* get the current tty */
#if defined(__FreeBSD__)
sprintf(filename,VTNAME,vt_active - 1);
#else
sprintf(filename,VTNAME,vt_active);
#endif
if (stat(filename,&buf)) {
perror(filename);
exit(1);
}
console_dev=buf.st_dev;
console_ino=buf.st_ino;
console_uid=buf.st_uid;
/* get the owner of current tty */
if (!(pwnam=getpwuid(console_uid))) {
perror("can't getpwuid");
exit(1);
}
/* check to make sure that user has process on that tty */
while ((dentp=readdir(dp))) {
sprintf(filename,"/proc/%s/fd/0",dentp->d_name);
if (stat(filename,&buf)) /*stat will fail if prcs lacks stdin*/
continue;
if(buf.st_dev == console_dev && buf.st_ino == console_ino
&& buf.st_uid == console_uid)
break;
}
if(!(buf.st_dev == console_dev && buf.st_ino == console_ino
&& buf.st_uid == console_uid)) {
fprintf(stderr,"couldn't find owner of current tty!\n");
exit(1);
}
} else {
if (!geteuid()) {
uid_t uid = getuid();
chown(vtname, uid, getgid());
setuid(uid);
}
}
if (verbose)
fprintf(stderr, "open: using VT %s\n", vtname);
if(!as_user) {
if (!(argc > optind)) {
def_cmd = getenv("SHELL");
if (def_cmd == NULL)
usage(0);
cmd = malloc(strlen(def_cmd + 2));
} else {
cmd = malloc(strlen(argv[optind] + 2));
}
if (login)
strcpy(cmd, "-");
else
cmd[0] = '\0';
if (def_cmd)
strcat(cmd, def_cmd);
else
strcat(cmd, argv[optind]);
if (login)
argv[optind] = cmd++;
}
if((pid=fork()) == 0) {
/* leave current vt */
#ifdef ESIX_5_3_2_D
if (setpgrp() < 0) {
#else
if (setsid() < 0) {
#endif
fprintf(stderr, "open: Unable to set new session (%s)\n",
strerror(errno));
}
close(0);
close(1);
close(2);
close(fd);
/* and grab new one */
if ((fd = open(vtname, O_RDWR)) == -1) { /* Shouldn't happen */
_exit (4); /* silently die */
}
dup(fd); dup(fd);
if (ioctl(fd, TIOCSCTTY, NULL) < 0)
_exit(4);
if (show) {
/*
* Can't tell anyone if any of these fail, so throw away
* the return values
*/
if (ioctl(fd, VT_ACTIVATE, vtno) < 0)
_exit(4);
/* wait to be really sure we have switched */
if (ioctl(fd, VT_WAITACTIVE, vtno) < 0)
_exit(4);
}
if(as_user)
execlp("login","login","-f",pwnam->pw_name,NULL);
else if (def_cmd)
execlp(cmd, def_cmd, NULL);
else
execvp(cmd, &argv[optind]);
}
if ( pid < 0 ) {
perror("open: fork() error");
return(6);
}
if ( do_wait ) {
wait(NULL);
if (show) { /* Switch back... */
if (ioctl(fd, VT_ACTIVATE, vt_active) < 0)
_exit(4);
/* wait to be really sure we have switched */
if (ioctl(fd, VT_WAITACTIVE, vt_active) < 0)
_exit(4);
}
}
close (fd);
return 0;
}
void usage(int stat)
{
fprintf(stderr,
"Usage: open [-c vtnumer ][-l] [-u] [-s] [-v] -- command_line\n");
exit (stat);
}
syntax highlighted by Code2HTML, v. 0.9.1