/*
 * ----------------------------------------------------------------
 * Night Light System Functions
 * ----------------------------------------------------------------
 * Copyright (C) 1997-2003 Jonas Kvinge <jonas@night-light.net>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Last modified by:
 * Jonas Kvinge (15.11.2006)
 *
 */

#define SYSCALLS_C

#define NEED_SYS_TYPES_H 1		/* Extra types */
#define NEED_SYS_PARAM_H 1		/* Some systems need this */
#define NEED_LIMITS_H 1			/* Kernel limits */
#define NEED_STDARG_H 1			/* va_list, etc */
#define NEED_ERRNO_H 1			/* errno */
#define NEED_CTYPE_H 1			/* isdigit(), etc */
#define NEED_NETINET_IN_H 1		/* in_addr, sockaddr_in, etc */
#define NEED_ARPA_INET_H 1		/* inet_ntoa(), inet_aton(), etc */
#define NEED_STDIO_H 1			/* Standard C UNIX functions */
#define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
#define NEED_TIME_H 1			/* time(), etc */
#define NEED_SYSCTL_H 0			/* sysctl(), etc */
#define NEED_SYS_STAT_H 1		/* chmod(), mkdir(), etc */
#define NEED_SYS_UIO_H 0		/* iovec, etc */
#define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
#define NEED_SYS_IOCTL_H 1		/* ioctl(), etc */
#define NEED_SYS_FILIO_H 1		/* Solaris need this for ioctl(), etc */
#define NEED_UNISTD_H 1			/* Unix standard functions */
#define NEED_STRING_H 1			/* C string functions */
#define NEED_SIGNAL_H 1			/* Signal functions */
#define NEED_SYS_SOCKET_H 1		/* Socket functions */
#define NEED_NETDB_H 0			/* Network database functions */
#define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 1 	/* Functions to retrive system passwords */

#include "includes.h"

#include "nlstrsignal.h"
#include "main.h"
#include "conf.h"

#if DCC
  #include "dcc_conn.h"
#endif

/* VARIABLES - JONAS (23.08.2001) */

const char SYSCALLS_VERSION[] = "1.3.5d";

unsigned short int ScreenMode = TRUE;
unsigned short int ScreenPrint = TRUE;
unsigned short int ScreenDTS = TRUE;
unsigned short int Run = TRUE;
unsigned short int Exit = FALSE;
unsigned short int Root = FALSE;

static pid_t PID = 0;

time_t StartTime = 0;
time_t FlushTime = 0;
time_t ExitTime = 0;

#if !WIN32

uid_t UID_Current = 0;
uid_t EUID_Current = 0;
uid_t UID_Normal = 0;
uid_t EUID_Normal = 0;

gid_t GID_Current = 0;
gid_t EGID_Current = 0;
gid_t GID_Normal = 0;
gid_t EGID_Normal = 0;

#endif

unsigned short int ExitSignals = 0;

char *TMPSTRPT = NULL;

extern unsigned long int ScreenBitmask;

extern struct PrintFile_Struct PrintFileS[];
extern unsigned short int PrintFileS_Len;

extern struct Conf_Struct ConfS;

/* SYSINIT FUNCTION - JONAS (27.02.2002) */

void sysinit(void) {

  signed long int Flags = 0;
  signed long int Result = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "System initialization.");

  PID = getpid();
  NOW = time(NULL);
  srand(NOW);
  StartTime = NOW;

#if defined(NBLOCK_SYSV)
  Flags = 1;
  Result = ioctl(STDIN_FILENO, FIONBIO, &Flags);
#else
  Flags = fcntl(STDIN_FILENO, F_GETFL);
  if (Flags <= ERROR) { Flags = 0; }
#if defined(NBLOCK_BSD)
  Flags |= O_NDELAY;
#elif defined(NBLOCK_POSIX)
  Flags |= O_NONBLOCK;
#else
  #warning "This system does not support non-blocking sockets?"
  Flags |= O_NONBLOCK;
#endif
  Result = fcntl(STDIN_FILENO, F_SETFL, Flags);
#endif

  strgetunameinfo();
  strgetplatform();
  strgetosname();
  strgetosrelease();
  strgethostname();

}

#if !WIN32
/* SYSINITID FUNCTION - JONAS (18.07.2001) */

