Logo Search packages:      
Sourcecode: freebsd-utils version File versions

geom.c

/*-
 * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sbin/geom/core/geom.c,v 1.32.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $");

#include <sys/param.h>
#include <sys/linker.h>
#include <sys/module.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <libutil.h>
#include <inttypes.h>
#include <dlfcn.h>
#include <assert.h>
#include <libgeom.h>
#include <geom.h>

#include "misc/subr.h"


static char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL;
static uint32_t *version = NULL;
static int verbose = 0;
static struct g_command *class_commands = NULL;

#define     GEOM_CLASS_CMDS   0x01
#define     GEOM_STD_CMDS     0x02
static struct g_command *find_command(const char *cmdstr, int flags);
static int std_available(const char *name);

static void std_help(struct gctl_req *req, unsigned flags);
static void std_list(struct gctl_req *req, unsigned flags);
static void std_status(struct gctl_req *req, unsigned flags);
static void std_load(struct gctl_req *req, unsigned flags);
static void std_unload(struct gctl_req *req, unsigned flags);

struct g_command std_commands[] = {
      { "help", 0, std_help, G_NULL_OPTS, NULL, NULL },
      { "list", 0, std_list, G_NULL_OPTS, NULL, 
          "[name ...]"
      },
      { "status", 0, std_status,
          {
            { 's', "script", NULL, G_TYPE_BOOL },
            G_OPT_SENTINEL
          },
          NULL, "[-s] [name ...]"
      },
      { "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS,
          NULL, NULL },
      { "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS, NULL, NULL },
      G_CMD_SENTINEL
};

static void
usage_command(struct g_command *cmd, const char *prefix)
{
      struct g_option *opt;
      unsigned i;

      fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
      if (cmd->gc_usage != NULL) {
            fprintf(stderr, " %s\n", cmd->gc_usage);
            return;
      }
      if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
            fprintf(stderr, " [-v]");
      for (i = 0; ; i++) {
            opt = &cmd->gc_options[i];
            if (opt->go_name == NULL)
                  break;
            if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
                  fprintf(stderr, " [");
            else
                  fprintf(stderr, " ");
            fprintf(stderr, "-%c", opt->go_char);
            if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
                  fprintf(stderr, " %s", opt->go_name);
            if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
                  fprintf(stderr, "]");
      }
      if (cmd->gc_argname)
            fprintf(stderr, " %s", cmd->gc_argname);
      fprintf(stderr, "\n");
}

static void
usage(void)
{

      if (class_name == NULL) {
            errx(EXIT_FAILURE, "usage: %s <class> <command> [options]",
                "geom");
      } else {
            struct g_command *cmd;
            const char *prefix;
            unsigned i;

            prefix = "usage:";
            if (class_commands != NULL) {
                  for (i = 0; ; i++) {
                        cmd = &class_commands[i];
                        if (cmd->gc_name == NULL)
                              break;
                        usage_command(cmd, prefix);
                        prefix = "      ";
                  }
            }
            for (i = 0; ; i++) {
                  cmd = &std_commands[i];
                  if (cmd->gc_name == NULL)
                        break;
                  /*
                   * If class defines command, which has the same name as
                   * standard command, skip it, because it was already
                   * shown on usage().
                   */
                  if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL)
                        continue;
                  usage_command(cmd, prefix);
                  prefix = "      ";
            }
            exit(EXIT_FAILURE);
      }
}

static void
load_module(void)
{
      char name1[64], name2[64];

      snprintf(name1, sizeof(name1), "g_%s", class_name);
      snprintf(name2, sizeof(name2), "geom_%s", class_name);
      if (modfind(name1) < 0) {
            /* Not present in kernel, try loading it. */
            if (kldload(name2) < 0 || modfind(name1) < 0) {
                  if (errno != EEXIST) {
                        errx(EXIT_FAILURE,
                            "%s module not available!", name2);
                  }
            }
      }
}

static int
strlcatf(char *str, size_t size, const char *format, ...)
{
      size_t len;
      va_list ap;
      int ret;

      len = strlen(str);
      str += len;
      size -= len;

      va_start(ap, format);
      ret = vsnprintf(str, size, format, ap);
      va_end(ap);

      return (ret);
}

