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

ctl.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.
 */

#include "unionfs.h"
#include "unionctl.h"

static char **branches;
static int *branchperms;

/*
   Finds union with union_path
   Returns 0 on success, -1 on error
 */
int unionfs_find_union(const char *union_path, char **actual_path)
{
      char resolv_path[PATH_MAX];
      char *options = NULL;
      int err;

      err = get_real_path(union_path, resolv_path);
      if (err)
            goto out;

      err = find_union(resolv_path, &options, actual_path, 1);

      out:
      if ( options )
            free(options);

      return 0;
}

int unionfs_query(const char *file_path, struct unionfs_branch **ufs_branches)
{
      int i;
      int fd;
      int ret;
      int len;
      fd_set branchlist;
      char resolv_path[PATH_MAX];

      if ( get_real_path(file_path, resolv_path) )
            return -1;

      if ( load_branches(resolv_path) )
            return -1;

      if ((fd = open(file_path, O_RDONLY)) < 0) {
            fprintf(stderr,
                        "Unable to open file %s : %s",
                        file_path, strerror(errno));
            return -1;
      }

      len = ioctl(fd, UNIONFS_IOCTL_QUERYFILE, &branchlist);
      if (len < 0) {
            fprintf(stderr,
                        "Unable to retrieve list of branches for file %s : %s\n",
                        file_path, strerror(errno));
            return -1;
      }

      ret = 0;
      *ufs_branches = malloc(sizeof(struct unionfs_branch));
      if (!(*ufs_branches)) {
            errno = ENOMEM;
            return -1;
      }


      for (i = 0; i <= len; i++) {
            if (FD_ISSET(i, &branchlist)) {
                  *ufs_branches = realloc(*ufs_branches,
                              sizeof(struct unionfs_branch)*(ret+1));
                  (*ufs_branches)[ret].path = malloc(strlen(branches[ret]+1));
                  strcpy((*ufs_branches)[ret].path, branches[i]);
                  (*ufs_branches)[ret].perms = branchperms[i];
                  ret++;
            }

      }
      return ret;
}

int unionfs_dump(const char *union_path, const char *prefix)
{
      char resolv_path[PATH_MAX];
      if ( get_real_path(union_path, resolv_path) )
            return -1;

      if ( load_branches(resolv_path) )
            return -1;

      dump_branches(prefix);
      return 0;
}


/*
   This function adds a branch to a union
Example: unionfs_add("/", "/tmp", 0, MAY_READ | MAY_WRITE);
 */
int unionfs_add(const char *union_path, const char *branch_path, int branch_number, int perms)
{
      int fd, ret;
      struct unionfs_addbranch_args addargs;
      char *options = NULL, *actual_path = NULL;
      char resolv_path[PATH_MAX], resolv_bp[PATH_MAX];

      ret = get_real_path(union_path, resolv_path);
      if (ret)
            goto out;

      ret = get_real_path(branch_path, resolv_bp);
      if (ret)
            goto out;

      ret = find_union(resolv_path, &options, &actual_path, 1);
      if (ret) {
            errno = EINVAL;
            goto out;
      }

      addargs.ab_branch = branch_number;
      addargs.ab_perms = perms;
      addargs.ab_path = resolv_bp;

      fd = open(resolv_path, O_RDONLY);
      if(fd < 0) {
            errno = EACCES;
            goto out;
      }
      ret = ioctl(fd, UNIONFS_IOCTL_ADDBRANCH, &addargs);
      close(fd);

      out:
      if (options)
            free(options);

      if (actual_path)
            free(actual_path);

      return ret;
}

/*
   This function deletes a branch from a union
 */
int unionfs_remove(const char *union_path, int branch)
{
      int ret;
      unsigned long remountdata[3];
      char *options = NULL, *actual_path = NULL;
      char resolv_path[PATH_MAX];

      ret = get_real_path(union_path, resolv_path);
      if (ret)
            goto out;

      ret = find_union(resolv_path, &options, &actual_path, 1);
      if (ret) {
            errno = EINVAL;
            goto out;
      }

      errno = 0;
      remountdata[0] = UNIONFS_REMOUNT_MAGIC;
      remountdata[1] = UNIONFS_IOCTL_DELBRANCH;
      remountdata[2] = branch;
      ret = mount("unionfs", actual_path, "unionfs", MS_REMOUNT | MS_MGC_VAL, remountdata);

      out:
      if (options)
            free(options);

      if (actual_path)
            free(actual_path);

      return ret;
}

/*
   Gets the branch number from a path.
   Returns branch number on success and -1 on failure.
 */
