#include <stdio.h>
#include <X11/Xos.h>
#include <stdlib.h>
#include "misc.h"
#include "globals.h"
#include <signal.h>
#ifdef MEMBUG
#include <util/memleak/memleak.h>
#endif
#include <sys/wait.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#ifndef X_NOT_POSIX
#ifdef _POSIX_SOURCE
#include <limits.h>
#else
#define _POSIX_SOURCE
#include <limits.h>
#undef _POSIX_SOURCE
#endif
#endif
#ifndef PATH_MAX
#include <sys/param.h>
#ifndef PATH_MAX
#ifdef MAXPATHLEN
#define PATH_MAX MAXPATHLEN
#else
#define PATH_MAX 1024
#endif
#endif
#endif
#if defined(X_NOT_POSIX) && (defined(SYSV) || defined(SVR4))
#define SIGNALS_RESET_WHEN_CAUGHT
#endif
#include <stdlib.h>
extern char *configfilename;
static Bool dropPriv = FALSE;
#ifdef DEFAULT_DAEMON
static Bool becomeDaemon = TRUE;
#else
static Bool becomeDaemon = FALSE;
#endif
static const char *userId = NULL;
char *progname;
Bool CloneSelf;
Bool portFromCmdline = FALSE;
OldListenRec *OldListen = NULL;
int OldListenCount = 0;
#ifdef STDERR_FILENO
# define WRITES write(STDERR_FILENO, s, strlen(s))
#else
# define WRITES write(fileno(stderr), s, strlen(s))
#endif
static char *pidFile = XFSPIDDIR "/xfs.pid";
static int pidFd;
static FILE *pidFilePtr;
static int StorePid (void);
SIGVAL
AutoResetServer(int n)
{
int olderrno = errno;
#ifdef DEBUG
WRITES("got a reset signal\n");
#endif
dispatchException |= DE_RESET;
isItTimeToYield = TRUE;
#ifdef SIGNALS_RESET_WHEN_CAUGHT
signal(SIGHUP, AutoResetServer);
#endif
errno = olderrno;
}
SIGVAL
GiveUp(int n)
{
int olderrno = errno;
#ifdef DEBUG
WRITES("got a TERM signal\n");
#endif
dispatchException |= DE_TERMINATE;
isItTimeToYield = TRUE;
errno = olderrno;
}
SIGVAL
ServerReconfig(int n)
{
int olderrno = errno;
#ifdef DEBUG
WRITES("got a re-config signal\n");
#endif
dispatchException |= DE_RECONFIG;
isItTimeToYield = TRUE;
#ifdef SIGNALS_RESET_WHEN_CAUGHT
signal(SIGUSR1, ServerReconfig);
#endif
errno = olderrno;
}
SIGVAL
ServerCacheFlush(int n)
{
int olderrno = errno;
#ifdef DEBUG
WRITES("got a flush signal\n");
#endif
dispatchException |= DE_FLUSH;
isItTimeToYield = TRUE;
#ifdef SIGNALS_RESET_WHEN_CAUGHT
signal(SIGUSR2, ServerCacheFlush);
#endif
errno = olderrno;
}
SIGVAL
CleanupChild(int n)
{
int olderrno = errno;
#ifdef DEBUG
WRITES("got a child signal\n");
#endif
wait(NULL);
#ifdef SIGNALS_RESET_WHEN_CAUGHT
signal(SIGCHLD, CleanupChild);
#endif
errno = olderrno;
}
long
GetTimeInMillis(void)
{
struct timeval tp;
X_GETTIMEOFDAY(&tp);
return ((tp.tv_sec * 1000) + (tp.tv_usec / 1000));
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [-config config_file] [-port tcp_port] [-droppriv] [-daemon] [-nodaemon] [-user user_name] [-ls listen_socket]\n",
progname);
exit(1);
}
void
OsInitAllocator (void)
{
#ifdef MEMBUG
CheckMemory ();
#endif
}
void
ProcessLSoption (char *str)
{
char *ptr = str;
char *slash;
char number[20];
int count = 0;
int len, i;
while (*ptr != '\0')
{
if (*ptr == ',')
count++;
ptr++;
}
OldListenCount = count + 1;
OldListen = (OldListenRec *) malloc (
OldListenCount * sizeof (OldListenRec));
if (OldListen == NULL) {
fprintf(stderr, "ProcessLSoption: malloc error\n");
exit(1);
}
ptr = str;
for (i = 0; i < OldListenCount; i++)
{
slash = (char *) strchr (ptr, '/');
if (slash == NULL) {
usage();
}
len = slash - ptr;
strncpy (number, ptr, len);
number[len] = '\0';
OldListen[i].trans_id = atoi (number);
ptr = slash + 1;
slash = (char *) strchr (ptr, '/');
if (slash == NULL) {
usage();
}
len = slash - ptr;
strncpy (number, ptr, len);
number[len] = '\0';
OldListen[i].fd = atoi (number);
ptr = slash + 1;
if (i == OldListenCount - 1)
OldListen[i].portnum = atoi (ptr);
else
{
char *comma = (char *) strchr (ptr, ',');
if (comma == NULL) {
usage();
}
len = comma - ptr;
strncpy (number, ptr, len);
number[len] = '\0';
OldListen[i].portnum = atoi (number);
ptr = comma + 1;
}
}
}
void
ProcessCmdLine(int argc, char **argv)
{
int i;
progname = argv[0];
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-port")) {
if (argv[i + 1]) {
ListenPort = atoi(argv[++i]);
portFromCmdline = TRUE;
} else
usage();
} else if (!strcmp(argv[i], "-ls")) {
if (argv[i + 1])
ProcessLSoption (argv[++i]);
else
usage();
} else if (!strcmp(argv[i], "-droppriv")) {
dropPriv = TRUE;
} else if (!strcmp(argv[i], "-daemon")) {
becomeDaemon = TRUE;
} else if (!strcmp(argv[i], "-nodaemon")) {
becomeDaemon = FALSE;
} else if (!strcmp(argv[i], "-user")) {
if (argv[i + 1])
userId = argv[++i];
else
usage();
} else if (!strcmp(argv[i], "-cf") || !strcmp(argv[i], "-config")) {
if (argv[i + 1])
configfilename = argv[++i];
else
usage();
}
#ifdef MEMBUG
else if ( strcmp( argv[i], "-alloc") == 0)
{
extern unsigned long MemoryFail;
if(++i < argc)
MemoryFail = atoi(argv[i]);
else
usage ();
}
#endif
else
usage();
}
}
#ifndef SPECIAL_MALLOC
unsigned long Must_have_memory;
#ifdef MEMBUG
#define MEM_FAIL_SCALE 100000
unsigned long MemoryFail;
#endif
pointer
FSalloc (unsigned long amount)
{
register pointer ptr;
if ((long)amount < 0)
return 0;
if (amount == 0)
amount++;
amount = (amount + 3) & ~3;
#ifdef MEMBUG
if (!Must_have_memory && MemoryFail &&
((random() % MEM_FAIL_SCALE) < MemoryFail))
return 0;
if (ptr = (pointer)fmalloc(amount))
return ptr;
#else
if ((ptr = (pointer)malloc(amount)) != 0)
return ptr;
#endif
if (Must_have_memory)
FatalError("out of memory\n");
return 0;
}
pointer
FScalloc (unsigned long amount)
{
pointer ret;
ret = FSalloc (amount);
if (ret)
bzero ((char *) ret, (int) amount);
return ret;
}
pointer
FSrealloc (pointer ptr, unsigned long amount)
{
#ifdef MEMBUG
if (!Must_have_memory && MemoryFail &&
((random() % MEM_FAIL_SCALE) < MemoryFail))
return 0;
ptr = (pointer)frealloc((char *) ptr, amount);
if (ptr)
return ptr;
#else
if ((long)amount <= 0)
{
if (ptr && !amount)
free(ptr);
return 0;
}
amount = (amount + 3) & ~3;
if (ptr)
ptr = (pointer)realloc((char *)ptr, amount);
else
ptr = (pointer)malloc(amount);
if (ptr)
return ptr;
#endif
if (Must_have_memory)
FatalError("out of memory\n");
return 0;
}
void
FSfree(pointer ptr)
{
#ifdef MEMBUG
if (ptr)
ffree((char *)ptr);
#else
if (ptr)
free((char *)ptr);
#endif
}
#endif
void
SetUserId(void)
{
if ((geteuid() == 0) && (dropPriv || userId)) {
const char *user;
struct passwd *pwent;
if (!userId)
user = "xfs";
else
user = userId;
pwent = getpwnam(user);
if (pwent) {
if (setgid(pwent->pw_gid)) {
FatalError("fatal: couldn't set groupid to xfs user's group\n");
}
#ifndef QNX4
#ifndef __CYGWIN__
if (setgroups(0, NULL)) {
FatalError("fatal: couldn't drop supplementary groups\n");
}
#endif
if (initgroups(user, pwent->pw_gid)) {
FatalError("fatal: couldn't init supplementary groups\n");
}
#endif
if (setuid(pwent->pw_uid)) {
FatalError("fatal: couldn't set userid to %s user\n", user);
}
}
} else if (dropPriv || userId) {
FatalError("fatal: -droppriv or -user flag specified, but xfs not run as root\n");
}
}
void
SetDaemonState(void)
{
int oldpid;
if (becomeDaemon) {
BecomeOrphan();
BecomeDaemon();
if ((oldpid = StorePid ())) {
if (oldpid == -1)
ErrorF ("error opening process-id file %s\n", pidFile);
else
ErrorF ("process-id file %s indicates another xfs is "
"running (pid %d); exiting\n", pidFile, oldpid);
exit(1);
}
}
}
static int
StorePid (void)
{
int oldpid;
if (pidFile[0] != '\0') {
pidFd = open (pidFile, O_RDWR);
if (pidFd == -1 && errno == ENOENT)
pidFd = open (pidFile, O_RDWR|O_CREAT, 0666);
if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
{
ErrorF ("cannot open process-id file %s: %s\n", pidFile,
strerror (errno));
return -1;
}
if (fscanf (pidFilePtr, "%d\n", &oldpid) != 1)
oldpid = -1;
if (fseek (pidFilePtr, 0L, SEEK_SET) == -1)
{
ErrorF ("cannot seek process-id file %s: %s\n", pidFile,
strerror (errno));
return -1;
}
if (fprintf (pidFilePtr, "%5ld\n", (long) getpid ()) != 6)
{
ErrorF ("cannot write to process-id file %s: %s\n", pidFile,
strerror (errno));
return -1;
}
(void) fflush (pidFilePtr);
(void) fclose (pidFilePtr);
}
return 0;
}