Exemple #1
0
char *
complete_dest_paths_generator (const char *text, int state)
{
#ifdef HAVE_LIBREADLINE

  static size_t len, index;
  static struct word *words = NULL;
  static size_t nr_words = 0;
  guestfs_error_handler_cb old_error_cb;
  void *old_error_cb_data;

  /* Temporarily replace the error handler so that messages don't
   * get printed to stderr while we are issuing commands.
   */
#define SAVE_ERROR_CB							\
  old_error_cb = guestfs_get_error_handler (g, &old_error_cb_data);	\
  guestfs_set_error_handler (g, NULL, NULL);

  /* Restore error handler. */
#define RESTORE_ERROR_CB						\
  guestfs_set_error_handler (g, old_error_cb, old_error_cb_data);

  if (!state) {
    char **strs;

    len = strlen (text);
    index = 0;

    if (words) free_words (words, nr_words);

    words = NULL;
    nr_words = 0;

    SAVE_ERROR_CB

/* Silently do nothing if an allocation fails */
#define APPEND_STRS_AND_FREE						\
  do {									\
    if (strs) {								\
      size_t i;								\
      size_t n = count_strings (strs);					\
                                                                        \
      if ( n > 0 && ! xalloc_oversized (nr_words + n, sizeof (struct word))) { \
        struct word *w;							\
        w = realloc (words, sizeof (struct word) * (nr_words + n));	\
                                                                        \
        if (w == NULL) {						\
          free_words (words, nr_words);					\
          words = NULL;							\
          nr_words = 0;							\
        } else {							\
          words = w;							\
          for (i = 0; i < n; ++i) {					\
            words[nr_words].name = strs[i];				\
            words[nr_words].is_dir = 0;					\
            nr_words++;							\
          }								\
        }								\
      }									\
      free (strs);							\
    }									\
  } while (0)

    /* Is it a device? */
    if (len < 5 || STREQLEN (text, "/dev/", 5)) {
      /* Get a list of everything that can possibly begin with /dev/ */
      strs = guestfs_list_devices (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_partitions (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_lvs (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_dm_devices (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_md_devices (g);
      APPEND_STRS_AND_FREE;
    }

    if (len < 1 || text[0] == '/') {
      /* If we've got a partial path already, we need to list everything
       * in that directory, otherwise list everything in /
       */
      char *p, *dir;
      struct guestfs_dirent_list *dirents;

      p = strrchr (text, '/');
      dir = p && p > text ? strndup (text, p - text) : strdup ("/");
      if (dir) {
        dirents = guestfs_readdir (g, dir);

        /* Prepend directory to names before adding them to the list
         * of words.
         */
        if (dirents) {
          size_t i;

          for (i = 0; i < dirents->len; ++i) {
            int err;

            if (STRNEQ (dirents->val[i].name, ".") &&
                STRNEQ (dirents->val[i].name, "..")) {
              if (STREQ (dir, "/"))
                err = asprintf (&p, "/%s", dirents->val[i].name);
              else
                err = asprintf (&p, "%s/%s", dir, dirents->val[i].name);
              if (err >= 0) {
                if (!xalloc_oversized (nr_words+1, sizeof (struct word))) {
                  struct word *w;

                  w = realloc (words, sizeof (struct word) * (nr_words+1));
                  if (w == NULL) {
                    free_words (words, nr_words);
                    words = NULL;
                    nr_words = 0;
                  }
                  else {
                    words = w;
                    words[nr_words].name = p;
                    words[nr_words].is_dir = dirents->val[i].ftyp == 'd';
                    nr_words++;
                  }
                }
              }
            }
          }

          guestfs_free_dirent_list (dirents);
        }
      }
    }

    /* else ...  In theory we could complete other things here such as VG
     * names.  At the moment we don't do that.
     */

    RESTORE_ERROR_CB
  }
Exemple #2
0
char *
complete_dest_paths_generator (const char *text, int state)
{
#ifdef HAVE_LIBREADLINE

  static size_t len, index;
  static struct word *words = NULL;
  static size_t nr_words = 0;

  if (!state) {
    char **strs;

    len = strlen (text);
    index = 0;

    if (words) free_words (words, nr_words);

    words = NULL;
    nr_words = 0;

    guestfs_push_error_handler (g, NULL, NULL);

/* Silently do nothing if an allocation fails */
#define APPEND_STRS_AND_FREE						\
  do {									\
    if (strs) {								\
      size_t i;								\
      size_t n = count_strings (strs);					\
                                                                        \
      if ( n > 0 && ! xalloc_oversized (nr_words + n, sizeof (struct word))) { \
        struct word *w;							\
        w = realloc (words, sizeof (struct word) * (nr_words + n));	\
                                                                        \
        if (w == NULL) {						\
          free_words (words, nr_words);					\
          words = NULL;							\
          nr_words = 0;							\
        } else {							\
          words = w;							\
          for (i = 0; i < n; ++i) {					\
            words[nr_words].name = strs[i];				\
            words[nr_words].is_dir = 0;					\
            nr_words++;							\
          }								\
        }								\
      }									\
      free (strs);							\
    }									\
  } while (0)

    /* Is it a device? */
    if (len < 5 || STREQLEN (text, "/dev/", 5)) {
      /* Get a list of everything that can possibly begin with /dev/ */
      strs = guestfs_list_devices (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_partitions (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_lvs (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_dm_devices (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_md_devices (g);
      APPEND_STRS_AND_FREE;
    }

    if (len < 1 || text[0] == '/') {
      /* If we've got a partial path already, we need to list everything
       * in that directory, otherwise list everything in /
       */
      char *p, *dir;
      struct guestfs_dirent_list *dirents;

      p = strrchr (text, '/');
      dir = p && p > text ? strndup (text, p - text) : strdup ("/");
      if (dir) {
        dirents = guestfs_readdir (g, dir);

        /* Prepend directory to names before adding them to the list
         * of words.
         */
        if (dirents) {
          size_t i;

          for (i = 0; i < dirents->len; ++i) {
            int err;

            if (STRNEQ (dirents->val[i].name, ".") &&
                STRNEQ (dirents->val[i].name, "..")) {
              if (STREQ (dir, "/"))
                err = asprintf (&p, "/%s", dirents->val[i].name);
              else
                err = asprintf (&p, "%s/%s", dir, dirents->val[i].name);
              if (err >= 0) {
                if (!xalloc_oversized (nr_words+1, sizeof (struct word))) {
                  struct word *w;

                  w = realloc (words, sizeof (struct word) * (nr_words+1));
                  if (w == NULL) {
                    free_words (words, nr_words);
                    words = NULL;
                    nr_words = 0;
                  }
                  else {
                    words = w;
                    words[nr_words].name = p;
                    words[nr_words].is_dir = dirents->val[i].ftyp == 'd';
                    nr_words++;
                  }
                }
              }
            }
          }

          guestfs_free_dirent_list (dirents);
        }
      }
    }

    /* else ...  In theory we could complete other things here such as VG
     * names.  At the moment we don't do that.
     */

    guestfs_pop_error_handler (g);
  }

  /* This inhibits ordinary (local filename) completion. */
  rl_attempted_completion_over = 1;

  /* Sort the words so the list is stable over multiple calls. */
  if (words)
    qsort (words, nr_words, sizeof (struct word), compare_words);

  /* Complete the string. */
  while (index < nr_words) {
    struct word *word;

    word = &words[index];
    index++;

    /* Whether we should match case insensitively here or not is
     * determined by the value of the completion-ignore-case readline
     * variable.  Default to case insensitive.  (See: RHBZ#582993).
     */
    char *cic_var = rl_variable_value ("completion-ignore-case");
    int cic = 1;
    if (cic_var && STREQ (cic_var, "off"))
      cic = 0;

    int matches =
      cic ? STRCASEEQLEN (word->name, text, len)
          : STREQLEN (word->name, text, len);

    if (matches) {
      if (word->is_dir)
        rl_completion_append_character = '/';

      return strdup (word->name);
    }
  }

#endif /* HAVE_LIBREADLINE */

  return NULL;
}