void sysinitid(void) {

  signed long int Result = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Initializing ID.");

  UID_Current = getuid();
  EUID_Current = geteuid();

  GID_Current = getgid();
  EGID_Current = getegid();

  UID_Normal = UID_Current;
  GID_Normal = GID_Current;

  if (UID_Current == 0) {
    Root = TRUE;
    assert(ConfS.EUser != NULL);
    EUID_Normal = sysgetuidfromuser(ConfS.EUser);
    if (aerrno != AESUCCESS) {
      printf("%s: No such user.\n", ConfS.EUser);
      printf("Cannot start %s from root without a vaild EUSER.\n", PACKAGE);
      exit(ERROR);
    }
    if (EUID_Normal == 0) {
      printf("You must set EUSER to something else than root!\n");
      exit(ERROR);
    }
    EGID_Normal = sysgetgidfromgroup(ConfS.EGroup);
    if (aerrno != AESUCCESS) {
      printf("%s: No such group.\n", ConfS.EGroup);
      printf("Cannot start %s from root without a vaild EGROUP.\n", PACKAGE);
      exit(ERROR);
    }
    if (EGID_Normal == 0) {
      printf("You must set EGROUP to something else than (root/system/wheel)!\n");
      exit(ERROR);
    }
  }
  else {
    Root = FALSE;
    EUID_Normal = EUID_Current;
    EGID_Normal = EGID_Current;
  }

  if (ConfS.ChDir == TRUE) {
    Result = chdir(ConfS.ChDirPath);
    if (Result == ERROR) {
      printf("Unable to change working directory to %s (CHDIRPATH): [%d] %s\n", ConfS.ChDirPath, errno, strerror(errno));
      exit(ERROR);
    }
  }

  if (GID_Current == 0) {
    Result = setegid(EGID_Normal);
    if (Result <= ERROR) { printf("Unable to change effective group ID to %ld: [%d] %s\n", (PRINT_GID_T) EGID_Normal, errno, strerror(errno)); exit(1); }
    EGID_Current = EGID_Normal;
  }

  if (UID_Current == 0) {
    Result = seteuid(EUID_Normal);
    if (Result <= ERROR) { printf("Unable to change effective user ID to %ld: [%d] %s\n", (PRINT_UID_T) EUID_Normal, errno, strerror(errno)); exit(1); }
    EUID_Current = EUID_Normal;
  }

  assert(EUID_Current == EUID_Normal);
  assert(EGID_Current == EGID_Normal);

  assert(EUID_Current == geteuid());
  assert(EGID_Current == getegid());

  assert(EUID_Current != 0);
  assert(EGID_Current != 0);

}
#endif

#if !WIN32
/* SYSSETEUIDNORMAL FUNCTION - JONAS (01.07.2000) */

signed long int sysseteuidnormal(void) {

  signed long int Result = 0;

  if (EUID_Current == EUID_Normal) { return(SUCCESS); }

  if (EUID_Current != 0) {
    Result = seteuid(0);
    if (Result <= ERROR) { sysprint(BITMASK_ERROR, "Unable to change effective user ID to root (0): [%d] %s", errno, strerror(errno)); exit(1); }
    EUID_Current = 0;
  }

  Result = seteuid(EUID_Normal);
  if (Result <= ERROR) { sysprint(BITMASK_ERROR, "Unable to change effective user ID to normal (%ld): [%d] %s", (PRINT_UID_T) EUID_Normal, errno, strerror(errno)); exit(1); }
  EUID_Current = EUID_Normal;

  return(SUCCESS);

}
#endif

#if !WIN32
/* SYSSETUID FUNCTION - JONAS (01.07.2000) */

signed long int sysseteuid(const uid_t UID) {

  signed long int Result = 0;

  if (UID_Current != 0) { return(ERROR); }
  if (EUID_Current == UID) { return(SUCCESS); }

  Result = seteuid(0);
  if (Result <= ERROR) { sysprint(BITMASK_ERROR, "Unable to change effective user ID to root (0): [%d] %s", errno, strerror(errno)); return(ERROR); }
  EUID_Current = 0;
  if (UID == 0) { return(SUCCESS); }

  Result = seteuid(UID);
  if (Result <= ERROR) {
    sysprint(BITMASK_ERROR, "Unable to change effective user ID to %ld: [%d] %s", (PRINT_UID_T) UID, errno, strerror(errno));
    Result = seteuid(EUID_Normal);
    if (Result <= ERROR) { sysprint(BITMASK_ERROR, "Unable to change effective user ID to normal (%ld): [%d] %s", (PRINT_UID_T) EUID_Normal, errno, strerror(errno)); exit(1); }
    return(ERROR);
  }
  EUID_Current = UID;

  return(SUCCESS);

}
#endif

#if !WIN32
/* SYSSETUIDBYUSER FUNCTION - JONAS (01.07.2000) */

signed long int sysseteuidbyuser(const char *const UserPT) {

  signed long int Result = 0;
  uid_t UID = 0;

  assert(UserPT != NULL);

  if (UID_Current != 0) { return(ERROR); }

  UID = sysgetuidfromuser(UserPT);
  if (aerrno != AESUCCESS) { return(ERROR); }

  if (EUID_Current == UID) { return(SUCCESS); }

  Result = sysseteuid(UID);

  return(Result);

}
#endif

/* SYSINITFILES FUNCTION - JONAS (27.02.2002) */

