X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=fish%2Ffish.c;h=2ddf9013e1b5b34fed501e601d771680d83b02c0;hp=5e8a6e9e80ea4e05f279435aa3440564d38cc463;hb=b48dea6217920ef26e4745a9797c07a21407574f;hpb=b96fb7eb3aa0ac67957ed15a7dd22bc7399cad44 diff --git a/fish/fish.c b/fish/fish.c index 5e8a6e9..2ddf901 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -1,5 +1,5 @@ /* guestfish - the filesystem interactive shell - * Copyright (C) 2009 Red Hat Inc. + * 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 @@ -29,6 +29,8 @@ #include #include #include +#include +#include #ifdef HAVE_LIBREADLINE #include @@ -138,9 +140,15 @@ main (int argc, char *argv[]) struct mp *mp; char *p, *file = NULL; int c, inspector = 0; + struct sigaction sa; initialize_readline (); + memset (&sa, 0, sizeof sa); + sa.sa_handler = SIG_IGN; + sa.sa_flags = SA_RESTART; + sigaction (SIGPIPE, &sa, NULL); + /* guestfs_create is meant to be a lightweight operation, so * it's OK to do it early here. */ @@ -462,6 +470,8 @@ script (int prompt) "\n")); while (!quit) { + char *pipe = NULL; + exit_on_error = global_exit_on_error; buf = rl_gets (prompt); @@ -522,9 +532,8 @@ script (int prompt) /* Get the parameters. */ while (*p && i < sizeof argv / sizeof argv[0]) { - /* Parameters which start with quotes or square brackets - * are treated specially. Bare parameters are delimited - * by whitespace. + /* Parameters which start with quotes or pipes are treated + * specially. Bare parameters are delimited by whitespace. */ if (*p == '"') { p++; @@ -556,6 +565,10 @@ script (int prompt) } p[len] = '\0'; pend = p[len+1] ? &p[len+2] : &p[len+1]; + } else if (*p == '|') { + *p = '\0'; + pipe = p+1; + continue; /* } else if (*p == '[') { int c = 1; @@ -607,7 +620,7 @@ script (int prompt) argv[i] = NULL; got_command: - if (issue_command (cmd, argv) == -1) { + if (issue_command (cmd, argv, pipe) == -1) { if (exit_on_error) exit (1); } @@ -636,18 +649,51 @@ cmdline (char *argv[], int optind, int argc) optind++; if (optind == argc) { - if (issue_command (cmd, params) == -1) exit (1); + if (issue_command (cmd, params, NULL) == -1) exit (1); } else { argv[optind] = NULL; - if (issue_command (cmd, params) == -1) exit (1); + if (issue_command (cmd, params, NULL) == -1) exit (1); cmdline (argv, optind+1, argc); } } int -issue_command (const char *cmd, char *argv[]) +issue_command (const char *cmd, char *argv[], const char *pipecmd) { int argc; + int stdout_saved_fd = -1; + int pid = 0; + int r; + + /* For | ... commands. Annoyingly we can't use popen(3) here. */ + if (pipecmd) { + int fd[2]; + + fflush (stdout); + pipe (fd); + pid = fork (); + if (pid == -1) { + perror ("fork"); + return -1; + } + + if (pid == 0) { /* Child process. */ + close (fd[1]); + dup2 (fd[0], 0); + + r = system (pipecmd); + if (r == -1) { + perror (pipecmd); + _exit (1); + } + _exit (WEXITSTATUS (r)); + } + + stdout_saved_fd = dup (1); + close (fd[0]); + dup2 (fd[1], 1); + close (fd[1]); + } for (argc = 0; argv[argc] != NULL; ++argc) ; @@ -657,29 +703,48 @@ issue_command (const char *cmd, char *argv[]) list_commands (); else display_command (argv[0]); - return 0; + r = 0; } else if (strcasecmp (cmd, "quit") == 0 || strcasecmp (cmd, "exit") == 0 || strcasecmp (cmd, "q") == 0) { quit = 1; - return 0; + r = 0; } else if (strcasecmp (cmd, "alloc") == 0 || strcasecmp (cmd, "allocate") == 0) - return do_alloc (cmd, argc, argv); + r = do_alloc (cmd, argc, argv); else if (strcasecmp (cmd, "echo") == 0) - return do_echo (cmd, argc, argv); + r = do_echo (cmd, argc, argv); else if (strcasecmp (cmd, "edit") == 0 || strcasecmp (cmd, "vi") == 0 || strcasecmp (cmd, "emacs") == 0) - return do_edit (cmd, argc, argv); + r = do_edit (cmd, argc, argv); else if (strcasecmp (cmd, "lcd") == 0) - return do_lcd (cmd, argc, argv); + r = do_lcd (cmd, argc, argv); else if (strcasecmp (cmd, "glob") == 0) - return do_glob (cmd, argc, argv); + r = do_glob (cmd, argc, argv); + else if (strcasecmp (cmd, "more") == 0 || + strcasecmp (cmd, "less") == 0) + r = do_more (cmd, argc, argv); + else if (strcasecmp (cmd, "time") == 0) + r = do_time (cmd, argc, argv); else - return run_action (cmd, argc, argv); + r = run_action (cmd, argc, argv); + + /* Always flush stdout after every command, so that messages, results + * etc appear immediately. + */ + fflush (stdout); + + if (pipecmd) { + close (1); + dup2 (stdout_saved_fd, 1); + close (stdout_saved_fd); + waitpid (pid, NULL, 0); + } + + return r; } void @@ -701,6 +766,10 @@ list_builtin_commands (void) "lcd", _("local change directory")); printf ("%-20s %s\n", "glob", _("expand wildcards in command")); + printf ("%-20s %s\n", + "more", _("view a file in the pager")); + printf ("%-20s %s\n", + "time", _("measure time taken to run command")); /* actions are printed after this (see list_commands) */ } @@ -762,6 +831,21 @@ display_builtin_command (const char *cmd) " Glob runs with wildcards expanded in any\n" " command args. Note that the command is run repeatedly\n" " once for each expanded argument.\n")); + else if (strcasecmp (cmd, "more") == 0 || + strcasecmp (cmd, "less") == 0) + printf (_("more - view a file in the pager\n" + " more \n" + "\n" + " This is used to view a file in the pager.\n" + "\n" + " It is the equivalent of (and is implemented by)\n" + " running \"cat\" and using the pager.\n" + "\n" + " Normally it uses $PAGER, but if you use the alias\n" + " \"less\" then it always uses \"less\".\n" + "\n" + " NOTE: This will not work reliably for large files\n" + " (> 2 MB) or binary files containing \\0 bytes.\n")); else if (strcasecmp (cmd, "help") == 0) printf (_("help - display a list of commands or help on a command\n" " help cmd\n" @@ -771,6 +855,12 @@ display_builtin_command (const char *cmd) strcasecmp (cmd, "q") == 0) printf (_("quit - quit guestfish\n" " quit\n")); + else if (strcasecmp (cmd, "time") == 0) + printf (_("time - measure time taken to run command\n" + " time [ ...]\n" + "\n" + " This runs as usual, and prints the elapsed\n" + " time afterwards.\n")); else fprintf (stderr, _("%s: command not known, use -h to list all commands\n"), cmd); @@ -903,3 +993,21 @@ add_history_line (const char *line) nr_history_lines++; #endif } + +int +xwrite (int fd, const void *buf, size_t len) +{ + int r; + + while (len > 0) { + r = write (fd, buf, len); + if (r == -1) { + perror ("write"); + return -1; + } + buf += r; + len -= r; + } + + return 0; +}