/*
 * Find given option in options available for given command.
 */
static struct g_option *
find_option(struct g_command *cmd, char ch)
{
      struct g_option *opt;
      unsigned i;

      for (i = 0; ; i++) {
            opt = &cmd->gc_options[i];
            if (opt->go_name == NULL)
                  return (NULL);
            if (opt->go_char == ch)
                  return (opt);
      }
      /* NOTREACHED */
      return (NULL);
}

/*
 * Add given option to gctl_req.
 */
static void
set_option(struct gctl_req *req, struct g_option *opt, const char *val)
{

      if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
            intmax_t number;

            if (expand_number(val, &number) == -1) {
                  err(EXIT_FAILURE, "Invalid value for '%c' argument.",
                      opt->go_char);
            }
            opt->go_val = malloc(sizeof(intmax_t));
            if (opt->go_val == NULL)
                  errx(EXIT_FAILURE, "No memory.");
            *(intmax_t *)opt->go_val = number;

            gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val);
      } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
            gctl_ro_param(req, opt->go_name, -1, val);
      } else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
            opt->go_val = malloc(sizeof(int));
            if (opt->go_val == NULL)
                  errx(EXIT_FAILURE, "No memory.");
            *(int *)opt->go_val = *val - '0';

            gctl_ro_param(req, opt->go_name, sizeof(int),
                opt->go_val);
      } else {
            assert(!"Invalid type");
      }
}

/*
 * 1. Add given argument by caller.
 * 2. Add default values of not given arguments.
 * 3. Add the rest of arguments.
 */
static void
parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
    char ***argv)
{
      struct g_option *opt;
      char opts[64];
      unsigned i;
      int ch;

      *opts = '\0';
      if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
            strlcat(opts, "v", sizeof(opts));
      for (i = 0; ; i++) {
            opt = &cmd->gc_options[i];
            if (opt->go_name == NULL)
                  break;
            assert(G_OPT_TYPE(opt) != 0);
            assert((opt->go_type & ~G_TYPE_MASK) == 0);
            strlcatf(opts, sizeof(opts), "%c", opt->go_char);
            if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
                  strlcat(opts, ":", sizeof(opts));
      }

      /*
       * Add specified arguments.
       */
      while ((ch = getopt(*argc, *argv, opts)) != -1) {
            /* Standard (not passed to kernel) options. */
            switch (ch) {
            case 'v':
                  verbose = 1;
                  continue;
            }
            /* Options passed to kernel. */
            opt = find_option(cmd, ch);
            if (opt == NULL)
                  usage();
            if (G_OPT_ISDONE(opt)) {
                  warnx("Option '%c' specified twice.", opt->go_char);
                  usage();
            }
            G_OPT_DONE(opt);

            if (G_OPT_TYPE(opt) == G_TYPE_BOOL)
                  set_option(req, opt, "1");
            else
                  set_option(req, opt, optarg);
      }
      *argc -= optind;
      *argv += optind;

      /*
       * Add not specified arguments, but with default values.
       */
      for (i = 0; ; i++) {
            opt = &cmd->gc_options[i];
            if (opt->go_name == NULL)
                  break;
            if (G_OPT_ISDONE(opt))
                  continue;

            if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
                  assert(opt->go_val == NULL);
                  set_option(req, opt, "0");
            } else {
                  if (opt->go_val == NULL) {
                        warnx("Option '%c' not specified.",
                            opt->go_char);
                        usage();
                  } else {
                        if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
                              gctl_ro_param(req, opt->go_name,
                                  sizeof(intmax_t), opt->go_val);
                        } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
                              if (cmd->gc_argname == NULL ||
                                  opt->go_val == NULL ||
                                  *(char *)opt->go_val != '\0')
                                    gctl_ro_param(req, opt->go_name,
                                        -1, opt->go_val);
                        } else {
                              assert(!"Invalid type");
                        }
                  }
            }
      }

      if (cmd->gc_argname == NULL) {
            /*
             * Add rest of given arguments.
             */
            gctl_ro_param(req, "nargs", sizeof(int), argc);
            for (i = 0; i < (unsigned)*argc; i++) {
                  char argname[16];

                  snprintf(argname, sizeof(argname), "arg%u", i);
                  gctl_ro_param(req, argname, -1, (*argv)[i]);
            }
      } else {
            if (*argc != 1)
                  usage();
            gctl_ro_param(req, cmd->gc_argname, -1, (*argv)[0]);
      }
}