void sysinitfiles(void) {

  unsigned short int Index = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Initializing all files.");

  for (Index = 0 ; Index < PrintFileS_Len ; Index++) {

    char File[FILELEN+1] = "";

    assert(PrintFileS[Index].Name != NULL);

    if ((strncmp(PrintFileS[Index].Name, ConfS.LogPath, strlen(ConfS.LogPath)) != FALSE) && (PrintFileS[Index].Name[0] != '/')) {
      memset(File, 0, FILELEN+1);
      strncat(File, ConfS.LogPath, (FILELEN - strlen(File)));
      if (File[strlen(File)] != '/') { strncat(File, "/", (FILELEN - strlen(File))); }
      strncat(File, PrintFileS[Index].Name, (FILELEN - strlen(File)));
      PrintFileS[Index].Name = strrealloc(PrintFileS[Index].Name, File);
    }
    assert(PrintFileS[Index].Name != NULL);
    if (Index == 2) { PrintFileS[Index].FilePT = stderr; }
    else { PrintFileS[Index].FilePT = stdout; }


  }

}

/* SYSCLOSEFILES FUNCTION - JONAS (25.06.2000) */

void sysclosefiles(void) {

  unsigned long int FD = 0;
  unsigned long int FDL = sysconf(_SC_OPEN_MAX);

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Closing all files.");

  for (FD = 0 ; FD <= FDL ; FD++) { close(FD); }

}

/* SYSOPENFILES_FG FUNCTION - JONAS (18.07.2001) */

void sysopenfiles_fg(void) {

  unsigned short int Index = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Opening files (foreground).");

  for (Index = 1 ; Index < PrintFileS_Len ; ++Index) {
    assert(PrintFileS[Index].Name != NULL);
    PrintFileS[Index].FilePT = fopen(PrintFileS[Index].Name, "a");
    if (PrintFileS[Index].FilePT == NULL) {
      printf("Unable to open %s: [%d] %s\n", PrintFileS[Index].Name, errno, strerror(errno));
      exit(1);
    }
  }

}

#if !WIN32
/* SYSOPENFILES_BG FUNCTION - JONAS (18.07.2001) */

void sysopenfiles_bg(void) {

  signed long int Result = 0;
  unsigned short int Index = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Opening files (background).");

  for (Index = 0 ; Index < PrintFileS_Len ; ++Index) {
    if ((PrintFileS[Index].FilePT == NULL) || (PrintFileS[Index].FilePT == stdin) || (PrintFileS[Index].FilePT == stdout) || (PrintFileS[Index].FilePT == stderr)) { continue; }
    Result = fclose(PrintFileS[Index].FilePT);
    if (Result == EOF) {
      sysprint(BITMASK_ERROR, "Unable to close %s: [%d] %s", PrintFileS[Index].Name, errno, strerror(errno));
      exit(1);
    }
    PrintFileS[Index].FilePT = NULL;
  }

  close(0);
  close(1);
  close(2);

#if 0
  FD_CLR(0, &ReadFDS);
  FD_CLR(0, &WriteFDS);
  FD_CLR(1, &ReadFDS);
  FD_CLR(1, &WriteFDS);
  FD_CLR(2, &ReadFDS);
  FD_CLR(2, &WriteFDS);
#endif

  for (Index = 0 ; Index < PrintFileS_Len ; ++Index) {
    switch (Index) {
      case 0:
      case 1:
      case 2:
        Result = open(PrintFileS[Index].Name, (O_CREAT|O_NONBLOCK|O_WRONLY|O_APPEND), (S_IRUSR|S_IWUSR|S_IRGRP));
        assert(Result == Index);
        if (Result != Index) { abort(); }
        if (Index == 0) { PrintFileS[Index].FilePT = NULL; }
        else if (Index == 1) { PrintFileS[Index].FilePT = stdout; }
        else if (Index == 2) { PrintFileS[Index].FilePT = stderr; }
        break;
      default:
        PrintFileS[Index].FilePT = fopen(PrintFileS[Index].Name, "a");
        if (PrintFileS[Index].FilePT == NULL) {
          sysprint(BITMASK_ERROR, "Unable to open %s: [%d] %s", PrintFileS[Index].Name, errno, strerror(errno));
          exit(1);
        }
    }
  }

}
#endif

/* SYSFLUSHFILES FUNCTION - JONAS (18.07.2001) */

void sysflushfiles(void) {

  signed long int Result = 0;
  unsigned long int Index = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Flushing all file descriptors...");

  FlushTime = NOW;

  for (Index = 0 ; Index < PrintFileS_Len ; Index++) {
    if (PrintFileS[Index].Name == NULL) { continue; }
    if (PrintFileS[Index].FilePT == NULL) { continue; }
    Result = fflush(PrintFileS[Index].FilePT);
    if (Result <= ERROR) {
      sysprint(BITMASK_ERROR, "Unable to flush %s: [%d] %s", PrintFileS[Index].Name, errno, strerror(errno));
      exit(1);
    }
  }

}

#if !WIN32
/* SYSCHECKPID FUNCTION - JONAS (11.07.2001) */

