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

faubackup-gather.c

/*
 *  FauBackup - Backup System, using a Filesystem for Storage
 *  Copyright (c) 2000-01 Dr. Volkmar Sieh, (c) 2000-06 Martin Waitz
 *  $Id$
 *
 *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include "config.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <utime.h>
#include <popt.h>

#include "faubackup.h"


int error;
const char* progname;

/* variables set by command line */
static int verbose = 0;
static int atime_preserve = 0;


static void
send_buf(void *_buf, size_t len)
{
      unsigned char *buf = _buf;
      int ret;

      while( len > 0 ) {
            ret = fwrite( buf, 1, len, stdout );
            if( ferror(stdout) ) {
                  fprintf( stderr, "%s: stdout fwrite %d bytes: %s\n",
                              progname, len, strerror(errno));
                  exit(1);
            }
            buf += ret;
            len -= ret;
      }
}

static void
send_string(char *str)
{
      unsigned int tmp, len;

      len = strlen(str);
      tmp = htonl(len);

      send_buf( &tmp, sizeof(tmp) );
      send_buf( str, len );
}

static void
send_inode(struct stat *st)
{
      unsigned int tmp;
      int size64 = 0;

      /*
       * send contents of inode
       */
      assert( sizeof(tmp) == 4 );
      tmp = htonl(st->st_dev); send_buf( &tmp, sizeof(tmp) );
      tmp = htonl(st->st_ino); send_buf( &tmp, sizeof(tmp) );
      tmp = st->st_mode & 07777;
      switch( st->st_mode & ~07777 ) {
      case S_IFBLK: tmp |= B_IFBLK; break;
      case S_IFCHR: tmp |= B_IFCHR; break;
      case S_IFDIR: tmp |= B_IFDIR; break;
      case S_IFIFO: tmp |= B_IFIFO; break;
      case S_IFLNK: tmp |= B_IFLNK; break;
      case S_IFREG: tmp |= B_IFREG; break;
      case S_IFSOCK: tmp |= B_IFSOCK; break;
      default: assert(0); break;
      }
      if(st->st_size>>32) {
            tmp |= B_IFSIZE64;
            size64 = 1;
      }
      tmp = htonl(tmp);
      send_buf( &tmp, sizeof(tmp) );
      tmp = htonl(st->st_uid); send_buf( &tmp, sizeof(tmp) );
      tmp = htonl(st->st_gid); send_buf( &tmp, sizeof(tmp) );
      tmp = htonl(st->st_rdev); send_buf( &tmp, sizeof(tmp) );
      tmp = htonl(st->st_size); send_buf( &tmp, sizeof(tmp) );
      if( size64 ) {
            tmp = htonl(st->st_size>>32); send_buf( &tmp, sizeof(tmp) );
      }
/*    tmp = htonl(st->st_atime); send_buf( &tmp, sizeof(tmp) );*/
      tmp = htonl(st->st_mtime); send_buf( &tmp, sizeof(tmp) );
}


static void
gather_blk(char *path, struct stat *st)
{
      assert( S_ISBLK(st->st_mode) );

      send_inode( st );
      send_string( path );
}


static void
gather_chr(char *path, struct stat *st)
{
      assert( S_ISCHR(st->st_mode) );

      send_inode( st );
      send_string( path );
}


static void
gather_reg(char *path, struct stat *st)
{
      int fd;
      FILE *file;
      int ret;
      off_t pos;
      struct utimbuf times;

      assert( S_ISREG(st->st_mode) );

#if HAVE_O_NOATIME
      fd = open( path, O_NOATIME );
#else
      fd = -1;
#endif
      if( fd < 0 ) {
            /* retry without O_NOATIME */
            fd = open(path, 0);
      }
      if( fd < 0 ) {
            fprintf( stderr, "%s: open \"%s\": %s\n",
                        progname, path, strerror(errno));
            error++;
            return;
      }


      file = fdopen( fd, "r" );
      if( !file ) {
            fprintf( stderr, "%s: fopen \"%s\": %s\n",
                        progname, path, strerror(errno));
            error++;
            return;
      }

      send_inode( st );
      send_string( path );

      for( pos = 0; pos < st->st_size; ) {
            char buf[128*1024];
            size_t count;
            size_t len;

            if( st->st_size - pos < (off_t) sizeof(buf) ) {
                  count = st->st_size - pos;
            } else {
                  count = sizeof(buf);
            }

            len = fread(buf, 1, count, file);
            if( ferror(file) < 0) {
                  fprintf(stderr, "%s: fread \"%s\": %s\n",
                              progname, path, strerror(errno));
                  error++;

                  /* ignore any error and send `count' bytes */
                  /* otherwise we will get a protocol error */
                  len = count;
            }

            send_buf( buf, len );

            pos += len;
      }

      ret = fclose(file);
      if( ret < 0) {
            fprintf(stderr, "%s: close \"%s\": %s\n",
                        progname, path, strerror(errno));
            error++;
            return;
      }

      if( atime_preserve ) {
            /* reset atime of file */
            times.actime = st->st_atime;
            times.modtime = st->st_mtime;
            ret = utime( path, &times );
            if( ret<0 && errno != EROFS && errno != EPERM ) {
                  fprintf(stderr, "%s: utime \"%s\": %s\n",
                              progname, path, strerror(errno));
                  return;
            }
      }
}


