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

mount.c

/*
 * Copyright (c) 2003, 2004, 2005 Nokia
 * Author: Timo Savola <tsavola@movial.fi>
 *
 * This program is licensed under GPL (see COPYING for details)
 */

#include "mount.h"
#include "common.h"

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>

mount_info_t *mntinfo_alloc(void)
{
      return calloc(1, sizeof (mount_info_t));
}

void mntinfo_free(mount_info_t *mi)
{
      if (mi->opts)
            free(mi->opts);

      if (mi->device)
            free(mi->device);

      if (mi->point)
            free(mi->point);

      free(mi);
}

int mntinfo_copy(mount_info_t *dest, mount_info_t *src)
{
      memset(dest, 0, sizeof (mount_info_t));

      dest->type = src->type;

      dest->point = strdup(src->point);
      if (!dest->point)
            goto _err;

      dest->device = strdup(src->device);
      if (!dest->device)
            goto _err;

      if (src->opts) {
            dest->opts = strdup(src->opts);
            if (!dest->opts)
                  goto _err;
      }

      dest->device_dev = src->device_dev;

      return 0;

_err:
      if (dest->device)
            free(dest->device);

      if (dest->point)
            free(dest->point);

      oom_error();
      return -1;
}

/**
 * Returns a newly allocated mount_info_t and sets its fields according
 * to the input string.
 */
mount_info_t *mntinfo_parse(const char *input)
{
      mount_info_t *mi;
      char *buf = NULL, *type, *device, *point, *opts;

      mi = mntinfo_alloc();
      if (!mi) {
            oom_error();
            return NULL;
      }

      buf = strdup(input);
      if (!buf) {
            oom_error();
            goto _err_buf;
      }

      split_string(buf, &type, &device, &point, &opts, NULL);

      if (!type || !device || !point) {
            error("Invalid mount entry: %s", input);
            goto _err;
      }

      if (strcmp(type, MTYPE_NFS_S) == 0) {
            mi->type = MTYPE_NFS;
      } else if (strcmp(type, MTYPE_BIND_S) == 0) {
            mi->type = MTYPE_BIND;
      } else {
            error("Unknown mount type: %s", type);
            goto _err;
      }

      mi->device = strdup(device);
      if (!mi->device) {
            oom_error();
            goto _err;
      }

      mi->point = strdup(point);
      if (!mi->point) {
            oom_error();
            goto _err;
      }

      if (opts) {
            mi->opts = strdup(opts);
            if (!mi->opts) {
                  oom_error();
                  goto _err;
            }
      }

      free(buf);

      return mi;

_err:
      free(buf);

_err_buf:
      mntinfo_free(mi);
      return NULL;
}

/*
 * Parse IP address (addr_p) and path (path_p) from NFS mount string (fs).
 * NFS mount string should be of the form "<host>:<path>".
 * Returns -1 on error; 0 otherwise.
 */
static int resolve_nfs(const char *fs, uint32_t *addr_p, char **path_p)
{
      char host[MAXHOSTNAMELEN], *path;
      uint32_t addr;

      path = strchr(fs, ':');
      if (!path || path[1] == '\0') {
            error("Invalid NFS filesystem: %s", fs);
            return -1;
      }

      memset(host, '\0', sizeof (host));
      strncpy(host, fs, MIN(path - fs, sizeof (host) - 1));

      addr = resolve(host);
      if (!addr)
            return -1;

      *addr_p = addr;
      *path_p = path + 1;

      return 0;
}

/*
 * Check if NFS filesystem is not originating from this host, and try to
 * find the local mount point if it's originating from a remote host.
 */
static char *get_local_path(uint32_t r_addr, char *r_path)
{
      FILE *file;
      char buf[1024];
      struct { char nfs_path[PATH_MAX], *path; } sel;

      sel.path = NULL;

      file = fopen(MOUNTS_FILE, "r");
      if (!file) {
            error("Can't open " MOUNTS_FILE);
            return NULL;
      }

      while (1) {
            char *device, *point, *type, *nfs_path;
            uint32_t nfs_addr;

            if (read_line(file, buf, sizeof (buf)) < 0)
                  break;

            split_string(buf, &device, &point, &type, NULL);
            if (!device || !point || !type || !strchr(device,':') || strcmp(type, "nfs") != 0)
                  continue;

            if (resolve_nfs(device, &nfs_addr, &nfs_path) < 0)
                  goto _err;

            if (r_addr != nfs_addr)
                  continue;

            if (strncmp(r_path, nfs_path, strlen(nfs_path)) != 0)
                  continue;

            /* addr and nfs_path match */

            if (sel.path) {
                  if (strlen(sel.nfs_path) < strlen(nfs_path))
                        continue;

                  free(sel.path);
            }

            sel.path = strdup(point);
            if (!sel.path) {
                  oom_error();
                  goto _err;
            }

            memset(sel.nfs_path, '\0', sizeof (sel.nfs_path));
            strncpy(sel.nfs_path, nfs_path, sizeof (sel.nfs_path) - 1);
      }

      fclose(file);

      if (sel.path)
            return sel.path;
      else
            return r_path;

_err:
      if (sel.path)
            free(sel.path);

      fclose(file);

      return NULL;
}

static char *scratchbox_path_alias(const char *const path)
{
      const char *const scratchbox = "/scratchbox/";
      const size_t scratchbox_len = strlen(scratchbox);

      char *alias, *renamed;
      size_t alias_len, renamed_len;

      alias = getenv("_SBOX_DIR");
      if (!alias)
            return NULL;

      alias_len = strlen(alias);
      if (alias_len <= 1 || strncmp(path, alias, alias_len) != 0)
            return NULL;

      renamed_len = strlen(path) - alias_len + scratchbox_len + 1;
      renamed = malloc(renamed_len);
      if (!renamed) {
            oom_error();
            return NULL;
      }

      strcpy(renamed, scratchbox);
      strcat(renamed, path + alias_len);

      return renamed;
}

/**
 * Fills in the device_dev field of mount_info_t.
 */
int mntinfo_stat_device(mount_info_t *mi)
{
      char *nfs_path, *path, *renamed_path;
      uint32_t nfs_addr;
      struct stat buf;
      int rc;

      if (resolve_nfs(mi->device, &nfs_addr, &nfs_path) < 0)
            return -1;

      path = get_local_path(nfs_addr, nfs_path);
      if (!path)
            return -1;

      renamed_path = scratchbox_path_alias(path);
      if (renamed_path) {
            if (path != nfs_path)
                  free(path);

            path = renamed_path;
      }

      rc = stat(path, &buf);
      if (rc >= 0)
            mi->device_dev = buf.st_dev;
      else
            error("Can't stat %s", path);

      if (path != nfs_path)
            free(path);

      return rc;
}

/**
 * Bubble sort based on mount point string.
 */
void mntinfo_sort_vec(mount_info_t **vec)
{
      mount_info_t **p, *tmp;
      bool_t touched;

      if (!vec[0] || !vec[1])
            return;

      do {
            touched = FALSE;

            for (p = vec; p[1]; ++p)
                  if (strcmp(p[0]->point, p[1]->point) > 0) {
                        tmp = p[0];
                        p[0] = p[1];
                        p[1] = tmp;

                        touched = TRUE;
                  }

      } while (touched);
}

Generated by  Doxygen 1.6.0   Back to index