Logo Search packages:      
Sourcecode: paco version File versions  Download package

log.c

/***********************************************************************
 * log.c: Handles the system calls that create files and logs them.
 ***********************************************************************
 * This file is part of the package paco
 * Copyright (C) 2004-2009 David Rosal
 * For more information visit http://paco.sourceforge.net
 ***********************************************************************/

#include "config.h"
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>                    
#include <stdarg.h>
#include <unistd.h>

#define __have_64__  (HAVE_OPEN64 && HAVE_CREAT64 && HAVE_TRUNCATE64 \
                      && HAVE_FOPEN64 && HAVE_FREOPEN64)

#define CHECK_INIT  do { \
      if (!lp_tmpfile) lp_init(); \
} while (0)

#define PACO_BUFSIZE  4096

static int  (*libc_creat)           (const char*, mode_t);
static int  (*libc_link)            (const char*, const char*);
static int  (*libc_open)            (const char*, int, ...);
static int  (*libc_rename)          (const char*, const char*);
static int  (*libc_symlink)         (const char*, const char*);
static int  (*libc_truncate)  (const char*, off_t);
static FILE*(*libc_fopen)           (const char*, const char*);
static FILE*(*libc_freopen)         (const char*, const char*, FILE*);
#if __have_64__
static int  (*libc_creat64)         (const char*, mode_t);
static int  (*libc_open64)          (const char*, int, ...);
static int  (*libc_truncate64)      (const char*, off64_t);
static FILE*(*libc_fopen64)         (const char*, const char*);
static FILE*(*libc_freopen64) (const char*, const char*, FILE*);
#endif  /* __have_64__ */

static char*      lp_tmpfile;
static int        lp_debug;


static void lp_die(const char* fmt, ...)
{
      va_list ap;
      
      fflush(stdout);
      fputs("libpaco-log: ", stderr);
      va_start(ap, fmt);
      vfprintf(stderr, fmt, ap);
      va_end(ap);
      putc('\n', stderr);
      
      exit(EXIT_FAILURE);
}


static void* lp_dlsym(const char* symbol)
{
      void* ret;
      char* error;

      dlerror();

      if (!(ret = dlsym(RTLD_NEXT, symbol))) {
            error = (char*)dlerror();
            lp_die("dlsym(%p, \"%s\"): %s", RTLD_NEXT, symbol,
                  error ? error : "failed");
      }

      return ret;
}

            
static void lp_init()
{
      static char* dbg = NULL;

      /* handle libc */
      
      libc_creat = lp_dlsym("creat");
      libc_link = lp_dlsym("link");
      libc_open = lp_dlsym("open");
      libc_rename = lp_dlsym("rename");
      libc_symlink = lp_dlsym("symlink");
      libc_truncate = lp_dlsym("truncate");
      libc_fopen = lp_dlsym("fopen");
      libc_freopen = lp_dlsym("freopen");
#if __have_64__
      libc_open64 = lp_dlsym("open64");
      libc_creat64 = lp_dlsym("creat64");
      libc_truncate64 = lp_dlsym("truncate64");
      libc_fopen64 = lp_dlsym("fopen64");
      libc_freopen64 = lp_dlsym("freopen64");
#endif  /* __have_64__ */

      /* read the environment */
      
      if (!lp_tmpfile && !(lp_tmpfile = getenv("PACO_TMPFILE")))
            lp_die("variable %s undefined", "PACO_TMPFILE"); \
            
      if (!dbg && (dbg = getenv("PACO_DEBUG")))
            lp_debug = !strcmp(dbg, "yes");
}