/*
 * Find given command in commands available for given class.
 */
static struct g_command *
find_command(const char *cmdstr, int flags)
{
      struct g_command *cmd;
      unsigned i;

      /*
       * First try to find command defined by loaded library.
       */
      if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) {
            for (i = 0; ; i++) {
                  cmd = &class_commands[i];
                  if (cmd->gc_name == NULL)
                        break;
                  if (strcmp(cmd->gc_name, cmdstr) == 0)
                        return (cmd);
            }
      }
      /*
       * Now try to find in standard commands.
       */
      if ((flags & GEOM_STD_CMDS) != 0) {
            for (i = 0; ; i++) {
                  cmd = &std_commands[i];
                  if (cmd->gc_name == NULL)
                        break;
                  if (strcmp(cmd->gc_name, cmdstr) == 0)
                        return (cmd);
            }
      }
      return (NULL);
}

static unsigned
set_flags(struct g_command *cmd)
{
      unsigned flags = 0;

      if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
            flags |= G_FLAG_VERBOSE;

      return (flags);
}

/*
 * Run command.
 */
static void
run_command(int argc, char *argv[])
{
      struct g_command *cmd;
      struct gctl_req *req;
      const char *errstr;
      char buf[4096];

      /* First try to find a command defined by a class. */
      cmd = find_command(argv[0], GEOM_CLASS_CMDS);
      if (cmd == NULL) {
            /* Now, try to find a standard command. */
            cmd = find_command(argv[0], GEOM_STD_CMDS);
            if (cmd == NULL) {
                  warnx("Unknown command: %s.", argv[0]);
                  usage();
            }
            if (!std_available(cmd->gc_name)) {
                  warnx("Command '%s' not available.", argv[0]);
                  exit(EXIT_FAILURE);
            }
      }
      if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
            load_module();

      req = gctl_get_handle();
      gctl_ro_param(req, "class", -1, gclass_name);
      gctl_ro_param(req, "verb", -1, argv[0]);
      if (version != NULL)
            gctl_ro_param(req, "version", sizeof(*version), version);
      parse_arguments(cmd, req, &argc, &argv);

      bzero(buf, sizeof(buf));
      if (cmd->gc_func != NULL) {
            unsigned flags;

            flags = set_flags(cmd);
            cmd->gc_func(req, flags);
            errstr = req->error;
      } else {
            gctl_rw_param(req, "output", sizeof(buf), buf);
            errstr = gctl_issue(req);
      }
      if (errstr != NULL && errstr[0] != '\0') {
            warnx("%s", errstr);
            if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) {
                  gctl_free(req);
                  exit(EXIT_FAILURE);
            }
      }
      if (buf[0] != '\0')
            printf("%s", buf);
      gctl_free(req);
      if (verbose)
            printf("Done.\n");
      exit(EXIT_SUCCESS);
}

static const char *
library_path(void)
{
      const char *path;

      path = getenv("GEOM_LIBRARY_PATH");
      if (path == NULL)
            path = CLASS_DIR;
      return (path);
}

