Run our TTYs with our own tty runner
[grml-scripts.git] / compile / grml-runtty.c
1 /*
2  * Copyright 2011 Christian Hofstaedtler. Licensed under GPL Version 2.
3  *
4  * Most of this is copied from fgetty, which is
5  *   Copyright Felix von Leitner, licensed under GPL Version 2.
6 */
7
8 #define _GNU_SOURCE
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #include <pwd.h>
15 #include <grp.h>
16 #include <sys/param.h>
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <syslog.h>
22 #include <signal.h>
23
24 char* tty;
25 char* prog;
26 char* user;
27
28 void error(const char* message, int exitcode) {
29   write(2, "E: ", 3);
30   write(2, message, strlen(message));
31   write(2, "\n", 1);
32   syslog(LOG_CRIT, "%s", message);
33   sleep(15);
34   closelog();
35   exit(exitcode);
36 }
37
38 void sigquit_handler(int signum) {
39   error("SIGQUIT received\n",23);
40 }
41
42 void setup_tty() {
43   struct sigaction sa;
44   int fd;
45   if (chown(tty,0,0) || chmod(tty,0600))
46     error("could not chown/chmod tty device\n",1);
47   sa.sa_handler=SIG_IGN;
48   sa.sa_flags=0;
49   sigemptyset(&sa.sa_mask);
50   sigaction(SIGHUP,&sa,NULL);
51   sa.sa_handler=sigquit_handler;
52   sigaction(SIGQUIT,&sa,NULL);
53
54   setsid();
55   if ((fd=open(tty, O_RDWR, 0))<0)
56     error("open tty failed", errno);
57   if (ioctl (fd, TIOCSCTTY, (void *)1) == -1)
58     error("ioctl TIOCSCTTY failed", errno);
59   if (!isatty(fd))
60     error("\"not a typewriter\" (isatty failed)", errno);
61   if (vhangup())        /* linux specific */
62     error("vhangup failed", errno);
63   close(2); close(1); close(0); close(fd);
64   if (open(tty, O_RDWR,0) != 0)
65     error("could not (re)open tty", errno);
66   if (dup(0) != 1 || dup(0) != 2)
67     error("could not dup stdout and stderr", errno);
68
69   sa.sa_handler=SIG_DFL;
70   sa.sa_flags=0;
71   sigemptyset(&sa.sa_mask);
72   sigaction(SIGHUP,&sa,NULL);
73 }
74
75 void setenvvar(char* envvar, char* value) {
76   /* buf ends up directly in env. can't use alloca */
77   char* buf = malloc(strlen(envvar) + strlen(value) + 2);
78   strcpy(buf, envvar);
79   strcat(buf, "=");
80   strcat(buf, value);
81   putenv(buf);
82 }
83
84 int main(int argc, char* argv[]) {
85   struct passwd* pw;
86
87   tty = argv[1];
88   prog = argv[2];
89   user = argv[3];
90
91   openlog("startprog", LOG_CONS | LOG_PID, LOG_AUTHPRIV);
92
93   if (tty == NULL || prog == NULL || user == NULL)
94     error("Usage: startprog /dev/ttyX /bin/bash user", 1);
95
96   pw = getpwnam(user);
97   if (!pw)
98     error("User does not exist", 1);
99
100   clearenv();
101   putenv("TERM=linux");
102   setenvvar("TTY", tty);
103   setenvvar("USER", pw->pw_name);
104   setenvvar("LOGNAME", pw->pw_name);
105   setenvvar("SHELL", pw->pw_shell);
106   setenvvar("HOME", pw->pw_dir);
107   {
108     char uidbuf[15];
109     sprintf(uidbuf, "%i", pw->pw_uid);
110     setenvvar("UID", uidbuf);
111   }
112
113 #ifndef DEBUG
114   setup_tty();
115 #endif
116   chown(tty, pw->pw_uid, pw->pw_gid);
117
118   if (initgroups(pw->pw_name, pw->pw_gid) == -1)
119     error("initgroups failed", 1);
120   if (setgid(pw->pw_gid) == -1)
121     error("setgid failed", 1);
122   if (setuid(pw->pw_uid) == -1)
123     error("setuid failed", 1);
124
125   {
126     char *Argv[] = {prog, 0};
127     execve(prog, Argv, environ);
128   }
129
130   /* should never come here */
131   error("Program startup failed", 99);
132 }