void syscheckpid(void) {

  FILE *FilePT = NULL;
  char Line[LINELEN+1] = "";
  char *LinePT = NULL;
  unsigned long int pid = 0;
  signed long int Result = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Checking PID file.");

  if ((UID_Current == 0) && (EUID_Current != 0)) {
    Result = seteuid(0);
    if (Result <= ERROR) { sysprint(BITMASK_ERROR, "Unable to change effective user ID to root (0): [%d] %s", errno, strerror(errno)); }
    else { EUID_Current = 0; }
  }

  FilePT = fopen(ConfS.PIDFile, "r");
  if (FilePT == NULL) {
    if (errno != ENOENT) { sysprint(BITMASK_ERROR, "Unable to open %s for reading: [%d] %s", ConfS.PIDFile, errno, strerror(errno)); }
  }
  else {
    LinePT = fgets(Line, LINELEN, FilePT);
    if (LinePT != NULL) pid = atoi(LinePT);
    if (pid <= 1) { fclose(FilePT); }
    else {
      Result = kill(pid, SIGUSR1);
      if (Result != ERROR) {
        fclose(FilePT);
        printf("%s already running, PID: %ld\n", PACKAGE, (PRINT_PID_T) pid);
        exit(1);
      }
      fclose(FilePT);
    }
  }

  if (EUID_Current != EUID_Normal) {
    Result = seteuid(EUID_Normal);
    if (Result <= ERROR) { sysprint(BITMASK_ERROR, "Unable to change effective user ID to %ld: [%d] %s", (PRINT_UID_T) EUID_Normal, errno, strerror(errno)); exit(1); }
    EUID_Current = EUID_Normal;
  }

}
#endif

#if !WIN32
/* SYSWRITEPID FUNCTION - JONAS (25.06.2000) */

void syswritepid(void) {

  signed long int Result = 0;
  FILE *FilePT = NULL;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Writing PID file, current PID: %ld.", (PRINT_PID_T) PID);

  if ((UID_Current == 0) && (EUID_Current != 0)) {
    Result = seteuid(0);
    if (Result <= ERROR) { sysprint(BITMASK_ERROR, "Unable to change effective user ID to root (0): [%d] %s", errno, strerror(errno)); }
    else { EUID_Current = 0; }
  }

  FilePT = fopen(ConfS.PIDFile, "w");
  if (FilePT == NULL) {
    sysprint(BITMASK_ERROR, "Unable to open %s for writing: [%d] %s", ConfS.PIDFile, errno, strerror(errno));
    exit(1);
  }

  fprintf(FilePT, "%ld%s", (PRINT_PID_T) PID, LINEFEED);
  fclose(FilePT);

  if (EUID_Current != EUID_Normal) {
    Result = seteuid(EUID_Normal);
    if (Result <= ERROR) { sysprint(BITMASK_ERROR, "Unable to change effective user ID to %ld: [%d] %s", (PRINT_UID_T) EUID_Normal, errno, strerror(errno)); exit(1); }
    EUID_Current = EUID_Normal;
  }

}
#endif

/* SYSSETSIGNALS FUNCTION - JONAS (25.06.2000) */

void syssetsignals(void) {

  void *ResultPT = NULL;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Setting signals.");

#ifdef SIGHUP
  ResultPT = signal(SIGHUP, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Hangup\"."); }
#endif

#ifdef SIGINT
  ResultPT = signal(SIGINT, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Interrupt\"."); }
#endif

#ifdef SIGQUIT
  ResultPT = signal(SIGQUIT, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Quit\"."); }
#endif

#ifdef SIGILL
  ResultPT = signal(SIGILL, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Illegal instruction\"."); }
#endif

#ifdef SIGTRAP
  ResultPT = signal(SIGTRAP, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Trace trap\"."); }
#endif

#ifdef SIGABRT
  ResultPT = signal(SIGABRT, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Abort\"."); }
#endif

#ifdef SIGIOT
  ResultPT = signal(SIGIOT, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Abort\"."); }
#endif

#ifdef SIGEMT
  ResultPT = signal(SIGEMT, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"EMT instruction\"."); }
#endif

#ifdef SIGFPE
  ResultPT = signal(SIGFPE, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Floating-point exception\"."); }
#endif

#ifdef SIGBUS
  ResultPT = signal(SIGBUS, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Bus error\"."); }
#endif

#ifdef SIGSEGV
  ResultPT = signal(SIGSEGV, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Segmentation violation\"."); }
#endif

#ifdef SIGSYS
  ResultPT = signal(SIGSYS, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Non-existent system call invoked\"."); }
#endif

#ifdef SIGPIPE
  ResultPT = signal(SIGPIPE, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Broken pipe\"."); }
#endif

#ifdef SIGALRM
  ResultPT = signal(SIGALRM, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Alarm clock\"."); }
#endif

#ifdef SIGTERM
  ResultPT = signal(SIGTERM, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Termination\"."); }
#endif

#ifdef SIGURG
  ResultPT = signal(SIGURG, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Urgent condition on IO channel\"."); }
#endif

#ifdef SIGTSTP
  ResultPT = signal(SIGTSTP, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Stop signal from tty\"."); }
#endif

#ifdef SIGCONT
  ResultPT = signal(SIGCONT, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Continue a stopped process\"."); }
#endif

#ifdef SIGCHLD
  ResultPT = signal(SIGCHLD, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Signal to parent on child stop or exit\"."); }
#endif

#ifdef SIGTTIN
  ResultPT = signal(SIGTTIN, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Background read from tty\"."); }