static void
load_library(void)
{
      char *curpath, path[MAXPATHLEN], *totalpath;
      uint32_t *lib_version;
      void *dlh;
      int ret;

      ret = 0;
      totalpath = strdup(library_path());
      if (totalpath == NULL)
            err(EXIT_FAILURE, "Not enough memory for library path");

      if (strchr(totalpath, ':') != NULL)
            curpath = strsep(&totalpath, ":");
      else
            curpath = totalpath;
      /* Traverse the paths to find one that contains the library we want. */
      while (curpath != NULL) {
            snprintf(path, sizeof(path), "%s/geom_%s.so", curpath,
                class_name);
            ret = access(path, F_OK);
            if (ret == -1) {
                  if (errno == ENOENT) {
                        /*
                         * If we cannot find library, try the next
                         * path.
                         */
                        curpath = strsep(&totalpath, ":");
                        continue;
                  }
                  err(EXIT_FAILURE, "Cannot access library");
            }
            break;
      }
      free(totalpath);
      /* No library was found, but standard commands can still be used */
      if (ret == -1)
            return;
      dlh = dlopen(path, RTLD_NOW);
      if (dlh == NULL)
            errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
      lib_version = dlsym(dlh, "lib_version");
      if (lib_version == NULL) {
            warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
            dlclose(dlh);
            exit(EXIT_FAILURE);
      }
      if (*lib_version != G_LIB_VERSION) {
            dlclose(dlh);
            errx(EXIT_FAILURE, "%s and %s are not synchronized.",
                getprogname(), path);
      }
      version = dlsym(dlh, "version");
      if (version == NULL) {
            warnx("Cannot find symbol %s: %s.", "version", dlerror());
            dlclose(dlh);
            exit(EXIT_FAILURE);
      }
      class_commands = dlsym(dlh, "class_commands");
      if (class_commands == NULL) {
            warnx("Cannot find symbol %s: %s.", "class_commands",
                dlerror());
            dlclose(dlh);
            exit(EXIT_FAILURE);
      }
}

/*
 * Class name should be all capital letters.
 */
static void
set_class_name(void)
{
      char *s1, *s2;

      s1 = class_name;
      for (; *s1 != '\0'; s1++)
            *s1 = tolower(*s1);
      gclass_name = malloc(strlen(class_name) + 1);
      if (gclass_name == NULL)
            errx(EXIT_FAILURE, "No memory");
      s1 = gclass_name;
      s2 = class_name;
      for (; *s2 != '\0'; s2++)
            *s1++ = toupper(*s2);
      *s1 = '\0';
}

static void
get_class(int *argc, char ***argv)
{

      snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
      if (strcmp(comm, "geom") == 0) {
            if (*argc < 2)
                  usage();
            else if (*argc == 2) {
                  if (strcmp((*argv)[1], "-h") == 0 ||
                      strcmp((*argv)[1], "help") == 0) {
                        usage();
                  }
            }
            strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
            class_name = (*argv)[1];
            *argc -= 2;
            *argv += 2;
      } else if (*comm == 'g') {
            class_name = comm + 1;
            *argc -= 1;
            *argv += 1;
      } else {
            errx(EXIT_FAILURE, "Invalid utility name.");
      }
      set_class_name();
      load_library();
      if (*argc < 1)
            usage();
}

int
main(int argc, char *argv[])
{

      get_class(&argc, &argv);
      run_command(argc, argv);
      /* NOTREACHED */

      exit(EXIT_FAILURE);
}

static struct gclass *
find_class(struct gmesh *mesh, const char *name)
{
      struct gclass *classp;

      LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
            if (strcmp(classp->lg_name, name) == 0)
                  return (classp);
      }
      return (NULL);
}

static struct ggeom *
find_geom(struct gclass *classp, const char *name)
{
      struct ggeom *gp;

      LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
            if (strcmp(gp->lg_name, name) == 0)
                  return (gp);
      }
      return (NULL);
}

static void
list_one_provider(struct gprovider *pp, const char *prefix)
{
      struct gconfig *conf;
      char buf[5];

      printf("Name: %s\n", pp->lg_name);
      humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
          HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
      printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
          buf);
      printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
      printf("%sMode: %s\n", prefix, pp->lg_mode);
      LIST_FOREACH(conf, &pp->lg_config, lg_config) {
            printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
      }
}

static void
list_one_consumer(struct gconsumer *cp, const char *prefix)
{
      struct gprovider *pp;
      struct gconfig *conf;

      pp = cp->lg_provider;
      if (pp == NULL)
            printf("[no provider]\n");
      else {
            char buf[5];

            printf("Name: %s\n", pp->lg_name);
            humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
                HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
            printf("%sMediasize: %jd (%s)\n", prefix,
                (intmax_t)pp->lg_mediasize, buf);
            printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
            printf("%sMode: %s\n", prefix, cp->lg_mode);
      }
      LIST_FOREACH(conf, &cp->lg_config, lg_config) {
            printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
      }
}

