Logo Search packages:      
Sourcecode: unionfs-tools version File versions  Download package

usercommon.c

/*
 * Copyright (c) 2003-2006 Erez Zadok
 * Copyright (c) 2003-2006 Charles P. Wright
 * Copyright (c) 2005-2006 Josef Sipek
 * Copyright (c) 2005      Arun M. Krishnakumar
 * Copyright (c) 2005-2006 David P. Quigley
 * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
 * Copyright (c) 2003      Puja Gupta
 * Copyright (c) 2003      Harikesavan Krishnan
 * Copyright (c) 2003-2006 Stony Brook University
 * Copyright (c) 2003-2006 The Research Foundation of State University of New York
 *
 * For specific licensing information, see the COPYING file distributed with
 * this package.
 *
 * This Copyright notice must be kept intact and distributed with all sources.
 */
/*
 *  $Id: usercommon.c,v 1.5 2006/12/09 23:35:51 ezk Exp $
 */

#include "config.h"

#ifdef HAVE_STDLIB_H
      #include <stdlib.h>
#else /* HAVE_STDLIB_H */
      #error Need stdlib.h to compile
#endif /* HAVE_STDLIB_H */

#ifdef HAVE_STDIO_H
      #include <stdio.h>
#else /* HAVE_STDIO_H */
      #error Need stdio.h to compile
#endif /* HAVE_STDIO_H */

#ifdef HAVE_STRING_H
      #include <string.h>
#else /* HAVE_STRING_H */
      #error Need string.h to compile
#endif /* HAVE_STRING_H */

#ifdef HAVE_SYS_IOCTL_H
      #include <sys/ioctl.h>
#else   /* HAVE_SYS_IOCTL_H */
      #error Need sys/ioctl.h to compile
#endif /* HAVE_SYS_IOCTL_H */

#ifdef HAVE_SYS_STAT_H
      #include <sys/stat.h>
#else /* HAVE_SYS_STAT_H */
      #error Need sys/stat.h to compile
#endif /* HAVE_SYS_STAT_H */

#ifdef HAVE_ERRNO_H
      #include <errno.h>
#else /* HAVE_ERRNO_H */
      #error Need errno.h to compile
#endif /* HAVE_ERRNO_H */

#ifdef HAVE_LIMITS_H
      #include <limits.h>
#else /* HAVE_LIMITS_H */
      #define PATH_MAX 4096
#endif /* HAVE_LIMITS_H */

/*
 * This function will take a patch and check it against /proc/mounts to
 * find its mount point. If uniononly is set  then it will make sure its
 * a unionf  mount point. This function assumes the both options and actual_path
 * are valid and not null;
 */
int find_union(const char *path, char **options, char **actual_path,
             int uniononly)
{
      FILE *f = NULL;
      char *s = NULL;
      char *s2 = NULL;
      char *p;
      char *q;
      int candidate = 0;
      int mallocsize = 1024;  /* Just a reasonable starting value. */

      retry:
      if (*options) {
            free(*options);
            *options = NULL;
      }

      if (*actual_path) {
            free(*actual_path);
            *actual_path = NULL;
      }
      if (f) {
            fclose(f);
            f = NULL;
      }
      s2 = realloc(s, mallocsize);
      if (!s2) {
            fprintf(stderr, "realloc(%d): %s\n", mallocsize,
                  strerror(errno));
            goto out;
      }
      s = s2;

      f = fopen("/proc/mounts", "r");
      if (!f) {
            fprintf(stderr, "fopen(/proc/mounts): %s\n", strerror(errno));
            goto out;
      }
      while (fgets(s, mallocsize, f)) {
            int testcan;

            /* If we don't have enough information, we should remalloc it. */
            if (strlen(s) == (mallocsize - 1)) {
                  mallocsize *= 2;
                  goto retry;
            }

            p = strchr(s, ' ');
            if (!p)
                  continue;
            p++;

            q = strchr(p, ' ');
            if (!q)
                  continue;
            *q++ = '\0';

            testcan = strlen(p);
            if (testcan <= candidate) {
                  continue;
            }

            if (!strncmp(path, p, testcan)) {
                  if (*actual_path) {
                        free(*actual_path);
                  }
                  *actual_path = strdup(p);
                  if (!*actual_path) {
                        fprintf(stderr, "strdup: %s\n",
                              strerror(errno));
                        goto out;
                  }
                  p = strchr(q, ' ');
                  if (!p)
                        continue;
                  *p++ = '\0';
                  if (uniononly) {
                        if (strcmp(q, "unionfs")) {
                              candidate = 0;
                              continue;
                        }
                  }
                  candidate = testcan;

                  q = strrchr(p, ' ');
                  if (!q)
                        continue;
                  *q = '\0';
                  q = strrchr(p, ' ');
                  if (!q)
                        continue;
                  *q = '\0';

                  if (*options) {
                        free(*options);
                  }
                  *options = strdup(p);
                  if (!*options) {
                        fprintf(stderr, "strdup: %s\n",
                              strerror(errno));
                        goto out;
                  }
            }
      }

      out:
      if (s)
            free(s);
      if (f)
            fclose(f);

      if (*options) {
            return 0;
      }

      errno = -ENOENT;
      return -1;
}

/*
 * Resolves the real path of a relative path
 */
int get_real_path(const char *path, char *resolv_path)
{
      struct stat st;

      if (realpath(path, resolv_path) == NULL) {
            perror("realpath()");
            return -1;
      }

      if (strcmp(resolv_path, "/") && (resolv_path[strlen(resolv_path) - 1] == '/')) {
            resolv_path[strlen(resolv_path) - 1] = '\0';
      }

      if (stat(resolv_path, &st) == -1) {
            perror("stat()");
            return -1;
      }

      return 0;
}


/**
 * Takes the device and creates an fsid from it by placing major in the first
 * int and minor in the second.
 */
void fillfsid(dev_t dev, fsid_t * fsid)
{
      ((unsigned int *)fsid)[0] = major(dev);
      ((unsigned int *)fsid)[1] = minor(dev);
}

int mkfsid(char *path, fsid_t * fsid)
{
      int err = 0;
      char *actual_path = NULL;
      char *options = NULL;
      char res_path[PATH_MAX];
      struct stat stat_struct;

      err = get_real_path(path, res_path);
      if (err)
            goto out;

      memset(&stat_struct, 0, sizeof(struct stat));
      err = find_union(res_path, &options, &actual_path, 0);
      if (err) {
            fprintf(stderr, "find_union failed:\n");
            goto out;
      }
      err = stat(actual_path, &stat_struct);
      if (err) {
            perror("Couldn't stat path: ");
            goto out;
      }

      fillfsid(stat_struct.st_dev, fsid);

      out:
      if (options)
            free(options);

      return err;
}

/*
 *
 * vim:shiftwidth=8
 * vim:tabstop=8
 *
 * For Emacs:
 * Local variables:
 * c-basic-offset: 8
 * c-comment-only-line-offset: 0
 * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0)
 *              (substatement-open . 0) (label . 0) (statement-cont . +))
 * indent-tabs-mode: t
 * tab-width: 8
 * End:
 */

Generated by  Doxygen 1.6.0   Back to index