#endif

#ifdef SIGTTOU
  ResultPT = signal(SIGTTOU, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Background write to tty\"."); }
#endif

#ifdef SIGIO
  ResultPT = signal(SIGIO, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"I/O possible\"."); }
#endif

#ifdef SIGXCPU
  ResultPT = signal(SIGXCPU, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Exceeded CPU time limit\"."); }
#endif

#ifdef SIGXFSZ
  ResultPT = signal(SIGXFSZ, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Exceeded file size limit\"."); }
#endif

#ifdef SIGVTALRM
  ResultPT = signal(SIGVTALRM, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Virtual alarm clock\"."); }
#endif

#ifdef SIGPROF
  ResultPT = signal(SIGPROF, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Profiling alarm clock\"."); }
#endif

#ifdef SIGWINCH
  ResultPT = signal(SIGWINCH, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Window size change\"."); }
#endif

#if 0
  ResultPT = signal(SIGINFO, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Information request\"."); }
#endif

#ifdef SIGUSR1
  ResultPT = signal(SIGUSR1, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"User-defined signal 1\"."); }
#endif

#ifdef SIGUSR2
  ResultPT = signal(SIGUSR2, SIG_IGN);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"User-defined signal 1\"."); }
#endif

#ifdef SIGPWR
  ResultPT = signal(SIGPWR, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Power failure restart\"."); }
#endif

#ifdef SIGSTKFLT
  ResultPT = signal(SIGSTKFLT, syshandlesignal);
  if (ResultPT == SIG_ERR) { sysprint(BITMASK_ERROR, "Unable to install signal handler for \"Stack fault\"."); }
#endif

}

/* SYSHANDLESIGNAL FUNCTION - JONAS (26.03.2002) */

void syshandlesignal(int Signal) {

  signal(Signal, syshandlesignal);


  /* Signals telling us to rehash the configuration */

#ifdef SIGHUP
  if (Signal == SIGHUP) { /* Hangup */
    sysprint(BITMASK_MAIN, "Caught signal %d, %s.", Signal, nlstrsignal(Signal));
    main_rehash();
    return;
  }
#endif


  /* Signals telling us to exit normally */

  if
    (
    (1 == 2)
#ifdef SIGINT
    ||
    (Signal == SIGINT) /* Interrupt */
#endif
#ifdef SIGTERM
    ||
    (Signal == SIGTERM)	/* Termination */
#endif
  ) {
    ExitSignals++;
    if (ExitSignals >= 3) { exit(0); }
    sysprint(BITMASK_MAIN, "Caught signal %d, %s.", Signal, nlstrsignal(Signal));
    sysflushfiles();
    main_exit("Caught signal %d, %s", Signal, nlstrsignal(Signal));
    return;
  }


  /* Signals telling us something went wrong */

  if
    (
    (1 == 2)
#ifdef SIGQUIT
    ||
    (Signal == SIGQUIT) /* Quit */
#endif
#ifdef SIGILL
    ||
    (Signal == SIGILL) /* Illegal instruction */
#endif
#ifdef SIGTRAP
    ||
    (Signal == SIGTRAP) /* Trace trap */
#endif
#ifdef SIGABRT
    ||
    (Signal == SIGABRT) /* Abort */
#endif
#ifdef SIGIOT
    ||
    (Signal == SIGIOT) /* Abort? */
#endif
#ifdef SIGEMT
    ||
    (Signal == SIGEMT) /* EMT instruction */
#endif
#ifdef SIGFPE
    ||
    (Signal == SIGFPE) /* Floating-point exception */
#endif
#ifdef SIGBUS
    ||
    (Signal == SIGBUS) /* BUS error */
#endif
#ifdef SIGSEGV
    ||
    (Signal == SIGSEGV) /* Segmentation violation */
#endif
#ifdef SIGSYS
    ||
    (Signal == SIGSYS) /* Non-existent system call invoked */
#endif
#ifdef SIGSTKFLT
    ||
    (Signal == SIGSTKFLT) /* Stack fault */
#endif
#ifdef SIGPWR
    ||
    (Signal == SIGPWR) /* Power failure restart */
#endif
#ifdef SIGTSTP
    ||
    (Signal == SIGTSTP) /* Stop signal from tty */
#endif
#ifdef SIGXCPU
    ||
    (Signal == SIGXCPU) /* Exceeded CPU time limit */
#endif
#ifdef SIGXFSZ
    ||
    (Signal == SIGXFSZ) /* Exceeded file size limit */
#endif
  ) {
    ExitSignals++;
    if (ExitSignals >= 3) { exit(0); }
    sysprint(BITMASK_ERROR, "Caught signal %d, %s.", Signal, nlstrsignal(Signal));
    sysflushfiles();
    main_exit("Caught signal %d, %s", Signal, nlstrsignal(Signal));
    main_loop();
    return;
  }


  /* And basically just print anything else */

  sysprint(BITMASK_MAIN, "Caught signal %d, %s.", Signal, nlstrsignal(Signal));

}

#if !WIN32
/* SYSFORK FUNCTION - JONAS (25.06.2000) */