static void
list_one_geom(struct ggeom *gp)
{
      struct gprovider *pp;
      struct gconsumer *cp;
      struct gconfig *conf;
      unsigned n;

      printf("Geom name: %s\n", gp->lg_name);
      LIST_FOREACH(conf, &gp->lg_config, lg_config) {
            printf("%s: %s\n", conf->lg_name, conf->lg_val);
      }
      if (!LIST_EMPTY(&gp->lg_provider)) {
            printf("Providers:\n");
            n = 1;
            LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
                  printf("%u. ", n++);
                  list_one_provider(pp, "   ");
            }
      }
      if (!LIST_EMPTY(&gp->lg_consumer)) {
            printf("Consumers:\n");
            n = 1;
            LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
                  printf("%u. ", n++);
                  list_one_consumer(cp, "   ");
            }
      }
      printf("\n");
}

static void
std_help(struct gctl_req *req __unused, unsigned flags __unused)
{

      usage();
}

static int
std_list_available(void)
{
      struct gmesh mesh;
      struct gclass *classp;
      int error;

      error = geom_gettree(&mesh);
      if (error != 0)
            errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
      classp = find_class(&mesh, gclass_name);
      geom_deletetree(&mesh);
      if (classp != NULL)
            return (1);
      return (0);
}

static void
std_list(struct gctl_req *req, unsigned flags __unused)
{
      struct gmesh mesh;
      struct gclass *classp;
      struct ggeom *gp;
      const char *name;
      int error, i, nargs;

      error = geom_gettree(&mesh);
      if (error != 0)
            errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
      classp = find_class(&mesh, gclass_name);
      if (classp == NULL) {
            geom_deletetree(&mesh);
            errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
      }
      nargs = gctl_get_int(req, "nargs");
      if (nargs > 0) {
            for (i = 0; i < nargs; i++) {
                  name = gctl_get_ascii(req, "arg%d", i);
                  gp = find_geom(classp, name);
                  if (gp != NULL)
                        list_one_geom(gp);
                  else
                        errx(EXIT_FAILURE, "No such geom: %s.", name);
            }
      } else {
            LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
                  if (LIST_EMPTY(&gp->lg_provider))
                        continue;
                  list_one_geom(gp);
            }
      }
      geom_deletetree(&mesh);
}

static int
std_status_available(void)
{

      /* 'status' command is available when 'list' command is. */
      return (std_list_available());
}

static void
status_update_len(struct ggeom *gp, int *name_len, int *status_len)
{
      struct gprovider *pp;
      struct gconfig *conf;
      int len;

      assert(gp != NULL);
      assert(name_len != NULL);
      assert(status_len != NULL);

      pp = LIST_FIRST(&gp->lg_provider);
      if (pp != NULL)
            len = strlen(pp->lg_name);
      else
            len = strlen(gp->lg_name);
      if (*name_len < len)
            *name_len = len;
      LIST_FOREACH(conf, &gp->lg_config, lg_config) {
            if (strcasecmp(conf->lg_name, "state") == 0) {
                  len = strlen(conf->lg_val);
                  if (*status_len < len)
                        *status_len = len;
            }
      }
}

static char *
status_one_consumer(struct gconsumer *cp)
{
      static char buf[256];
      struct gprovider *pp;
      struct gconfig *conf;

      pp = cp->lg_provider;
      if (pp == NULL)
            return (NULL);
      LIST_FOREACH(conf, &cp->lg_config, lg_config) {
            if (strcasecmp(conf->lg_name, "synchronized") == 0)
                  break;
      }
      if (conf == NULL)
            snprintf(buf, sizeof(buf), "%s", pp->lg_name);
      else {
            snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
                conf->lg_val);
      }
      return (buf);
}

static void
status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
{
      struct gprovider *pp;
      struct gconsumer *cp;
      struct gconfig *conf;
      const char *name, *status, *component;
      int gotone;

      pp = LIST_FIRST(&gp->lg_provider);
      if (pp != NULL)
            name = pp->lg_name;
      else
            name = gp->lg_name;
      LIST_FOREACH(conf, &gp->lg_config, lg_config) {
            if (strcasecmp(conf->lg_name, "state") == 0)
                  break;
      }
      if (conf == NULL)
            status = "N/A";
      else
            status = conf->lg_val;
      gotone = 0;
      LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
            component = status_one_consumer(cp);
            if (component == NULL)
                  continue;
            gotone = 1;
            printf("%*s  %*s  %s\n", name_len, name, status_len, status,
                component);
            if (!script)
                  name = status = "";
      }
      if (!gotone) {
            printf("%*s  %*s  %s\n", name_len, name, status_len, status,
                "N/A");
      }
}

