Logo Search packages:      
Sourcecode: pbbuttonsd version File versions

pbb_misc.c

/* ----------------------------------------------------------------------------
 * pbb_misc.c
 * funtions usefull for everybody
 *
 * Copyright 2002 Matthias Grimm
 *
 * 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.
 * ----------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <syslog.h>

#include "pbb.h"

/* the prototype for getpgid() should be in unistd.h but although it is
 * included above the compiler complains with "implicit declaration for
 * getpgid" if this line is missing. This must be further investigated.
 */
extern pid_t getpgid (pid_t pid);

extern struct libbase libdata;

/* This function checks the existance and the filetype of a given
 * file and returns the result. The result is '0' if the given file
 * exists and matches the desired filetype. Otherwise an error code
 * is returned.
 */
int
check_devorfile (char *file, int type)
{
      struct stat stat_buf;
      int rc;

      if (type == TYPE_SYMLINK)
            rc = lstat(file, &stat_buf);  /* don't follow symlinks */
      else
            rc = stat(file, &stat_buf);     /* follow symlinks */

      if (rc)
            return E_NOEXIST;
      else
            switch (type) {
                  case TYPE_CHARDEV:
                        if(!S_ISCHR(stat_buf.st_mode))
                              return E_NOCHAR;
                        break;
                  case TYPE_BLKDEV:
                        if(!S_ISBLK(stat_buf.st_mode))
                              return E_NOBLK;
                        break;
                  case TYPE_SYMLINK:
                        if (!S_ISLNK(stat_buf.st_mode))
                              return E_NOLINK;
                        break;
                  case TYPE_FILE:
                        if (!S_ISREG(stat_buf.st_mode))
                              return E_NOFILE;
                        break;
            }
      return 0;
}

/* This function runs a program in an separate process and waits for
 * it's return. If the program haven't returned after base->timeforcmd
 * seconds, it will be killed. The child process closes all open
 * handles and switches STDIN, STDOUT and STDERR to /dev/null so
 * that the program can't process any input or output.
 */
int
launch_program (char* maskstr, ...)
{     
      struct libbase *base = &libdata;
      int pid, pgrp, status, i, n, rc, maxfiles;
      struct rlimit l;
      char *argv[MAXARGS+1], script[MAXCMDLEN+1];
      va_list list;

      va_start(list, maskstr);
      vsnprintf (script, MAXCMDLEN, maskstr, list);
      script[MAXCMDLEN] = '\0';
      va_end (list);

      i = n = rc = maxfiles = 0;
      do {
            argv[i++] = &script[n];  /* put argument in argv[] array */
            while (script[n] != ' ' && script[n] != '\0') n++;
            if (script[n] == ' ') {
                  script[n] = '\0';           /* terminate argument */
                  while (script[++n] == ' '); /* remove leading spaces */
            }
      } while (i < MAXARGS && script[n] != '\0');
      argv[i] = NULL;  /* terminate argv[] array */

      if((rc = check_permissions (argv[0], geteuid(), 022)))
            return rc;

      if (!getrlimit(RLIMIT_NOFILE, &l))
            maxfiles = l.rlim_cur; /* get max count of file handles */

      pid = fork();
      switch (pid) {
      case 0:
            /* child */
            for (i=0; i < maxfiles; i++)
                  close(i);      /* close all possible file handles */

            open("/dev/null", O_RDONLY);  /* STDIN */
            open("/dev/null", O_WRONLY);  /* STDOUT */
            open("/dev/null", O_WRONLY);  /* STDERR */
            setsid();             /* opens its own process group */
            execv(argv[0], argv); /* execute command */
            exit(99);             /* will only be executed if execv fails */
            break;
      case -1:
            /* fork failed, no child created */
            rc = E_CLDFAIL;
            break;
      default:
            /* parent */
            rc = 0;
            for (i=base->timeforcmd * 10; i > 0; i--) {
                  usleep(100000);  /* sleep 100ms */
                  if (waitpid (pid, &status, WNOHANG)) {
                        if (WIFEXITED(status)) {
                              if ((base->rc = WEXITSTATUS(status)))
                                    rc = E_CLDEXIT;
                        } else if (WIFSIGNALED(status))
                              rc = E_CLDSIG;
                        /* else: If the child did't exited normally and
                         * was not terminated by a signal then it has
                         * been stopped. In this case the lopp will
                         * continue and after the timeout is over the
                         * stopped child will be killed
                         */
                        break;
                  }
            }
            if (i == 0) {
                  pgrp = getpgid(pid);   /* get childs process group */
                  kill (-pgrp, SIGKILL);     /* kill child and his childs */
                  waitpid (pid, &status, 0); /* clean up zombie */
                  rc = E_CLDKILL;
            }
      }
      return rc;
}