static void lp_log(const char* path, const char* fmt, ...)
{
      static char abs_path[PACO_BUFSIZE];
      va_list a;
      int fd, len, __errno = errno;
      
      if (!strcmp(path, "/dev/tty") || !strcmp(path, "/dev/null") ||
            !strncmp(path, "/proc/", 6))
            goto ____end;

      CHECK_INIT;

      if (lp_debug) {
            fflush(stdout);
            fprintf(stderr, "paco :: ");
            va_start(a, fmt);
            vfprintf(stderr, fmt, a);
            va_end(a);
            putc('\n', stderr);
      }
      
      /* "Absolutize" relative paths */
      if (path[0] == '/') {
            strncpy(abs_path, path, PACO_BUFSIZE - 1);
            abs_path[PACO_BUFSIZE - 1] = '\0';
      }
      else if (getcwd(abs_path, PACO_BUFSIZE)) {
            strncat(abs_path, "/", PACO_BUFSIZE - strlen(abs_path) - 1);
            strncat(abs_path, path, PACO_BUFSIZE - strlen(abs_path) - 1);
      }
      else
            snprintf(abs_path, PACO_BUFSIZE, "./%s", path);

      strncat(abs_path, "\n", PACO_BUFSIZE - strlen(abs_path) - 1);

      if ((fd = libc_open(lp_tmpfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0)
            lp_die("open(\"%s\"): %s", lp_tmpfile, strerror(errno));
      
      len = strlen(abs_path);
      
      if (write(fd, abs_path, len) != len)
            lp_die("%s: write(): %s", lp_tmpfile, strerror(errno));
            
      if (close(fd) < 0)
            lp_die("close(%d): %s", fd, strerror(errno));
      
____end:
      errno = __errno;
}


/************************/
/* System call handlers */
/************************/

FILE* fopen(const char* path, const char* mode)
{
      FILE* ret;
      
      CHECK_INIT;
      
      ret = libc_fopen(path, mode);
      if (ret && strpbrk(mode, "wa+"))
            lp_log(path, "fopen(\"%s\", \"%s\")", path, mode);
      
      return ret;
}


FILE* freopen(const char* path, const char* mode, FILE* stream)
{
      FILE* ret;
      
      CHECK_INIT;
      
      ret = libc_freopen(path, mode, stream);
      if (ret && strpbrk(mode, "wa+"))
            lp_log(path, "freopen(\"%s\", \"%s\")", path, mode);
      
      return ret;
}


/*
 * If NEWBUF isn't a directory write it to the log, otherwise log files it and
 * its subdirectories contain.
 */
static void log_rename(const char* oldpath, const char* newpath)
{
      char oldbuf[PACO_BUFSIZE], newbuf[PACO_BUFSIZE];
      struct stat st;
      DIR* dir;
      struct dirent* e;
      size_t oldlen, newlen;
      int __errno = errno;    /* save global errno */

      /* The NEWpath file doesn't exist.  */
      if (-1 == lstat(newpath, &st)) 
            goto ____end;

      else if (!S_ISDIR(st.st_mode)) {
            /* NEWpath is a file or a symlink.  */
            lp_log(newpath, "rename(\"%s\", \"%s\")", oldpath, newpath);
            goto ____end;
      }

      /* Make sure we have enough space for the following slashes.  */
      oldlen = strlen(oldpath);
      newlen = strlen(newpath);
      if (oldlen + 2 >= PACO_BUFSIZE || newlen + 2 >= PACO_BUFSIZE)
            goto ____end;

      strcpy(oldbuf, oldpath);
      strcpy(newbuf, newpath);
      newbuf[PACO_BUFSIZE - 1] = oldbuf[PACO_BUFSIZE - 1] = '\0';

      /* We can do this in the loop below, buf it's more efficient to do
         that once. These slashes will separate the path NEWBUF/OLDBUF
         contains from names of its files/subdirectories.  */
      oldbuf[oldlen++] = newbuf[newlen++] = '/';
      oldbuf[oldlen] = newbuf[newlen] = '\0';

      dir = opendir(newbuf);

      while ((e = readdir(dir))) {
            if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
                  continue;
            strncat(oldbuf, e->d_name, PACO_BUFSIZE - oldlen - 1);
            strncat(newbuf, e->d_name, PACO_BUFSIZE - newlen - 1);
            log_rename(oldbuf, newbuf);
            oldbuf[oldlen] = newbuf[newlen] = '\0';
      }

      closedir(dir);

____end:
      /* Restore global errno */
      errno = __errno;
}


int rename(const char* oldpath, const char* newpath)
{
      int ret;
      
      CHECK_INIT;
      
      if ((ret = libc_rename(oldpath, newpath)) != -1)
            log_rename(oldpath, newpath);

      return ret;
}


int creat(const char* path, mode_t mode)
{
      int ret;
      
      CHECK_INIT;
      
      ret = libc_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
      
      if (ret != -1)
            lp_log(path, "creat(\"%s\", 0%o)", path, (int)mode);
      
      return ret;
}


int link(const char* oldpath, const char* newpath)
{
      int ret;
      
      CHECK_INIT;
      
      if ((ret = libc_link(oldpath, newpath)) != -1)
            lp_log(newpath, "link(\"%s\", \"%s\")", oldpath, newpath);
      
      return ret;
}


int truncate(const char* path, off_t length)
{
      int ret;
      
      CHECK_INIT;
      
      if ((ret = libc_truncate(path, length)) != -1)
            lp_log(path, "truncate(\"%s\", %d)", path, (int)length);
      
      return ret;
}


int open(const char* path, int flags, ...)
{
      va_list a;
      mode_t mode;
      int accmode, ret;
      
      CHECK_INIT;
      
      va_start(a, flags);
      mode = va_arg(a, mode_t);
      va_end(a);
      
      if ((ret = libc_open(path, flags, mode)) != -1) {
            accmode = flags & O_ACCMODE;
            if (accmode == O_WRONLY || accmode == O_RDWR)
                  lp_log(path, "open(\"%s\")", path);
      }

      return ret;
}


int symlink(const char* oldpath, const char* newpath)
{
      int ret;
      
      CHECK_INIT;
      
      if ((ret = libc_symlink(oldpath, newpath)) != -1)
            lp_log(newpath, "symlink(\"%s\", \"%s\")", oldpath, newpath);
      
      return ret;
}


#if __have_64__

int creat64(const char* path, mode_t mode)
{
      int ret;
      
      CHECK_INIT;
      
      if ((ret = libc_open64(path, O_CREAT | O_WRONLY | O_TRUNC, mode)) != -1)
            lp_log(path, "creat64(\"%s\")", path);
      
      return ret;
}


int open64(const char* path, int flags, ...)
{
      va_list a;
      mode_t mode;
      int accmode, ret;
      
      CHECK_INIT;
      
      va_start(a, flags);
      mode = va_arg(a, mode_t);
      va_end(a);
      
      if ((ret = libc_open64(path, flags, mode)) != -1) {
            accmode = flags & O_ACCMODE;
            if (accmode == O_WRONLY || accmode == O_RDWR)
                  lp_log(path, "open64(\"%s\")", path);
      }

      return ret;
}


int truncate64(const char* path, off64_t length)
{
      int ret;
      
      CHECK_INIT;
      
      if ((ret = libc_truncate64(path, length)) != -1)
            lp_log(path, "truncate64(\"%s\", %d)", path, (int)length);
      
      return ret;
}


FILE* fopen64(const char* path, const char* mode)
{
      FILE* ret;
      
      CHECK_INIT;
      
      ret = libc_fopen64(path, mode);
      if (ret && strpbrk(mode, "wa+"))
            lp_log(path, "fopen64(\"%s\", \"%s\")", path, mode);
      
      return ret;
}


FILE* freopen64(const char* path, const char* mode, FILE* stream)
{
      FILE* ret;
      
      CHECK_INIT;
      
      ret = libc_freopen64(path, mode, stream);
      if (ret && strpbrk(mode, "wa+"))
            lp_log(path, "freopen64(\"%s\", \"%s\")", path, mode);
      
      return ret;
}

#endif  /* __have_64__ */


Generated by  Doxygen 1.6.0   Back to index