static void
std_status(struct gctl_req *req, unsigned flags __unused)
{
      struct gmesh mesh;
      struct gclass *classp;
      struct ggeom *gp;
      const char *name;
      int name_len, status_len;
      int error, i, n, nargs, script;

      error = geom_gettree(&mesh);
      if (error != 0)
            errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
      classp = find_class(&mesh, gclass_name);
      if (classp == NULL)
            errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
      nargs = gctl_get_int(req, "nargs");
      script = gctl_get_int(req, "script");
      name_len = strlen("Name");
      status_len = strlen("Status");
      if (nargs > 0) {
            for (i = 0, n = 0; i < nargs; i++) {
                  name = gctl_get_ascii(req, "arg%d", i);
                  gp = find_geom(classp, name);
                  if (gp == NULL)
                        errx(EXIT_FAILURE, "No such geom: %s.", name);
                  else {
                        status_update_len(gp, &name_len, &status_len);
                        n++;
                  }
            }
            if (n == 0)
                  goto end;
      } else {
            n = 0;
            LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
                  if (LIST_EMPTY(&gp->lg_provider))
                        continue;
                  status_update_len(gp, &name_len, &status_len);
                  n++;
            }
            if (n == 0)
                  goto end;
      }
      if (!script) {
            printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
                "Components");
      }
      if (nargs > 0) {
            for (i = 0; i < nargs; i++) {
                  name = gctl_get_ascii(req, "arg%d", i);
                  gp = find_geom(classp, name);
                  if (gp != NULL) {
                        status_one_geom(gp, script, name_len,
                            status_len);
                  }
            }
      } else {
            LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
                  if (LIST_EMPTY(&gp->lg_provider))
                        continue;
                  status_one_geom(gp, script, name_len, status_len);
            }
      }
end:
      geom_deletetree(&mesh);
}

static int
std_load_available(void)
{
      char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
      struct stat sb;
      size_t len;

      snprintf(name, sizeof(name), "g_%s", class_name);
      /*
       * If already in kernel, "load" command is not available.
       */
      if (modfind(name) >= 0)
            return (0);
      bzero(paths, sizeof(paths));
      len = sizeof(paths);
      if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
            err(EXIT_FAILURE, "sysctl(kern.module_path)");
      for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
            snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
            /*
             * If geom_<name>.ko file exists, "load" command is available.
             */
            if (stat(name, &sb) == 0)
                  return (1);
      }
      return (0);
}

static void
std_load(struct gctl_req *req __unused, unsigned flags)
{

      /*
       * Do nothing special here, because of G_FLAG_LOADKLD flag,
       * module is already loaded.
       */
      if ((flags & G_FLAG_VERBOSE) != 0)
            printf("Module available.\n");
}

static int
std_unload_available(void)
{
      char name[64];
      int id;

      snprintf(name, sizeof(name), "geom_%s", class_name);
      id = kldfind(name);
      if (id >= 0)
            return (1);
      return (0);
}

static void
std_unload(struct gctl_req *req, unsigned flags __unused)
{
      char name[64];
      int id;

      snprintf(name, sizeof(name), "geom_%s", class_name);
      id = kldfind(name);
      if (id < 0) {
            gctl_error(req, "Could not find module: %s.", strerror(errno));
            return;
      }
      if (kldunload(id) < 0) {
            gctl_error(req, "Could not unload module: %s.",
                strerror(errno));
            return;
      }
}

static int
std_available(const char *name)
{

      if (strcmp(name, "help") == 0)
            return (1);
      else if (strcmp(name, "list") == 0)
            return (std_list_available());
      else if (strcmp(name, "status") == 0)
            return (std_status_available());
      else if (strcmp(name, "load") == 0)
            return (std_load_available());
      else if (strcmp(name, "unload") == 0)
            return (std_unload_available());
      else
            assert(!"Unknown standard command.");
      return (0);
}

Generated by  Doxygen 1.6.0   Back to index