int
get_lastrc()
{
      struct libbase *base = &libdata;
      return base->rc;
}

int
get_timeforcmd()
{
      struct libbase *base = &libdata;
      return base->timeforcmd;
}

void
set_timeforcmd(int timeout)
{
      struct libbase *base = &libdata;
      if (timeout <= 0)
            timeout = 1;
      base->timeforcmd = timeout;
}

int
check_permissions (char *file, int uid, int mask)
{
      struct stat stat_buf;

      if(stat(file, &stat_buf))
            return E_NOEXIST;
      if (stat_buf.st_uid != 0 && stat_buf.st_uid != uid)
            return E_USER;
      if (stat_buf.st_mode & mask)
            return E_RIGHTS;
      return 0;
}

int
get_owner (char *file)
{
      struct stat stat_buf;

      if(stat(file, &stat_buf))
            return -1;
      return stat_buf.st_uid;
      return 0;
}

int
get_permissions (char *file)
{
      struct stat stat_buf;

      if(stat(file, &stat_buf))
            return -1;
      return stat_buf.st_mode & 0777;
}

int
keydelayms (struct timeval *start, int value, int delay)
{
      struct timeval tv;
      long ms;

      if (value == 1)         /* key pressed for the first time */
            gettimeofday (start, 0);

      if (value == 2) {
            gettimeofday(&tv, 0);
            ms = (tv.tv_sec - start->tv_sec) * 1000000 + tv.tv_usec - start->tv_usec;
            if (ms > (delay * 1000))
                  return 1;
      }
      return 0;
}

/* This function removes all whitespaces from the buffer except
 * quoted ones.
 */
void
cleanup_buffer(char *buffer)
{
      char *buf2 = buffer, quotchar = 0;

      while (*buffer != 0) {
            *buf2 = *buffer++;
            if (quotchar == 0) {  /* no quoting active */
                  if ((*buf2 == '"') || (*buf2 == '\''))
                        quotchar = *buf2;
                  else if ((*buf2 != ' ') && (*buf2 != '\t'))
                        buf2++;                 
            } else if (*buf2 == quotchar)  /* qouting active */
                  quotchar = 0;
            else
                  buf2++;
      }
      *buf2 = 0;   /* terminate cleaned-up buffer again */
}

/* This function converts a string to an integer. Additionally to
 * atoi() it converts also hexadecimal values
 */
int
axtoi (char *arg)
{
      int n, val, pwr=1, m, rc = 0;
      char hex[9], c;

      for (n=0,m=0; n < strlen(arg); n++)
            if (arg[n] != ' ') {
                  hex[m++] = c = toupper(arg[n]);
                  if (m == sizeof(hex) || c < '0' || c > 'F')
                        return 0;   /* overflow or invalid */
            }
      hex[m] = '\0';  /* terminate string */

      for (n=0; n < m; n++) {
            c = hex[m-n-1];
            if ((c >= 'A') && (c <= 'F')) {
                  val = c -'A' + 10;
            } else {
                  val = c - '0';
            }
            rc = rc + val * pwr;
            pwr *= 16;
      }
      return rc;
}

Generated by  Doxygen 1.6.0   Back to index