aboutsummaryrefslogtreecommitdiff
path: root/riemann.fmi.uni-sofia.bg/programs/xinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'riemann.fmi.uni-sofia.bg/programs/xinit.c')
-rw-r--r--riemann.fmi.uni-sofia.bg/programs/xinit.c370
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