static void
gather_lnk(char *path, struct stat *st)
{
      char link[MAXLEN];
      int ret;

      assert( S_ISLNK(st->st_mode) );

      ret = readlink(path, link, sizeof(link) - 1);
      if( ret < 0) {
            fprintf(stderr, "%s: readlink \"%s\": %s\n",
                        progname, path, strerror(errno));
            error++;
            return;
      }
      link[ret] = '\0';

      send_inode( st );
      send_string( path );
      send_string( link );
}


static void
gather_dir(char *path, struct stat *st)
{
      assert( S_ISDIR(st->st_mode) );

      send_inode( st );
      send_string( path );
}

static void
gather(char *path)
{
      int ret;
      struct stat st;

      ret = lstat( path, &st );
      if( ret < 0) {
            fprintf(stderr, "%s: lstat \"%s\": %s\n",
                        progname, path, strerror(errno));
            error++;
            return;
      }

      if( S_ISBLK(st.st_mode) ) {
            gather_blk(path, &st);
      } else if( S_ISCHR(st.st_mode) ) {
            gather_chr(path, &st);
      } else if( S_ISREG(st.st_mode) ) {
            gather_reg(path, &st);
      } else if( S_ISLNK(st.st_mode) ) {
            gather_lnk(path, &st);
      } else if( S_ISDIR(st.st_mode) ) {
            gather_dir(path, &st);
      } else if( S_ISFIFO(st.st_mode)
            || S_ISSOCK(st.st_mode) ) {
            /* skip fifo/socket */
            /* nothing to do */
      } else {
            fprintf( stderr, "%s: \"%s\": unknown mode 0%o\n",
                        progname, path, (int) st.st_mode );
            error++;
            return;
      }

}


static struct poptOption options[] = {
      {
            .longName="verbose", .shortName='v',
            .argInfo=POPT_ARG_NONE, .arg=&verbose,
            .descrip = "Print verbose messages"
      }, {
            .longName="version",
            .val = 'V',
            .descrip = "Print program version"
      }, {
            .longName="atime-preserve",
            .argInfo=POPT_ARG_NONE, .arg=&atime_preserve,
            .descrip = "try to preserve access time, will change ctime"
      },
      POPT_AUTOHELP
      {}
};

int
main(int argc, const char* argv[])
{
      char path[MAXLEN];
      int c, len;
      poptContext popt;
      int rc;

      error=0;
      progname=argv[0];

      /* argument parsing */
      popt = poptGetContext("faubackup", argc, argv, options, 0);
      while( (rc = poptGetNextOpt(popt)) > 0 ) {
            switch (rc) {
            case 'V':
                  printf("%s\n", PACKAGE_STRING);
                  exit(0);
            }
      }
      if(rc<-1) {
            poptPrintUsage(popt, stderr, 0);
            fprintf(stderr, "%s: %s\n",
                        poptBadOption(popt, 0), poptStrerror(rc));
            exit(1);
      }

      if( poptPeekArg(popt) ) {
            poptPrintUsage(popt, stderr, 0);
            fprintf(stderr, "unknown parameter\n");
            exit(1);
      }

      /* process file list from stdin */
      len = 0;
      while( (c=fgetc(stdin)) != EOF ) {
            path[len++] = c;

            if( len==sizeof(path) ) {
                  /* didn't fit in here -> skip */
                  path[sizeof(path)-1] = '\0';
                  fprintf(stderr, "path too long: \"%s...\"!\n", path);
                  while( fgetc(stdin)>0 );
                  len = 0;
                  continue;
            }

            if( c!='\0' ) continue;
            /* one filename read, process it */

            if( verbose) {
                  fprintf(stderr, "%s\n", path);
            }

            gather( path );
            len = 0;
      }

      return( error!=0 );
}

Generated by  Doxygen 1.6.0   Back to index