]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - term-utils/script.c
Merge branch 'dmverity_options' of https://github.com/bluca/util-linux
[thirdparty/util-linux.git] / term-utils / script.c
index f9494fd507ee33f269d1b2509994d60bbc6e50b9..de95645903346c3a2d0398c75d7ab70159f3f1a0 100644 (file)
@@ -208,6 +208,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -e, --return                  return exit code of the child process\n"), out);
        fputs(_(" -f, --flush                   run flush after each write\n"), out);
        fputs(_("     --force                   use output file even when it is a link\n"), out);
+       fputs(_(" -E, --echo <when>             echo input (auto, always or never)\n"), out);
        fputs(_(" -o, --output-limit <size>     terminate if output files exceed size\n"), out);
        fputs(_(" -q, --quiet                   be quiet\n"), out);
 
@@ -324,6 +325,18 @@ static int log_close(struct script_control *ctl,
        return rc;
 }
 
+static int log_flush(struct script_control *ctl __attribute__((__unused__)), struct script_log *log)
+{
+
+       if (!log || !log->initialized)
+               return 0;
+
+       DBG(MISC, ul_debug("flushing %s", log->filename));
+
+       fflush(log->fp);
+       return 0;
+}
+
 static void log_free(struct script_control *ctl, struct script_log *log)
 {
        size_t i;
@@ -700,6 +713,25 @@ static int callback_log_signal(void *data, struct signalfd_siginfo *info, void *
        return ssz < 0 ? ssz : 0;
 }
 
+static int callback_flush_logs(void *data)
+{
+       struct script_control *ctl = (struct script_control *) data;
+       size_t i;
+
+       for (i = 0; i < ctl->out.nlogs; i++) {
+               int rc = log_flush(ctl, ctl->out.logs[i]);
+               if (rc)
+                       return rc;
+       }
+
+       for (i = 0; i < ctl->in.nlogs; i++) {
+               int rc = log_flush(ctl, ctl->in.logs[i]);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
+
 static void die_if_link(struct script_control *ctl, const char *filename)
 {
        struct stat s;
@@ -720,7 +752,7 @@ int main(int argc, char **argv)
                .in  = { .ident = 'I' },
        };
        struct ul_pty_callbacks *cb;
-       int ch, format = 0, caught_signal = 0, rc = 0;
+       int ch, format = 0, caught_signal = 0, rc = 0, echo = 0;
        const char *outfile = NULL, *infile = NULL;
        const char *timingfile = NULL, *shell = NULL, *command = NULL;
 
@@ -729,6 +761,7 @@ int main(int argc, char **argv)
        static const struct option longopts[] = {
                {"append", no_argument, NULL, 'a'},
                {"command", required_argument, NULL, 'c'},
+               {"echo", required_argument, NULL, 'E'},
                {"return", no_argument, NULL, 'e'},
                {"flush", no_argument, NULL, 'f'},
                {"force", no_argument, NULL, FORCE_OPTION,},
@@ -765,7 +798,14 @@ int main(int argc, char **argv)
        script_init_debug();
        ON_DBG(PTY, ul_pty_init_debug(0xFFFF));
 
-       while ((ch = getopt_long(argc, argv, "aB:c:efI:O:o:qm:T:t::Vh", longopts, NULL)) != -1) {
+       /* The default is to keep ECHO flag when stdin is not terminal. We need
+        * it to make stdin (in case of "echo foo | script") log-able and
+        * visiable on terminal, and for backward compatibility.
+        */
+       ctl.isterm = isatty(STDIN_FILENO);
+       echo = ctl.isterm ? 0 : 1;
+
+       while ((ch = getopt_long(argc, argv, "aB:c:eE:fI:O:o:qm:T:t::Vh", longopts, NULL)) != -1) {
 
                err_exclusive_options(ch, longopts, excl, excl_st);
 
@@ -776,6 +816,16 @@ int main(int argc, char **argv)
                case 'c':
                        command = optarg;
                        break;
+               case 'E':
+                       if (strcmp(optarg, "auto") == 0)
+                               ; /* keep default */
+                       else if (strcmp(optarg, "never") == 0)
+                               echo = 0;
+                       else if (strcmp(optarg, "always") == 0)
+                               echo = 1;
+                       else
+                               errx(EXIT_FAILURE, _("unssuported echo mode: '%s'"), optarg);
+                       break;
                case 'e':
                        ctl.rc_wanted = 1;
                        break;
@@ -870,17 +920,11 @@ int main(int argc, char **argv)
        if (!shell)
                shell = _PATH_BSHELL;
 
-       ctl.isterm = isatty(STDIN_FILENO);
        ctl.pty = ul_new_pty(ctl.isterm);
        if (!ctl.pty)
                err(EXIT_FAILURE, "failed to allocate PTY handler");
 
-       if (!ctl.isterm)
-               /* We keep ECHO flag for 'echo "date" | script' otherwise the
-                * input is no visible (output is completely comtroled by
-                * shell/command, we do not write anything there).
-                */
-               ul_pty_keep_slave_echo(ctl.pty, 1);
+       ul_pty_slave_echo(ctl.pty, echo);
 
        ul_pty_set_callback_data(ctl.pty, (void *) &ctl);
        cb = ul_pty_get_callbacks(ctl.pty);
@@ -888,6 +932,7 @@ int main(int argc, char **argv)
        cb->child_sigstop = callback_child_sigstop;
        cb->log_stream_activity = callback_log_stream_activity;
        cb->log_signal = callback_log_signal;
+       cb->flush_logs = callback_flush_logs;
 
        if (!ctl.quiet) {
                printf(_("Script started"));