void sysfork(void) {

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Going into the background...");

  PID = fork();
  switch(PID) {
    case ERROR:
      sysprint(BITMASK_ERROR, "Unable to create a child process: [%d] %s", errno, strerror(errno));
      exit(1);
    case SUCCESS:
      if (setsid() == ERROR) {
        sysprint(BITMASK_ERROR, "Unable to request a new session: [%d] %s", errno, strerror(errno));
        exit(1);
      }
      break;
    default:
      exit(0);
  }

  sysopenfiles_bg();
  PID = getpid();
  syswritepid();
  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Successfully went into the background, PID: %ld", (PRINT_PID_T) PID);
  ScreenMode = FALSE;

}
#endif

/* SYSPRINT FUNCTION - JONAS (25.06.2000) */

void sysprint(const unsigned long int Bitmask, const char *const LinePT, ...) {

  char Line[LINELEN+1] = "";
  va_list Args = { 0 };
  unsigned short int Index = 0;

  assert(LinePT != NULL);

  va_start(Args, LinePT);
  vsnprintf(Line, LINELEN+1, LinePT, Args);
  va_end(Args);

  for (Index = 0 ; Index < PrintFileS_Len ; Index++) {
    if (PrintFileS[Index].FilePT == NULL) { continue; }
    if ((ScreenMode == TRUE) && (ScreenPrint == TRUE) && ((PrintFileS[Index].FilePT == stdout) || (PrintFileS[Index].FilePT == stderr))) { continue; }
    if (PrintFileS[Index].Bitmask & Bitmask) {
      fprintf(PrintFileS[Index].FilePT, "%s *** %s%s", dtstamp(), Line, LINEFEED);
      fflush(PrintFileS[Index].FilePT);
    }
  }

  if ((ScreenMode == TRUE) && (ScreenPrint == TRUE) && (ScreenBitmask & Bitmask)) {
    if (ScreenDTS == TRUE) { fprintf(stdout, "%s *** %s\n", dtstamp(), Line); }
    else { fprintf(stdout, "%s\n", Line); }
    fflush(stdin);
    fflush(stdout);
    fflush(stderr);
  }

  #if DCC
    dcc_conn_sendall(Bitmask, "*** %s\r\n", Line);
  #endif

}

/* DEBUGPRINT FUNCTION - JONAS (01.12.2007) */

void debugprint(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, const char *const TextLinePT, ...) {

  char TextLine[LINELEN+1] = "";
  va_list Args = { 0 };
  unsigned short int Index = 0;

  assert(FilePT != NULL);
  assert(FunctionPT != NULL);
  assert(TextLinePT != NULL);

  va_start(Args, TextLinePT);
  vsnprintf(TextLine, LINELEN+1, TextLinePT, Args);
  va_end(Args);

  for (Index = 0 ; Index < PrintFileS_Len ; Index++) {
    if ((PrintFileS[Index].Bitmask & BITMASK_DEBUG) && (PrintFileS[Index].FilePT != NULL)) {
      fprintf(PrintFileS[Index].FilePT, "%s *** DEBUG *** FILE: %s LINE: %d FUNCTION: %s *** %s%s", dtstamp(), FilePT, Line, FunctionPT, TextLine, LINEFEED);
      fflush(PrintFileS[Index].FilePT);
    }
  }

  if ((ScreenMode == TRUE) && (ScreenPrint == TRUE) && (ScreenBitmask & BITMASK_DEBUG)) {
    if (ScreenDTS == TRUE) { fprintf(stdout, "%s *** DEBUG *** FILE: %s LINE: %d FUNCTION: %s *** %s%s", dtstamp(), FilePT, Line, FunctionPT, TextLine, LINEFEED); }
    else { fprintf(stdout, "*** DEBUG *** FILE: %s LINE: %d FUNCTION: %s *** %s%s", FilePT, Line, FunctionPT, TextLine, LINEFEED); }
    fflush(stdin);
    fflush(stdout);
    fflush(stderr);
  }

  #if DCC
    dcc_conn_sendall(BITMASK_DEBUG, "*** %s\r\n", Line);
  #endif

}

/* SYSREHASH FUNCTION - JONAS (01.07.2000) */

void sysrehash(void) {

  FILE *FilePT = fopen(ConfS.PIDFile, "r");
  char Line[LINELEN+1] = "";
  char *LinePT = NULL;
  pid_t pid = 0;
  signed long int Result = 0;

  if (FilePT == NULL) {
    printf("Cannot rehash %s: Unable to open PID file %s: [%d] %s\n", PACKAGE, ConfS.PIDFile, errno, strerror(errno));
    return;
  }
  LinePT = fgets(Line, LINELEN, FilePT);
  if (LinePT != NULL) pid = atoi(LinePT);
  if (pid <= 1) {
    printf("Cannot rehash %s: Invalid PID: %ld.\n", PACKAGE, (PRINT_PID_T) pid);
    return;
  }
  Result = kill(pid, SIGHUP);
  if (Result == ERROR) {
    printf("Cannot rehash %s, PID: %ld: [%d] %s\n", PACKAGE, (PRINT_PID_T) pid, errno, strerror(errno));
    fclose(FilePT);
    return;
  }

  printf("Sent HUP signal to %s, PID: %ld.\n", PACKAGE, (PRINT_PID_T) pid);
  fclose(FilePT);

}

