/* * util.c * * Copyright (c) 1990, 1991, John W. Eaton. * * You may distribute under the terms of the GNU General Public * License as specified in the file COPYING that comes with the man * distribution. * * John W. Eaton * jwe@che.utexas.edu * Department of Chemical Engineering * The University of Texas at Austin * Austin, Texas 78712 */ #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "gripedefs.h" int debug = 0; char * progname = 0; /* * Extract last element of a name like /foo/bar/baz. */ char * mkprogname (char *s) { char *t; t = strrchr (s, '/'); if (t == (char *)NULL) t = s; else t++; return my_strdup (t); } /* * Is file a nonempty and newer than file b? * * case: * * a newer than b returns 1 * a older than b returns 0 * stat on a fails or a empty returns -1 * stat on b fails or b empty returns -2 * both fail or empty returns -3 */ int is_newer (char *fa, char *fb) { struct stat fa_sb; struct stat fb_sb; register int fa_stat; register int fb_stat; register int status = 0; fa_stat = stat (fa, &fa_sb); if (fa_stat != 0 || fa_sb.st_size == 0) status = 1; fb_stat = stat (fb, &fb_sb); if (fb_stat != 0 || fb_sb.st_size == 0) status |= 2; if (status != 0) return -status; return (fa_sb.st_mtime > fb_sb.st_mtime); } int ruid, rgid, euid, egid, suid; void get_permissions (void) { ruid = getuid(); euid = geteuid(); rgid = getgid(); egid = getegid(); suid = (ruid != euid || rgid != egid); } void no_privileges (void) { if (suid) { #ifndef __CYGWIN32__ setreuid(ruid, ruid); setregid(rgid, rgid); #endif suid = 0; } } /* * Unfortunately, Linux libc system() ignores SIGINT and SIGQUIT * The consequence is that "man -K" cannot be interrupted. * Here a private copy that doesn't fiddle with signals. * (But see below.) */ static int system0 (char *command) { int pid, pid2, status; pid = fork(); if (pid == -1) { perror(progname); fatal (CANNOT_FORK, command); } if (pid == 0) { char *argv[4]; argv[0] = "sh"; argv[1] = "-c"; argv[2] = command; argv[3] = 0; execv("/bin/sh", argv); /* was: execve(*,*,environ); */ exit(127); } do { pid2 = wait(&status); if (pid2 == -1) return -1; } while(pid2 != pid); return status; } /* * What to do upon an interrupt? Experience shows that * if we exit immediately, sh notices that its child has * died and will try to fiddle with the tty. * Simultaneously, also less will fiddle with the tty, * resetting the mode before exiting. * This leads to undesirable races. So, we catch SIGINT here * and exit after the child has exited. */ static int interrupted = 0; static void catch_int(int a) { interrupted = 1; } static int system1 (char *command) { void (*prev_handler)(int) = signal (SIGINT,catch_int); int ret = system0(command); if (interrupted) exit(1); signal(SIGINT,prev_handler); return ret; } static int my_system (char *command) { int pid, pid2, status, stat; if (!suid) return system1 (command); #ifdef _POSIX_SAVED_IDS /* we need not fork */ setuid(ruid); setgid(rgid); status = system1(command); setuid(euid); setgid(egid); return (WIFEXITED(status) ? WEXITSTATUS(status) : 127); #endif fflush(stdout); fflush(stderr); pid = fork(); if (pid == -1) { perror(progname); fatal (CANNOT_FORK, command); } if (pid == 0) { setuid(ruid); setgid(rgid); status = system1 (command); exit(WIFEXITED(status) ? WEXITSTATUS(status) : 127); } pid2 = wait (&stat); if (pid2 == -1) { perror(progname); fatal (WAIT_FAILED, command); /* interrupted? */ } if (pid2 != pid) fatal (GOT_WRONG_PID); if (WIFEXITED(stat) && WEXITSTATUS(stat) != 127) return WEXITSTATUS(stat); fatal (CHILD_TERMINATED_ABNORMALLY, command); return -1; /* not reached */ } FILE * my_popen(const char *command, const char *type) { FILE *r; if (!suid) return popen(command, type); #ifdef _POSIX_SAVED_IDS setuid(ruid); setgid(rgid); r = popen(command, type); setuid(euid); setgid(egid); return r; #endif no_privileges(); return popen(command, type); } /* * Attempt a system () call. */ int do_system_command (char *command, int silent) { int status = 0; /* * If we're debugging, don't really execute the command -- you never * know what might be in that mangled string :-O. */ if (debug == 1) gripe (NO_EXEC, command); else status = my_system (command); if (status && !silent) gripe (SYSTEM_FAILED, command, status); return status; } char * my_malloc (int n) { char *s = (char*) malloc(n); if (!s) fatal (OUT_OF_MEMORY, n); return s; } char * my_strdup (char *s) { char *t = my_malloc(strlen(s) + 1); strcpy(t, s); return t; } /******************* modifyed by Wang XinKai ,1999.3.19 *********/ char *getmsg(int n) { static char buffer[100]; buffer[0] = 0; //sprintf(buffer,"error, errorcode = %d\n",n); return buffer; } void gripe (int n, ...) { va_list p; va_start(p, n); vfprintf (stderr, getmsg(n), p); va_end(p); fflush (stderr); } void fatal (int n, ...) { va_list p; fprintf (stderr, "%s: ", progname); va_start(p, n); vfprintf (stderr, getmsg(n), p); va_end(p); exit (1); } /************************** modify end ************************/