diff options
author | Richard Jones <rjones@trick.home.annexia.org> | 2009-07-15 11:39:04 +0100 |
---|---|---|
committer | Richard Jones <rjones@trick.home.annexia.org> | 2009-07-15 11:39:04 +0100 |
commit | 9449b0fce4145a56df9d43169d61e8b2c4e41b09 (patch) | |
tree | 02b52334c5712ab9ef98414807db03dc71ea3320 /fish | |
parent | 1d29b4e40bed1145e2ca359bda62d5aa218dbc41 (diff) | |
download | libguestfs-9449b0fce4145a56df9d43169d61e8b2c4e41b09.tar.gz libguestfs-9449b0fce4145a56df9d43169d61e8b2c4e41b09.tar.xz libguestfs-9449b0fce4145a56df9d43169d61e8b2c4e41b09.zip |
guestfish: Add tilde expansion for paths (RHBZ#511372).
This commit adds tilde expansion for local users in guestfish:
><fs> echo "~"
~
><fs> echo ~
/home/rjones
><fs> echo ~foo
~foo
><fs> echo ~rjones/bar
/home/rjones/bar
><fs> echo ~roo
~roo
><fs> echo ~root/foo
/root/foo
><fs> echo ~root
/root
Diffstat (limited to 'fish')
-rw-r--r-- | fish/Makefile.am | 1 | ||||
-rw-r--r-- | fish/fish.c | 14 | ||||
-rw-r--r-- | fish/fish.h | 3 | ||||
-rw-r--r-- | fish/tilde.c | 121 |
4 files changed, 138 insertions, 1 deletions
diff --git a/fish/Makefile.am b/fish/Makefile.am index dd793612..9ec0cf49 100644 --- a/fish/Makefile.am +++ b/fish/Makefile.am @@ -36,6 +36,7 @@ guestfish_SOURCES = \ rc_protocol.c \ rc_protocol.h \ reopen.c \ + tilde.c \ time.c BUILT_SOURCES = \ diff --git a/fish/fish.c b/fish/fish.c index 4042bbcf..f5d538d1 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -514,6 +514,7 @@ script (int prompt) char *argv[64]; int i, len; int global_exit_on_error = !prompt; + int tilde_candidate; if (prompt) printf (_("\n" @@ -587,6 +588,8 @@ script (int prompt) /* Get the parameters. */ while (*p && i < sizeof argv / sizeof argv[0]) { + tilde_candidate = 0; + /* Parameters which start with quotes or pipes are treated * specially. Bare parameters are delimited by whitespace. */ @@ -647,6 +650,11 @@ script (int prompt) *(pend-1) = '\0'; */ } else if (*p != ' ' && *p != '\t') { + /* If the first character is a ~ then note that this parameter + * is a candidate for ~username expansion. NB this does not + * apply to quoted parameters. + */ + tilde_candidate = *p == '~'; len = strcspn (p, " \t"); if (p[len]) { p[len] = '\0'; @@ -659,7 +667,11 @@ script (int prompt) abort (); } - argv[i++] = p; + if (!tilde_candidate) + argv[i] = p; + else + argv[i] = try_tilde_expansion (p); + i++; p = pend; if (*p) diff --git a/fish/fish.h b/fish/fish.h index f911eed7..59f2e10a 100644 --- a/fish/fish.h +++ b/fish/fish.h @@ -88,6 +88,9 @@ extern int do_reopen (const char *cmd, int argc, char *argv[]); /* in time.c */ extern int do_time (const char *cmd, int argc, char *argv[]); +/* in tilde.c */ +extern char *try_tilde_expansion (char *path); + /* This should just list all the built-in commands so they can * be added to the generated auto-completion code. */ diff --git a/fish/tilde.c b/fish/tilde.c new file mode 100644 index 00000000..13e6cd8f --- /dev/null +++ b/fish/tilde.c @@ -0,0 +1,121 @@ +/* guestfish - the filesystem interactive shell + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <assert.h> +#include <pwd.h> +#include <sys/types.h> + +#include "fish.h" + +static char *expand_home (const char *); +static const char *find_home_for_username (const char *, int); + +/* This is called from the script loop if we find a candidate for + * ~username (tilde-expansion). + */ +char * +try_tilde_expansion (char *str) +{ + assert (str[0] == '~'); + + /* Expand current user's home directory. By simple experimentation + * I found out that bash always uses $HOME. + */ + if (str[1] == '\0') /* ~ */ + return expand_home (NULL); + else if (str[1] == '/') /* ~/... */ + return expand_home (&str[1]); + + /* Try expanding the part up to the following '\0' or '/' as a + * username from the password file. + */ + else { + int len; + const char *home, *rest; + + len = strcspn (&str[1], "/"); + rest = &str[1+len]; + + home = find_home_for_username (&str[1], len); + + if (home) { + len = strlen (home) + strlen (rest); + str = malloc (len); + if (str == NULL) { + perror ("malloc"); + exit (1); + } + strcpy (str, home); + strcat (str, rest); + return str; + } + } + + /* No match, return the orignal string. */ + return str; +} + +/* Return $HOME + append string. */ +static char * +expand_home (const char *append) +{ + const char *home; + int len; + char *str; + + home = getenv ("HOME"); + if (!home) home = "~"; + + len = strlen (home) + (append ? strlen (append) : 0); + str = malloc (len); + if (str == NULL) { + perror ("malloc"); + exit (1); + } + + strcpy (str, home); + if (append) + strcat (str, append); + + return str; +} + +/* Lookup username (of length ulen), return home directory if found, + * or NULL if not found. + */ +static const char * +find_home_for_username (const char *username, int ulen) +{ + struct passwd *pw; + + setpwent (); + while ((pw = getpwent ()) != NULL) { + if (strlen (pw->pw_name) == ulen && + strncmp (username, pw->pw_name, ulen) == 0) + return pw->pw_dir; + } + + return NULL; +} |