int unionfs_get_branch(const char *union_path, const char *branch_path)
{
      char *end;
      int ret;
      char resolv_path[PATH_MAX], resolv_bp[PATH_MAX];


      if ( get_real_path(union_path, resolv_path) )
            return -1;

      if ( get_real_path(branch_path, resolv_bp) )
            return -1;

      if ( load_branches(resolv_path) )
            return -1;

      ret = strtol(resolv_bp, &end, 0);
      if (!*end)
            return ret;

      ret = strlen(resolv_bp);
      if ((ret > 1) && (resolv_bp[ret - 1] == '/')) {
            resolv_bp[ret - 1] = '\0';
      }

      ret = 0;
      while (branches[ret]) {
            if (!strcmp(branches[ret], resolv_bp))
                  return ret;
            ret++;
      }

      return -1;
}

int unionfs_mode(const char *union_path, int branch_number, int perms)
{
      struct unionfs_rdwrbranch_args rdwrargs;
      int ret, fd;
      char *options = NULL, *actual_path = NULL;
      char resolv_path[PATH_MAX];

      ret = get_real_path(union_path, resolv_path);
      if (ret)
            goto out;

      ret = find_union(resolv_path, &options, &actual_path, 1);
      if (ret) {
            errno = EINVAL;
            goto out;
      }

      rdwrargs.rwb_branch = branch_number;
      rdwrargs.rwb_perms = perms;

      fd = open(resolv_path, O_RDONLY);
      if (fd < 0) {
            errno = EACCES;
            goto out;
      }

      ret = ioctl(fd, UNIONFS_IOCTL_RDWRBRANCH, &rdwrargs);
      close(fd);

      out:
      if (options)
            free(options);

      if (actual_path)
            free(actual_path);

      return ret;
}

static int load_branches(const char *union_path) {
      int ret;
      char *options = NULL, *actual_path = NULL;

      ret = find_union(union_path, &options, &actual_path, 1);
      if (ret) {
            errno = EINVAL;
            goto out;
      }

      branches = parse_options(options);
      if (branches <= 0) {
            fprintf(stderr, "Could not parse options from /proc/mounts!\n");
            ret = -1;
            goto out;
      }

      out:
      if (options)
            free(options);

      if (actual_path)
            free(actual_path);

      return ret;
}

/*static*/ inline int parse_rw(char *p)
{
      if (strcmp(p, "ro") == 0)
            return MAY_READ;
      else if (strcmp(p, "nfsro") == 0)
            return MAY_READ | MAY_NFSRO;
      else if (strcmp(p, "rw") == 0)
            return MAY_READ | MAY_WRITE;
      else
            return 0;
}

static char **parse_options(char *options)
{
      char **ret = NULL;
      int i = 0;

      char *p;
      char *q;
      char *r;
      char *s, *t, *u;

      p = options;
      do {
            q = strchr(p, ',');
            if (q) {
                  *q++ = '\0';
            }
            if (!strncmp(p, "dirs=", strlen("dirs="))) {
                  r = p + strlen("dirs=");
                  do {
                        s = strchr(r, ':');
                        if (s) {
                              *s++ = '\0';
                        }

                        i++;
                        ret = realloc(ret, sizeof(char *) * (i + 1));
                        if (!ret) {
                              perror("realloc()");
                              return NULL;
                        }
                        branchperms =
                              realloc(branchperms, sizeof(int) * i);
                        if (!branchperms) {
                              perror("realloc()");
                              return NULL;
                        }

                        t = strchr(r, '=');
                        u = t + 1;
                        if (!t || !u || !*u)
                              goto err;
                        *t = 0;
                        branchperms[i - 1] = parse_rw(u);
                        if (!branchperms[i - 1]) {
err:
                              fprintf(stderr, "cannot parse '%s'\n",
                                          r);
                              return NULL;
                        }
                        ret[i - 1] = strdup(r);
                        ret[i] = NULL;

                        r = s;
                  }
                  while (r);
            }
            p = q;
      }
      while (p);

      branches = ret;
      return ret;
}

static void dump_branches(const char *prefix)
{
      int i = 0;

      while (branches && branches[i]) {
            char r, w, n;
            r = (branchperms[i] & MAY_READ) ? 'r' : '-';
            w = (branchperms[i] & MAY_WRITE) ? 'w' : '-';
            n = (branchperms[i] & MAY_NFSRO) ? 'n' : '-';
            printf("%s%s (%c%c%c)\n", prefix, branches[i], r, w, n);
            i++;
      }
}


Generated by  Doxygen 1.6.0   Back to index