/* SYSTERM FUNCTION - JONAS (01.07.2000) */

void systerm(void) {

  FILE *FilePT = fopen(ConfS.PIDFile, "r");
  char Line[LINELEN+1] = "";
  char *LinePT = NULL;
  pid_t pid = 0;
  signed long int Result = 0;

  if (FilePT == NULL) {
    printf("Cannot terminate %s: Unable to open PID file %s: [%d] %s\n", PACKAGE, ConfS.PIDFile, errno, strerror(errno));
    return;
  }
  LinePT = fgets(Line, LINELEN, FilePT);
  if (LinePT != NULL) pid = atoi(Line);
  if (pid <= 1) {
    printf("Cannot terminate %s: Invalid PID: %ld.\n", PACKAGE, (PRINT_PID_T) pid);
    return;
  }
  Result = kill(pid, SIGTERM);
  if (Result == ERROR) {
    printf("Cannot terminate %s, PID: %ld: [%d] %s\n", PACKAGE, (PRINT_PID_T) pid, errno, strerror(errno));
    fclose(FilePT);
    return;
  }

  printf("Sent TERM signal to %s, PID: %ld.\n", PACKAGE, (PRINT_PID_T) pid);
  fclose(FilePT);

}

/* SYSRUN FUNCTION - JONAS (01.07.2000) */

signed short int sysrun(const char *const CmdPT, char *ResultPT) {

  FILE *FilePT = NULL;
  signed long int Result = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Running shell command: %s", CmdPT);

  FilePT = popen(CmdPT, "r");
  if (FilePT == NULL) { return(ERROR); }
  Result = fread(ResultPT, sizeof(char), RECVBUFFERLEN, FilePT);
  pclose(FilePT);
  return(Result);

}

#if !WIN32
/* SYSGETUIDFROMUSER FUNCTION - JONAS (01.07.2000) */

#if HAVE_GETPWNAM
uid_t sysgetuidfromuser(const char *const UserPT) {

  struct passwd *PasswdPT = NULL;

  assert(UserPT != NULL);

  PasswdPT = getpwnam(UserPT);
  if (PasswdPT == NULL) {
    aerrno = AENOMATCH;
    return(0);
  }
  aerrno = AESUCCESS;
  return(PasswdPT->pw_uid);
}
#else
uid_t sysgetuidfromuser(const char *const UserPT) {

  FILE *FilePT = NULL;
  char *TempPT = NULL;
  char Line[LINELEN+1] = "";
  uid_t UID = 0;

  assert(UserPT != NULL);

  FilePT = fopen(PASSWD_FILE, "r");
  if (FilePT == NULL) {
    sysprint(BITMASK_ERROR, "Unable to open %s: [%d] %s", PASSWD_FILE, errno, strerror(errno));
    aerrno = AENORESOURCE;
    return(0);
  }

  FOREVERLOOP {

    TempPT = fgets(Line, LINELEN, FilePT);
    if (TempPT == NULL) { break; }

    while ((TempPT = strchr(Line, '\r')) != NULL) { *TempPT = '\0'; }
    while ((TempPT = strchr(Line, '\n')) != NULL) { *TempPT = '\0'; }
    if ((Line[0] == '#') || (Line[0] == ';') || (Line[0] == '\0')) { continue; }

    TempPT = strtok(Line, ":");
    if (TempPT == NULL) { continue; }
    if (strcmp(TempPT, UserPT) != FALSE) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    UID = strtoul(TempPT, NULL, 0);
    fclose(FilePT);
    aerrno = AESUCCESS;
    return(UID);
  }
  fclose(FilePT);
  aerrno = AENOMATCH;
  return(0);
}
#endif /* HAVE_GETPWNAM */
#endif /* !WIN32 */

#if !WIN32

/* SYSGETNAMEFROMUSER FUNCTION - JONAS (01.07.2000) */

#if HAVE_GETPWNAM
char *sysgetnamefromuser(const char *const UserPT) {

  struct passwd *PasswdPT = NULL;

  assert(UserPT != NULL);

  PasswdPT = getpwnam(UserPT);
  if (PasswdPT == NULL) { return(NULL); }
  TMPSTRPT = strrealloc(TMPSTRPT, PasswdPT->pw_gecos);
  return(TMPSTRPT);

}
#else
char *sysgetnamefromuser(const char *const UserPT) {

  FILE *FilePT = NULL;
  char *TempPT = NULL;
  char Line[LINELEN+1] = "";

  assert(UserPT != NULL);

  FilePT = fopen(PASSWD_FILE, "r");
  if (FilePT == NULL) {
    sysprint(BITMASK_ERROR, "Unable to open %s: [%d] %s", PASSWD_FILE, errno, strerror(errno));
    return(NULL);
  }

  FOREVERLOOP {

    TempPT = fgets(Line, LINELEN, FilePT);
    if (TempPT == NULL) { break; }

    while ((TempPT = strchr(Line, '\r')) != NULL) { *TempPT = '\0'; }
    while ((TempPT = strchr(Line, '\n')) != NULL) { *TempPT = '\0'; }
    if ((Line[0] == '#') || (Line[0] == ';') || (Line[0] == '\0')) { continue; }

    TempPT = strtok(Line, ":");
    if (TempPT == NULL) { continue; }
    if (strcmp(TempPT, UserPT) != FALSE) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    fclose(FilePT);

    TMPSTRPT = strrealloc(TMPSTRPT, TempPT);
    return(TMPSTRPT);

  }
  fclose(FilePT);

  return(NULL);

}
#endif
#endif

