/*
* 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <jerror.h>
#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 ************************/