diff options
Diffstat (limited to 'riemann.fmi.uni-sofia.bg/programs/xinit.c')
| -rw-r--r-- | riemann.fmi.uni-sofia.bg/programs/xinit.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/riemann.fmi.uni-sofia.bg/programs/xinit.c b/riemann.fmi.uni-sofia.bg/programs/xinit.c new file mode 100644 index 0000000..369625b --- /dev/null +++ b/riemann.fmi.uni-sofia.bg/programs/xinit.c @@ -0,0 +1,370 @@ +/* xinit.c + diet -Os gcc -nostdinc -O2 -s -o xinit xinit.c -Wall -W + diet -Os gcc -nostdinc -DUSE_XCLEAN -O2 -s -o xinit xinit.c -Wall -W + diet -Os gcc -nostdinc -DXwrapper -O2 -s -o xinit xinit.c -Wall -W + -DXwrapper --> try to exec first Xwrapper before X + + -DUSE_XCLEAN + If the variable XCLEAN is present, then after + finishing of the server xinit execs /bin/sh -c "$XCLEAN". + This is useful for cleaning of ~/.Xauthority + */ +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <string.h> +#ifndef __dietlibc__ +#include <time.h> +extern char **environ; +#endif + +/* A/UX setpgid incorrectly removes the controlling terminal. + Per Posix, only setsid should do that. */ +#define setpgrp setpgid +#define SIGVAL void +#define killpg(pgrp, sig) kill(-(pgrp), sig) + +char *default_server = "X"; +char *displayNum = ":0"; +char *default_client[] ={"xterm", "-geometry", "+1+1", "-n", "login", NULL}; +char *program; +int serverpid = -1; +int clientpid = -1; +volatile int gotSignal = 0; +volatile int gotAlarm = 0; + +static char processTimeout ( int timeout, char *string ); +static int startServer ( char *server[] ); +static int startClient ( char *client[] ); +static void shutDown ( void ); +static void pathexec_run(char *file,char **argv,char **envp); +static void Fatal(char *msg); +static void Error(char *s); +static void Error_n(int n); + +static SIGVAL sig_catch(int sig,void (*f)()) { + struct sigaction sa; + sa.sa_handler = f; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sig,&sa,(struct sigaction *) 0); +} +static SIGVAL sigCatch(int sig) {gotSignal = sig;} +static SIGVAL sigAlarm(int sig) {gotAlarm = sig;} +static SIGVAL sigUsr1() {} + +static void Execute(char **c) { + pathexec_run(*c,c,environ); + if (errno != ENOEXEC) return; + *--c = "/bin/sh"; + pathexec_run(*c,c,environ); +} + +static unsigned int env_len; +static char *path_save; + +int main(int argc, char *argv[]) { + int pid; + char **client, **cptr, **server, **ptr; +#ifdef USE_XCLEAN + char *xclean[] = { "/bin/sh", "-c", 0, 0 }; +#endif + + program = *argv++; + /* sh 5 \0 sh X :0 \0 = 11 */ + client = (char **) alloca((13+argc) * sizeof (char *)); + if (!client) Fatal("no memory\n"); + cptr = ++client; + + /* copy the client args. */ + if (*argv == 0 || (**argv != '/' && **argv != '.')) + for (ptr = default_client; *ptr; ) + *cptr++ = *ptr++; + while (*argv && strcmp(*argv, "--")) *cptr++ = *argv++; + *cptr++ = NULL; + if (*argv) argv++; + + /* Copy the server args. */ + server = ++cptr; + if (*argv == 0 || (**argv != '/' && **argv != '.')) + *cptr++ = default_server; + else + *cptr++ = *argv++; + + if (*argv && (argv[0][0] == ':' && (unsigned int)(argv[0][1] -'0')<10)) + displayNum = *argv; + *cptr++ = displayNum; + + do { *cptr++ = *argv; } while (*argv++); + + /* Start the server and client. */ + sig_catch(SIGCHLD, SIG_DFL); /* Insurance */ + + /* Let those signal interrupt the wait() call in the main loop */ + sig_catch(SIGQUIT, sigCatch); + sig_catch(SIGINT, sigCatch); + sig_catch(SIGHUP, sigCatch); + sig_catch(SIGPIPE, sigCatch); + + sig_catch(SIGUSR1, sigUsr1); + + /* count number of environment variables */ + for (ptr = environ; *ptr; ptr++) { + char *x = *ptr; + if (!memcmp("PATH=", x, 5)) path_save = x + 5; + +#ifdef USE_XCLEAN + if (!memcmp("XCLEAN=", x, 7)) { + xclean[2] = x + 7; + x = *environ++; + } +#endif + } + env_len = ptr - environ; + + if (startServer(server) > 0 && startClient(client) > 0) { + pid = -1; + while (pid != clientpid && pid != serverpid + && gotSignal == 0 ) pid = wait(NULL); + } + sig_catch(SIGQUIT, SIG_IGN); + sig_catch(SIGINT, SIG_IGN); + sig_catch(SIGHUP, SIG_IGN); + sig_catch(SIGPIPE, SIG_IGN); + + shutDown(); + if (gotSignal != 0) { + Error(program); Error(": unexpected signal: "); + Error_n(gotSignal); Error("\n"); + _exit(1); + } + if (serverpid < 0 ) Fatal("Server error.\n"); + if (clientpid < 0 ) Fatal("Client error.\n"); +#ifdef USE_XCLEAN + if (xclean[2]) execve(xclean[0], xclean, environ); +#endif + _exit(0); +} + +/* return TRUE if we timeout waiting for pid to exit, FALSE otherwise. */ +static char processTimeout(int timeout, char *string) { + int i = 0, pidfound = -1; + time_t deadline = time(0) + timeout; + for (;;) { + if ((pidfound = waitpid(serverpid, 0, WNOHANG)) == serverpid) + break; + if (i == 0) { + Error("\nwaiting for "); Error(string); + } else + Error("."); + + sleep (1); + if (++i > 1024 || time(0) > deadline) break; + } + if (i>0) Error("\n"); /* tidy up after message */ + return( serverpid != pidfound ); +} + +static int startServer(char *server[]) { + sigset_t mask, old; + + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_BLOCK, &mask, &old); + + switch((serverpid=fork())) { + case 0: + sigprocmask(SIG_UNBLOCK, &mask, 0); + + /* don't hang on read/write to control tty */ + sig_catch(SIGTTIN, SIG_IGN); + sig_catch(SIGTTOU, SIG_IGN); + + /* + * ignore SIGUSR1 in child. The server + * will notice this and send SIGUSR1 back + * at xinit when ready to accept connections + */ + (void) sig_catch(SIGUSR1, SIG_IGN); + /* + * prevent server from getting sighup from vhangup() + * if client is xterm -L + */ + setpgrp(0,getpid()); + +#ifdef Xwrapper + if (!strcmp(server[0],default_server)) { + server[0] = "Xwrapper"; + Execute(server); + server[0] = default_server; + } +#endif + Execute (server); + _exit(1); + break; + case -1: + break; + default: + /* don't nice server */ + setpriority( PRIO_PROCESS, serverpid, -1 ); + /* kludge to avoid race with TCP, giving server time to + set his socket options before we try to open it, + either use the 15 second timeout, or await SIGUSR1. + + If your machine is substantially slower than 15 seconds, + you can easily adjust this value. */ + sig_catch(SIGALRM, sigAlarm); + alarm (15); + sigsuspend(&old); + alarm (0); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + if (gotAlarm) {Error("unable to connect to X server\n"); + shutDown(); serverpid=-1; } + break; + } + return(serverpid); +} + +static int startClient(char *client[]) { + if ((clientpid = fork()) == 0) { + char **newenviron; + char **newPtr, **oldPtr, *displaybuf; + + newenviron = (char **) alloca ((env_len + 2) * sizeof(char *)); + if (!newenviron) Fatal("no memory\n"); + displaybuf = (char *) alloca(9 + strlen(displayNum)); + if (!displaybuf) Fatal("no memory\n"); + + /* put DISPLAY=displayname as first element */ + strcpy (displaybuf, "DISPLAY="); + strcpy (displaybuf + 8, displayNum); + newPtr = newenviron; + *newPtr++ = displaybuf; + + /* copy pointers to other variables */ + for (oldPtr = environ; ; oldPtr++) { + *newPtr = *oldPtr; + if (*oldPtr == 0) break; + if (memcmp (*newPtr, "DISPLAY=", 8)) + newPtr++; + } + environ = newenviron; + + setuid(getuid()); + setpgrp(0, getpid()); + + Execute (client); + _exit(1); + } + return (clientpid); +} + +static void shutDown(void) { + if (clientpid > 0) { + /* HUP all local clients to allow them to clean up */ + if ((killpg(clientpid, SIGHUP) != 0) && (errno != ESRCH)) { + Error("can't send HUP to process group "); + Error_n(clientpid); Error("\n"); + } + } + + if (serverpid < 0) return; + if (killpg(serverpid, SIGTERM) < 0) { + if (errno == EPERM) Fatal("Can't kill X server\n"); + if (errno == ESRCH) return; + } + if (! processTimeout(10, "X server to shut down")) { + Error("\n"); + return; + } + + Error("X server slow to shut down, sending KILL signal.\n"); + if (killpg(serverpid, SIGKILL) < 0) { + if (errno == ESRCH) + return; + } + if (processTimeout(3, "server to die")) Fatal("Can't kill X server\n"); + Error("\n"); + return; +} + +static void Error(char *s) {write(2,s,strlen(s));} +static void Fatal(char *msg) + {Error(program); Error(": "); Error(msg); _exit(1);} + +static void Error_n(int k) { + char buf[24], *last=buf+24, *p = last; + unsigned int u; + if (k<0) u=-k; + else u=k; + do { *--p = '0' + (u % 10); u /= 10; } while(u); + if (k<0) *--p = '-'; + write(2,p,last-p); +} + +static void pathexec_run(char *file,char **argv,char **envp) { + char *tmp,*next, *path; + int savederrno=0; + + if (strchr((char *)file,'/')) { execve(file,argv,envp); return; } + + path = (path_save) ? path_save : "/bin:/usr/bin"; + tmp = (char *)alloca(4+strlen(path) + strlen(file)); + if (!tmp) {errno=ENOMEM; return;} + + for (;;) { + size_t len = 1; + next = strchr(path,':'); + if (!next) next=path + strlen(path); + + if (path[0] == 0 || path[0] == ':') tmp[0] = '.'; + else { len = next-path; memcpy(tmp,path,len); } + tmp[len++] = '/'; + strcpy(tmp+len,file); + + execve(tmp,argv,envp); + if (errno != ENOENT) { + savederrno = errno; + if ((errno != EACCES) && (errno != ENOEXEC) && (errno != ENOTDIR)) return; + } + + if (*next==0) { + if (savederrno) errno = savederrno; + return; + } + path=next+1; + } +} + + +#if 0 +--- startx.original 2009-08-18 21:27:17.000000000 +0300 ++++ startx 2009-08-18 22:07:37.000000000 +0300 +@@ -175,13 +175,18 @@ + fi + + ++XCLEAN='' ++if [ x"$enable_xauth" = x1 ] ; then ++ if [ x"$removelist" != x ]; then ++ XCLEAN="xauth remove $removelist;" ++ fi ++ if [ x"$xserverauthfile" != x ]; then ++ XCLEAN="$XCLEAN""rm -f $xserverauthfile" ++ fi ++fi + +- +- +- +- +- +-xinit $client $clientargs -- $server $display $serverargs ++[ "$XCLEAN" != "" ] && export XCLEAN ++exec xinit $client $clientargs -- $server $display $serverargs + + + if [ x"$enable_xauth" = x1 ] ; then +#endif |