#if !WIN32

/* SYSGETHOMEDIRFROMUSER FUNCTION - JONAS (01.07.2000) */

#if HAVE_GETPWNAM
char *sysgethomedirfromuser(const char *const UserPT) {

  struct passwd *PasswdPT = NULL;

  assert(UserPT != NULL);

  PasswdPT = getpwnam(UserPT);
  if (PasswdPT == NULL) { return(NULL); }
  TMPSTRPT = strrealloc(TMPSTRPT, PasswdPT->pw_dir);
  return(TMPSTRPT);

}
#else
char *sysgethomedirfromuser(const char *const UserPT) {

  FILE *FilePT = NULL;
  char *TempPT = NULL;
  char Line[LINELEN+1] = "";

  assert(UserPT != NULL);

  FilePT = fopen(PASSWD_FILE, "r");
  if (FilePT == NULL) {
    sysprint(BITMASK_ERROR, "Unable to open %s: [%d] %s", PASSWD_FILE, errno, strerror(errno));
    return(NULL);
  }

  FOREVERLOOP {

    TempPT = fgets(Line, LINELEN, FilePT);
    if (TempPT == NULL) { break; }

    while ((TempPT = strchr(Line, '\r')) != NULL) { *TempPT = '\0'; }
    while ((TempPT = strchr(Line, '\n')) != NULL) { *TempPT = '\0'; }
    if ((Line[0] == '#') || (Line[0] == ';') || (Line[0] == '\0')) { continue; }

    TempPT = strtok(Line, ":");
    if (TempPT == NULL) { continue; }
    if (strcmp(TempPT, UserPT) != FALSE) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    fclose(FilePT);

    TMPSTRPT = strrealloc(TMPSTRPT, TempPT);
    return(TMPSTRPT);

  }
  fclose(FilePT);

  return(NULL);

}
#endif
#endif

#if !WIN32

/* SYSGETGIDFROMGROUP FUNCTION - JONAS (01.07.2000) */

gid_t sysgetgidfromgroup(const char *const GroupPT) {

  FILE *FilePT = NULL;
  char *TempPT = NULL;
  char Line[LINELEN+1] = "";
  gid_t GID = 0;

  assert(GroupPT != NULL);

  FilePT = fopen(GROUP_FILE, "r");
  if (FilePT == NULL) {
    sysprint(BITMASK_ERROR, "Unable to open %s: [%d] %s", GROUP_FILE, errno, strerror(errno));
    aerrno = AENORESOURCE;
    return(0);
  }

  FOREVERLOOP {

    TempPT = fgets(Line, LINELEN, FilePT);
    if (TempPT == NULL) { break; }

    while ((TempPT = strchr(Line, '\r')) != NULL) { *TempPT = '\0'; }
    while ((TempPT = strchr(Line, '\n')) != NULL) { *TempPT = '\0'; }
    if ((Line[0] == '#') || (Line[0] == ';') || (Line[0] == '\0')) { continue; }

    TempPT = strtok(Line, ":");
    if (TempPT == NULL) { continue; }
    if (strcmp(TempPT, GroupPT) != FALSE) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    TempPT = strtok(NULL, ":");
    if (TempPT == NULL) { continue; }

    GID = strtoul(TempPT, NULL, 0);
    fclose(FilePT);
    aerrno = AESUCCESS;
    return(GID);

  }
  aerrno = AENOMATCH;
  fclose(FilePT);
  return(0);

}
#endif

/* SYSCLEANUP FUNCTION - JONAS (01.07.2000) */

void syscleanup(void) {

  unsigned short int Index = 0;

  DEBUGPRINT(BITMASK_DEBUG_SYSCALLS, "Freeing %s allocated memory.", __FILE__);

  FREE(TMPSTRPT);
  for (Index = 0 ; Index < PrintFileS_Len ; ++Index) {
    FREE(PrintFileS[Index].Name);
  }

}

/* NL_NET_ATON FUNCTION - JONAS (01.07.2000) */

int nl_net_aton(const char *HostIPS, struct in_addr *InAddr) {

  signed long int Result = INADDR_NONE;

  Result = inet_addr(HostIPS);
  if (Result == INADDR_NONE) {
    return(0);
  }
  InAddr->s_addr = Result;
  return(1);

}



syntax highlighted by Code2HTML, v. 0.9.1