121c1c48aSSascha Wildner /*
221c1c48aSSascha Wildner * Copyright (c)2004 The DragonFly Project. All rights reserved.
321c1c48aSSascha Wildner *
421c1c48aSSascha Wildner * Redistribution and use in source and binary forms, with or without
521c1c48aSSascha Wildner * modification, are permitted provided that the following conditions
621c1c48aSSascha Wildner * are met:
721c1c48aSSascha Wildner *
821c1c48aSSascha Wildner * Redistributions of source code must retain the above copyright
921c1c48aSSascha Wildner * notice, this list of conditions and the following disclaimer.
1021c1c48aSSascha Wildner *
1121c1c48aSSascha Wildner * Redistributions in binary form must reproduce the above copyright
1221c1c48aSSascha Wildner * notice, this list of conditions and the following disclaimer in
1321c1c48aSSascha Wildner * the documentation and/or other materials provided with the
1421c1c48aSSascha Wildner * distribution.
1521c1c48aSSascha Wildner *
1621c1c48aSSascha Wildner * Neither the name of the DragonFly Project nor the names of its
1721c1c48aSSascha Wildner * contributors may be used to endorse or promote products derived
1821c1c48aSSascha Wildner * from this software without specific prior written permission.
1921c1c48aSSascha Wildner *
2021c1c48aSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2121c1c48aSSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2221c1c48aSSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2321c1c48aSSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2421c1c48aSSascha Wildner * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2521c1c48aSSascha Wildner * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2621c1c48aSSascha Wildner * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2721c1c48aSSascha Wildner * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2821c1c48aSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2921c1c48aSSascha Wildner * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3021c1c48aSSascha Wildner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
3121c1c48aSSascha Wildner * OF THE POSSIBILITY OF SUCH DAMAGE.
3221c1c48aSSascha Wildner */
3321c1c48aSSascha Wildner
3421c1c48aSSascha Wildner /*
3521c1c48aSSascha Wildner * commands.c
3621c1c48aSSascha Wildner * Execute a queued series of commands, updating a DFUI progress bar
3721c1c48aSSascha Wildner * as each is executed.
3821c1c48aSSascha Wildner * $Id: commands.c,v 1.27 2005/03/12 04:32:14 cpressey Exp $
3921c1c48aSSascha Wildner */
4021c1c48aSSascha Wildner
4121c1c48aSSascha Wildner #include <sys/time.h>
4221c1c48aSSascha Wildner #include <sys/types.h>
4321c1c48aSSascha Wildner
4421c1c48aSSascha Wildner #include <libgen.h>
4521c1c48aSSascha Wildner #include <signal.h>
4621c1c48aSSascha Wildner #include <stdarg.h>
4721c1c48aSSascha Wildner #include <stdlib.h>
4821c1c48aSSascha Wildner #include <string.h>
4921c1c48aSSascha Wildner #include <unistd.h>
5021c1c48aSSascha Wildner
5121c1c48aSSascha Wildner #include "libaura/mem.h"
5221c1c48aSSascha Wildner #include "libaura/buffer.h"
5321c1c48aSSascha Wildner #include "libaura/popen.h"
5421c1c48aSSascha Wildner
5521c1c48aSSascha Wildner #include "libdfui/dfui.h"
5621c1c48aSSascha Wildner
5721c1c48aSSascha Wildner #define NEEDS_COMMANDS_STRUCTURE_DEFINITIONS
5821c1c48aSSascha Wildner #include "commands.h"
5921c1c48aSSascha Wildner #undef NEEDS_COMMANDS_STRUCTURE_DEFINITIONS
6021c1c48aSSascha Wildner
6121c1c48aSSascha Wildner #include "diskutil.h"
6221c1c48aSSascha Wildner #include "functions.h"
6321c1c48aSSascha Wildner #include "uiutil.h"
6421c1c48aSSascha Wildner
6521c1c48aSSascha Wildner /*
6621c1c48aSSascha Wildner * Create a new queue of commands.
6721c1c48aSSascha Wildner */
6821c1c48aSSascha Wildner struct commands *
commands_new(void)6921c1c48aSSascha Wildner commands_new(void)
7021c1c48aSSascha Wildner {
7121c1c48aSSascha Wildner struct commands *cmds;
7221c1c48aSSascha Wildner
7321c1c48aSSascha Wildner AURA_MALLOC(cmds, commands);
7421c1c48aSSascha Wildner
7521c1c48aSSascha Wildner cmds->head = NULL;
7621c1c48aSSascha Wildner cmds->tail = NULL;
7721c1c48aSSascha Wildner
7821c1c48aSSascha Wildner return(cmds);
7921c1c48aSSascha Wildner }
8021c1c48aSSascha Wildner
8121c1c48aSSascha Wildner /*
8221c1c48aSSascha Wildner * Add a new, empty command to an existing queue of commands.
8321c1c48aSSascha Wildner */
8421c1c48aSSascha Wildner static struct command *
command_new(struct commands * cmds)8521c1c48aSSascha Wildner command_new(struct commands *cmds)
8621c1c48aSSascha Wildner {
8721c1c48aSSascha Wildner struct command *cmd;
8821c1c48aSSascha Wildner
8921c1c48aSSascha Wildner AURA_MALLOC(cmd, command);
9021c1c48aSSascha Wildner
9121c1c48aSSascha Wildner cmd->cmdline = NULL;
9221c1c48aSSascha Wildner cmd->desc = NULL;
9321c1c48aSSascha Wildner cmd->log_mode = COMMAND_LOG_VERBOSE;
9421c1c48aSSascha Wildner cmd->failure_mode = COMMAND_FAILURE_ABORT;
9521c1c48aSSascha Wildner cmd->tag = NULL;
9621c1c48aSSascha Wildner cmd->result = COMMAND_RESULT_NEVER_EXECUTED;
9721c1c48aSSascha Wildner cmd->output = NULL;
9821c1c48aSSascha Wildner
9921c1c48aSSascha Wildner cmd->next = NULL;
10021c1c48aSSascha Wildner if (cmds->head == NULL)
10121c1c48aSSascha Wildner cmds->head = cmd;
10221c1c48aSSascha Wildner else
10321c1c48aSSascha Wildner cmds->tail->next = cmd;
10421c1c48aSSascha Wildner
10521c1c48aSSascha Wildner cmd->prev = cmds->tail;
10621c1c48aSSascha Wildner cmds->tail = cmd;
10721c1c48aSSascha Wildner
10821c1c48aSSascha Wildner return(cmd);
10921c1c48aSSascha Wildner }
11021c1c48aSSascha Wildner
11121c1c48aSSascha Wildner /*
11221c1c48aSSascha Wildner * Add a new shell command to an existing queue of commands.
11321c1c48aSSascha Wildner * The command can be specified as a format string followed by
11421c1c48aSSascha Wildner * any number of arguments, in the style of "sprintf".
11521c1c48aSSascha Wildner */
11621c1c48aSSascha Wildner struct command *
command_add(struct commands * cmds,const char * fmt,...)11721c1c48aSSascha Wildner command_add(struct commands *cmds, const char *fmt, ...)
11821c1c48aSSascha Wildner {
11921c1c48aSSascha Wildner va_list args;
12021c1c48aSSascha Wildner struct command *cmd;
12121c1c48aSSascha Wildner
12221c1c48aSSascha Wildner cmd = command_new(cmds);
12321c1c48aSSascha Wildner
12421c1c48aSSascha Wildner va_start(args, fmt);
12521c1c48aSSascha Wildner vasprintf(&cmd->cmdline, fmt, args);
12621c1c48aSSascha Wildner va_end(args);
12721c1c48aSSascha Wildner
12821c1c48aSSascha Wildner return(cmd);
12921c1c48aSSascha Wildner }
13021c1c48aSSascha Wildner
13121c1c48aSSascha Wildner /*
13221c1c48aSSascha Wildner * Set the log mode of the given command.
13321c1c48aSSascha Wildner * Valid log modes are:
13421c1c48aSSascha Wildner * COMMAND_LOG_SILENT - do not log anything at all
13521c1c48aSSascha Wildner * COMMAND_LOG_QUIET - only log command name and exit code, not output
13621c1c48aSSascha Wildner * COMMAND_LOG_VERBOSE - log everything
13721c1c48aSSascha Wildner */
13821c1c48aSSascha Wildner void
command_set_log_mode(struct command * cmd,int log_mode)13921c1c48aSSascha Wildner command_set_log_mode(struct command *cmd, int log_mode)
14021c1c48aSSascha Wildner {
14121c1c48aSSascha Wildner cmd->log_mode = log_mode;
14221c1c48aSSascha Wildner }
14321c1c48aSSascha Wildner
14421c1c48aSSascha Wildner /*
14521c1c48aSSascha Wildner * Set the failure mode of the given command.
14621c1c48aSSascha Wildner * Valid failure modes are:
14721c1c48aSSascha Wildner * COMMAND_FAILURE_IGNORE - ignore failures and carry on
14821c1c48aSSascha Wildner * COMMAND_FAILURE_WARN - issue a non-critical warning
14921c1c48aSSascha Wildner * COMMAND_FAILURE_ABORT - halt the command chain and ask the user
15021c1c48aSSascha Wildner */
15121c1c48aSSascha Wildner void
command_set_failure_mode(struct command * cmd,int failure_mode)15221c1c48aSSascha Wildner command_set_failure_mode(struct command *cmd, int failure_mode)
15321c1c48aSSascha Wildner {
15421c1c48aSSascha Wildner cmd->failure_mode = failure_mode;
15521c1c48aSSascha Wildner }
15621c1c48aSSascha Wildner
15721c1c48aSSascha Wildner /*
15821c1c48aSSascha Wildner * Set the description of the given command. If present, it will
15921c1c48aSSascha Wildner * be displayed in the progress bar instead of the command line.
16021c1c48aSSascha Wildner */
16121c1c48aSSascha Wildner void
command_set_desc(struct command * cmd,const char * fmt,...)16221c1c48aSSascha Wildner command_set_desc(struct command *cmd, const char *fmt, ...)
16321c1c48aSSascha Wildner {
16421c1c48aSSascha Wildner va_list args;
16521c1c48aSSascha Wildner
16621c1c48aSSascha Wildner if (cmd->desc != NULL)
16721c1c48aSSascha Wildner free(cmd->desc);
16821c1c48aSSascha Wildner
16921c1c48aSSascha Wildner va_start(args, fmt);
17021c1c48aSSascha Wildner vasprintf(&cmd->desc, fmt, args);
17121c1c48aSSascha Wildner va_end(args);
17221c1c48aSSascha Wildner }
17321c1c48aSSascha Wildner
17421c1c48aSSascha Wildner /*
17521c1c48aSSascha Wildner * Set an arbitrary tag on the command.
17621c1c48aSSascha Wildner */
17721c1c48aSSascha Wildner void
command_set_tag(struct command * cmd,const char * fmt,...)17821c1c48aSSascha Wildner command_set_tag(struct command *cmd, const char *fmt, ...)
17921c1c48aSSascha Wildner {
18021c1c48aSSascha Wildner va_list args;
18121c1c48aSSascha Wildner
18221c1c48aSSascha Wildner if (cmd->tag != NULL)
18321c1c48aSSascha Wildner free(cmd->tag);
18421c1c48aSSascha Wildner
18521c1c48aSSascha Wildner va_start(args, fmt);
18621c1c48aSSascha Wildner vasprintf(&cmd->tag, fmt, args);
18721c1c48aSSascha Wildner va_end(args);
18821c1c48aSSascha Wildner }
18921c1c48aSSascha Wildner
19021c1c48aSSascha Wildner struct command *
command_get_first(const struct commands * cmds)19121c1c48aSSascha Wildner command_get_first(const struct commands *cmds)
19221c1c48aSSascha Wildner {
19321c1c48aSSascha Wildner return(cmds->head);
19421c1c48aSSascha Wildner }
19521c1c48aSSascha Wildner
19621c1c48aSSascha Wildner struct command *
command_get_next(const struct command * cmd)19721c1c48aSSascha Wildner command_get_next(const struct command *cmd)
19821c1c48aSSascha Wildner {
19921c1c48aSSascha Wildner return(cmd->next);
20021c1c48aSSascha Wildner }
20121c1c48aSSascha Wildner
20221c1c48aSSascha Wildner char *
command_get_cmdline(const struct command * cmd)20321c1c48aSSascha Wildner command_get_cmdline(const struct command *cmd)
20421c1c48aSSascha Wildner {
20521c1c48aSSascha Wildner return(cmd->cmdline);
20621c1c48aSSascha Wildner }
20721c1c48aSSascha Wildner
20821c1c48aSSascha Wildner char *
command_get_tag(const struct command * cmd)20921c1c48aSSascha Wildner command_get_tag(const struct command *cmd)
21021c1c48aSSascha Wildner {
21121c1c48aSSascha Wildner return(cmd->tag);
21221c1c48aSSascha Wildner }
21321c1c48aSSascha Wildner
21421c1c48aSSascha Wildner int
command_get_result(const struct command * cmd)21521c1c48aSSascha Wildner command_get_result(const struct command *cmd)
21621c1c48aSSascha Wildner {
21721c1c48aSSascha Wildner return(cmd->result);
21821c1c48aSSascha Wildner }
21921c1c48aSSascha Wildner
22021c1c48aSSascha Wildner /*
22121c1c48aSSascha Wildner * Allow the user to view the command log.
22221c1c48aSSascha Wildner */
22321c1c48aSSascha Wildner void
view_command_log(struct i_fn_args * a)22421c1c48aSSascha Wildner view_command_log(struct i_fn_args *a)
22521c1c48aSSascha Wildner {
22621c1c48aSSascha Wildner struct dfui_form *f;
22721c1c48aSSascha Wildner struct dfui_response *r;
22821c1c48aSSascha Wildner struct aura_buffer *error_log;
22921c1c48aSSascha Wildner
23021c1c48aSSascha Wildner error_log = aura_buffer_new(1024);
23121c1c48aSSascha Wildner aura_buffer_cat_file(error_log, "%sinstall.log", a->tmp);
23221c1c48aSSascha Wildner
23321c1c48aSSascha Wildner f = dfui_form_create(
23421c1c48aSSascha Wildner "error_log",
23521c1c48aSSascha Wildner "Error Log",
23621c1c48aSSascha Wildner aura_buffer_buf(error_log),
23721c1c48aSSascha Wildner "",
23821c1c48aSSascha Wildner
23921c1c48aSSascha Wildner "p", "role", "informative",
24021c1c48aSSascha Wildner "p", "minimum_width", "72",
24121c1c48aSSascha Wildner "p", "monospaced", "true",
24221c1c48aSSascha Wildner
24321c1c48aSSascha Wildner "a", "ok", "OK", "", "",
24421c1c48aSSascha Wildner NULL);
24521c1c48aSSascha Wildner
24621c1c48aSSascha Wildner if (!dfui_be_present(a->c, f, &r))
24721c1c48aSSascha Wildner abort_backend();
24821c1c48aSSascha Wildner
24921c1c48aSSascha Wildner dfui_form_free(f);
25021c1c48aSSascha Wildner dfui_response_free(r);
25121c1c48aSSascha Wildner
25221c1c48aSSascha Wildner aura_buffer_free(error_log);
25321c1c48aSSascha Wildner }
25421c1c48aSSascha Wildner
25521c1c48aSSascha Wildner /*
25621c1c48aSSascha Wildner * Preview a set of commands.
25721c1c48aSSascha Wildner */
25821c1c48aSSascha Wildner void
commands_preview(struct dfui_connection * c,const struct commands * cmds)25921c1c48aSSascha Wildner commands_preview(struct dfui_connection *c, const struct commands *cmds)
26021c1c48aSSascha Wildner {
26121c1c48aSSascha Wildner struct command *cmd;
26221c1c48aSSascha Wildner struct aura_buffer *preview;
26321c1c48aSSascha Wildner
26421c1c48aSSascha Wildner preview = aura_buffer_new(1024);
26521c1c48aSSascha Wildner
26621c1c48aSSascha Wildner for (cmd = cmds->head; cmd != NULL; cmd = cmd->next) {
26721c1c48aSSascha Wildner aura_buffer_cat(preview, cmd->cmdline);
26821c1c48aSSascha Wildner aura_buffer_cat(preview, "\n");
26921c1c48aSSascha Wildner }
27021c1c48aSSascha Wildner
2717eedf208SYONETANI Tomokazu inform(c, "%s", aura_buffer_buf(preview));
27221c1c48aSSascha Wildner
27321c1c48aSSascha Wildner aura_buffer_free(preview);
27421c1c48aSSascha Wildner }
27521c1c48aSSascha Wildner
27621c1c48aSSascha Wildner /*
27721c1c48aSSascha Wildner * The command chain executing engine proper follows.
27821c1c48aSSascha Wildner */
27921c1c48aSSascha Wildner
28021c1c48aSSascha Wildner /*
28121c1c48aSSascha Wildner * Read from the pipe that was opened to the executing commands
28221c1c48aSSascha Wildner * and update the progress bar as data comes and (and/or as the
28321c1c48aSSascha Wildner * read from the pipe times out.)
28421c1c48aSSascha Wildner */
28521c1c48aSSascha Wildner static int
pipe_loop(struct i_fn_args * a,struct dfui_progress * pr,struct command * cmd,int * cancelled)28621c1c48aSSascha Wildner pipe_loop(struct i_fn_args *a, struct dfui_progress *pr,
28721c1c48aSSascha Wildner struct command *cmd, int *cancelled)
28821c1c48aSSascha Wildner {
28921c1c48aSSascha Wildner FILE *cmdout = NULL;
29021c1c48aSSascha Wildner struct timeval tv = { 1, 0 };
29121c1c48aSSascha Wildner char cline[256];
29221c1c48aSSascha Wildner char *command;
29321c1c48aSSascha Wildner pid_t pid;
29421c1c48aSSascha Wildner fd_set r;
29521c1c48aSSascha Wildner int n;
29621c1c48aSSascha Wildner
29721c1c48aSSascha Wildner asprintf(&command, "(%s) 2>&1 </dev/null", cmd->cmdline);
29821c1c48aSSascha Wildner fflush(stdout);
299*a668c4cdSSascha Wildner cmdout = aura_popen("%s", "r", command);
30021c1c48aSSascha Wildner free(command);
30121c1c48aSSascha Wildner
30221c1c48aSSascha Wildner if (cmdout == NULL) {
30321c1c48aSSascha Wildner i_log(a, "! could not aura_popen() command");
30421c1c48aSSascha Wildner return(COMMAND_RESULT_POPEN_ERR);
30521c1c48aSSascha Wildner }
30621c1c48aSSascha Wildner pid = aura_pgetpid(cmdout);
30721c1c48aSSascha Wildner #ifdef DEBUG
30821c1c48aSSascha Wildner fprintf(stderr, "+ pid = %d\n", pid);
30921c1c48aSSascha Wildner #endif
31021c1c48aSSascha Wildner
31121c1c48aSSascha Wildner /*
31221c1c48aSSascha Wildner * Loop, selecting on the command and a timeout.
31321c1c48aSSascha Wildner */
31421c1c48aSSascha Wildner for (;;) {
31521c1c48aSSascha Wildner if (*cancelled)
31621c1c48aSSascha Wildner break;
31721c1c48aSSascha Wildner FD_ZERO(&r);
31821c1c48aSSascha Wildner FD_SET(fileno(cmdout), &r);
31921c1c48aSSascha Wildner n = select(fileno(cmdout) + 1, &r, NULL, NULL, &tv);
32021c1c48aSSascha Wildner #ifdef DEBUG
32121c1c48aSSascha Wildner fprintf(stderr, "+ select() = %d\n", n);
32221c1c48aSSascha Wildner #endif
32321c1c48aSSascha Wildner if (n < 0) {
32421c1c48aSSascha Wildner /* Error */
32521c1c48aSSascha Wildner i_log(a, "! select() failed\n");
32621c1c48aSSascha Wildner aura_pclose(cmdout);
32721c1c48aSSascha Wildner return(COMMAND_RESULT_SELECT_ERR);
32821c1c48aSSascha Wildner } else if (n == 0) {
32921c1c48aSSascha Wildner /* Timeout */
33021c1c48aSSascha Wildner if (!dfui_be_progress_update(a->c, pr, cancelled))
33121c1c48aSSascha Wildner abort_backend();
33221c1c48aSSascha Wildner #ifdef DEBUG
33321c1c48aSSascha Wildner fprintf(stderr, "+ cancelled = %d\n", *cancelled);
33421c1c48aSSascha Wildner #endif
33521c1c48aSSascha Wildner } else {
33621c1c48aSSascha Wildner /* Data came in */
33721c1c48aSSascha Wildner fgets(cline, 255, cmdout);
33821c1c48aSSascha Wildner while (strlen(cline) > 0 && cline[strlen(cline) - 1] == '\n')
33921c1c48aSSascha Wildner cline[strlen(cline) - 1] = '\0';
34021c1c48aSSascha Wildner if (feof(cmdout))
34121c1c48aSSascha Wildner break;
34221c1c48aSSascha Wildner if (!dfui_be_progress_update(a->c, pr, cancelled))
34321c1c48aSSascha Wildner abort_backend();
34421c1c48aSSascha Wildner if (cmd->log_mode == COMMAND_LOG_VERBOSE) {
34521c1c48aSSascha Wildner i_log(a, "| %s", cline);
34621c1c48aSSascha Wildner } else if (cmd->log_mode != COMMAND_LOG_SILENT) {
34721c1c48aSSascha Wildner fprintf(stderr, "| %s\n", cline);
34821c1c48aSSascha Wildner }
34921c1c48aSSascha Wildner }
35021c1c48aSSascha Wildner }
35121c1c48aSSascha Wildner
35221c1c48aSSascha Wildner if (*cancelled) {
35321c1c48aSSascha Wildner #ifdef DEBUG
35421c1c48aSSascha Wildner fprintf(stderr, "+ killing %d\n", pid);
35521c1c48aSSascha Wildner #endif
35621c1c48aSSascha Wildner n = kill(pid, SIGTERM);
35721c1c48aSSascha Wildner #ifdef DEBUG
35821c1c48aSSascha Wildner fprintf(stderr, "+ kill() = %d\n", n);
35921c1c48aSSascha Wildner #endif
36021c1c48aSSascha Wildner }
36121c1c48aSSascha Wildner
36221c1c48aSSascha Wildner #ifdef DEBUG
36321c1c48aSSascha Wildner fprintf(stderr, "+ pclosing %d\n", fileno(cmdout));
36421c1c48aSSascha Wildner #endif
36521c1c48aSSascha Wildner n = aura_pclose(cmdout) / 256;
36621c1c48aSSascha Wildner #ifdef DEBUG
36721c1c48aSSascha Wildner fprintf(stderr, "+ pclose() = %d\n", n);
36821c1c48aSSascha Wildner #endif
36921c1c48aSSascha Wildner return(n);
37021c1c48aSSascha Wildner }
37121c1c48aSSascha Wildner
37221c1c48aSSascha Wildner /*
37321c1c48aSSascha Wildner * Execute a single command.
37421c1c48aSSascha Wildner * Return value is a COMMAND_RESULT_* constant, or
37521c1c48aSSascha Wildner * a value from 0 to 255 to indicate the exit code
37621c1c48aSSascha Wildner * from the utility.
37721c1c48aSSascha Wildner */
37821c1c48aSSascha Wildner static int
command_execute(struct i_fn_args * a,struct dfui_progress * pr,struct command * cmd)37921c1c48aSSascha Wildner command_execute(struct i_fn_args *a, struct dfui_progress *pr,
38021c1c48aSSascha Wildner struct command *cmd)
38121c1c48aSSascha Wildner {
38221c1c48aSSascha Wildner FILE *log = NULL;
38321c1c48aSSascha Wildner char *filename;
38421c1c48aSSascha Wildner int cancelled = 0, done = 0, report_done = 0;
38521c1c48aSSascha Wildner
38621c1c48aSSascha Wildner if (cmd->desc != NULL)
38721c1c48aSSascha Wildner dfui_info_set_short_desc(dfui_progress_get_info(pr), cmd->desc);
38821c1c48aSSascha Wildner else
38921c1c48aSSascha Wildner dfui_info_set_short_desc(dfui_progress_get_info(pr), cmd->cmdline);
39021c1c48aSSascha Wildner
39121c1c48aSSascha Wildner if (!dfui_be_progress_update(a->c, pr, &cancelled))
39221c1c48aSSascha Wildner abort_backend();
39321c1c48aSSascha Wildner
39421c1c48aSSascha Wildner while (!done) {
39521c1c48aSSascha Wildner asprintf(&filename, "%sinstall.log", a->tmp);
39621c1c48aSSascha Wildner log = fopen(filename, "a");
39721c1c48aSSascha Wildner free(filename);
39821c1c48aSSascha Wildner
39921c1c48aSSascha Wildner if (cmd->log_mode != COMMAND_LOG_SILENT)
40021c1c48aSSascha Wildner i_log(a, ",-<<< Executing `%s'", cmd->cmdline);
40121c1c48aSSascha Wildner cmd->result = pipe_loop(a, pr, cmd, &cancelled);
40221c1c48aSSascha Wildner if (cmd->log_mode != COMMAND_LOG_SILENT)
40321c1c48aSSascha Wildner i_log(a, "`->>> Exit status: %d\n", cmd->result);
40421c1c48aSSascha Wildner
40521c1c48aSSascha Wildner if (log != NULL)
40621c1c48aSSascha Wildner fclose(log);
40721c1c48aSSascha Wildner
40821c1c48aSSascha Wildner if (cancelled) {
40921c1c48aSSascha Wildner if (!dfui_be_progress_end(a->c))
41021c1c48aSSascha Wildner abort_backend();
41121c1c48aSSascha Wildner
41221c1c48aSSascha Wildner report_done = 0;
41321c1c48aSSascha Wildner while (!report_done) {
41421c1c48aSSascha Wildner switch (dfui_be_present_dialog(a->c, "Cancelled",
41521c1c48aSSascha Wildner "View Log|Retry|Cancel|Skip",
41621c1c48aSSascha Wildner "Execution of the command\n\n%s\n\n"
41721c1c48aSSascha Wildner "was cancelled.",
41821c1c48aSSascha Wildner cmd->cmdline)) {
41921c1c48aSSascha Wildner case 1:
42021c1c48aSSascha Wildner /* View Log */
42121c1c48aSSascha Wildner view_command_log(a);
42221c1c48aSSascha Wildner break;
42321c1c48aSSascha Wildner case 2:
42421c1c48aSSascha Wildner /* Retry */
42521c1c48aSSascha Wildner cancelled = 0;
42621c1c48aSSascha Wildner report_done = 1;
42721c1c48aSSascha Wildner break;
42821c1c48aSSascha Wildner case 3:
42921c1c48aSSascha Wildner /* Cancel */
43021c1c48aSSascha Wildner cmd->result = COMMAND_RESULT_CANCELLED;
43121c1c48aSSascha Wildner report_done = 1;
43221c1c48aSSascha Wildner done = 1;
43321c1c48aSSascha Wildner break;
43421c1c48aSSascha Wildner case 4:
43521c1c48aSSascha Wildner /* Skip */
43621c1c48aSSascha Wildner cmd->result = COMMAND_RESULT_SKIPPED;
43721c1c48aSSascha Wildner report_done = 1;
43821c1c48aSSascha Wildner done = 1;
43921c1c48aSSascha Wildner break;
44021c1c48aSSascha Wildner }
44121c1c48aSSascha Wildner }
44221c1c48aSSascha Wildner
44321c1c48aSSascha Wildner if (!dfui_be_progress_begin(a->c, pr))
44421c1c48aSSascha Wildner abort_backend();
44521c1c48aSSascha Wildner
44621c1c48aSSascha Wildner } else if (cmd->failure_mode == COMMAND_FAILURE_IGNORE) {
44721c1c48aSSascha Wildner cmd->result = 0;
44821c1c48aSSascha Wildner done = 1;
44921c1c48aSSascha Wildner } else if (cmd->result != 0 && cmd->failure_mode != COMMAND_FAILURE_WARN) {
45021c1c48aSSascha Wildner if (!dfui_be_progress_end(a->c))
45121c1c48aSSascha Wildner abort_backend();
45221c1c48aSSascha Wildner
45321c1c48aSSascha Wildner report_done = 0;
45421c1c48aSSascha Wildner while (!report_done) {
45521c1c48aSSascha Wildner switch (dfui_be_present_dialog(a->c, "Command Failed!",
45621c1c48aSSascha Wildner "View Log|Retry|Cancel|Skip",
45721c1c48aSSascha Wildner "Execution of the command\n\n%s\n\n"
45821c1c48aSSascha Wildner "FAILED with a return code of %d.",
45921c1c48aSSascha Wildner cmd->cmdline, cmd->result)) {
46021c1c48aSSascha Wildner case 1:
46121c1c48aSSascha Wildner /* View Log */
46221c1c48aSSascha Wildner view_command_log(a);
46321c1c48aSSascha Wildner break;
46421c1c48aSSascha Wildner case 2:
46521c1c48aSSascha Wildner /* Retry */
46621c1c48aSSascha Wildner report_done = 1;
46721c1c48aSSascha Wildner break;
46821c1c48aSSascha Wildner case 3:
46921c1c48aSSascha Wildner /* Cancel */
47021c1c48aSSascha Wildner /* XXX need a better way to retain actual result */
47121c1c48aSSascha Wildner cmd->result = COMMAND_RESULT_CANCELLED;
47221c1c48aSSascha Wildner report_done = 1;
47321c1c48aSSascha Wildner done = 1;
47421c1c48aSSascha Wildner break;
47521c1c48aSSascha Wildner case 4:
47621c1c48aSSascha Wildner /* Skip */
47721c1c48aSSascha Wildner /* XXX need a better way to retain actual result */
47821c1c48aSSascha Wildner cmd->result = COMMAND_RESULT_SKIPPED;
47921c1c48aSSascha Wildner report_done = 1;
48021c1c48aSSascha Wildner done = 1;
48121c1c48aSSascha Wildner break;
48221c1c48aSSascha Wildner }
48321c1c48aSSascha Wildner }
48421c1c48aSSascha Wildner
48521c1c48aSSascha Wildner if (!dfui_be_progress_begin(a->c, pr))
48621c1c48aSSascha Wildner abort_backend();
48721c1c48aSSascha Wildner
48821c1c48aSSascha Wildner } else {
48921c1c48aSSascha Wildner done = 1;
49021c1c48aSSascha Wildner }
49121c1c48aSSascha Wildner }
49221c1c48aSSascha Wildner
49321c1c48aSSascha Wildner return(cmd->result);
49421c1c48aSSascha Wildner }
49521c1c48aSSascha Wildner
49621c1c48aSSascha Wildner /*
49721c1c48aSSascha Wildner * Execute a series of external utility programs.
49821c1c48aSSascha Wildner * Returns 1 if everything executed OK, 0 if one of the
49921c1c48aSSascha Wildner * critical commands failed or if the user cancelled.
50021c1c48aSSascha Wildner */
50121c1c48aSSascha Wildner int
commands_execute(struct i_fn_args * a,struct commands * cmds)50221c1c48aSSascha Wildner commands_execute(struct i_fn_args *a, struct commands *cmds)
50321c1c48aSSascha Wildner {
50421c1c48aSSascha Wildner struct dfui_progress *pr;
50521c1c48aSSascha Wildner struct command *cmd;
50621c1c48aSSascha Wildner int i;
50721c1c48aSSascha Wildner int n = 0;
50821c1c48aSSascha Wildner int result = 0;
50921c1c48aSSascha Wildner int return_val = 1;
51021c1c48aSSascha Wildner
51121c1c48aSSascha Wildner cmd = cmds->head;
51221c1c48aSSascha Wildner while (cmd != NULL) {
51321c1c48aSSascha Wildner n++;
51421c1c48aSSascha Wildner cmd = cmd->next;
51521c1c48aSSascha Wildner }
51621c1c48aSSascha Wildner
51721c1c48aSSascha Wildner pr = dfui_progress_new(dfui_info_new(
51821c1c48aSSascha Wildner "Executing Commands",
51921c1c48aSSascha Wildner "Executing Commands",
52021c1c48aSSascha Wildner ""),
52121c1c48aSSascha Wildner 0);
52221c1c48aSSascha Wildner
52321c1c48aSSascha Wildner if (!dfui_be_progress_begin(a->c, pr))
52421c1c48aSSascha Wildner abort_backend();
52521c1c48aSSascha Wildner
52621c1c48aSSascha Wildner i = 1;
52721c1c48aSSascha Wildner for (cmd = cmds->head; cmd != NULL; cmd = cmd->next, i++) {
52821c1c48aSSascha Wildner result = command_execute(a, pr, cmd);
52921c1c48aSSascha Wildner if (result == COMMAND_RESULT_CANCELLED) {
53021c1c48aSSascha Wildner return_val = 0;
53121c1c48aSSascha Wildner break;
53221c1c48aSSascha Wildner }
53321c1c48aSSascha Wildner if (result > 0 && result < 256) {
53421c1c48aSSascha Wildner return_val = 0;
53521c1c48aSSascha Wildner if (cmd->failure_mode == COMMAND_FAILURE_ABORT) {
53621c1c48aSSascha Wildner break;
53721c1c48aSSascha Wildner }
53821c1c48aSSascha Wildner }
53921c1c48aSSascha Wildner dfui_progress_set_amount(pr, (i * 100) / n);
54021c1c48aSSascha Wildner }
54121c1c48aSSascha Wildner
54221c1c48aSSascha Wildner if (!dfui_be_progress_end(a->c))
54321c1c48aSSascha Wildner abort_backend();
54421c1c48aSSascha Wildner
54521c1c48aSSascha Wildner dfui_progress_free(pr);
54621c1c48aSSascha Wildner
54721c1c48aSSascha Wildner return(return_val);
54821c1c48aSSascha Wildner }
54921c1c48aSSascha Wildner
55021c1c48aSSascha Wildner /*
55121c1c48aSSascha Wildner * Free the memory allocated for a queue of commands. This invalidates
55221c1c48aSSascha Wildner * the pointer passed to it.
55321c1c48aSSascha Wildner */
55421c1c48aSSascha Wildner void
commands_free(struct commands * cmds)55521c1c48aSSascha Wildner commands_free(struct commands *cmds)
55621c1c48aSSascha Wildner {
55721c1c48aSSascha Wildner struct command *cmd, *next;
55821c1c48aSSascha Wildner
55921c1c48aSSascha Wildner cmd = cmds->head;
56021c1c48aSSascha Wildner while (cmd != NULL) {
56121c1c48aSSascha Wildner next = cmd->next;
56221c1c48aSSascha Wildner if (cmd->cmdline != NULL)
56321c1c48aSSascha Wildner free(cmd->cmdline);
56421c1c48aSSascha Wildner if (cmd->desc != NULL)
56521c1c48aSSascha Wildner free(cmd->desc);
56621c1c48aSSascha Wildner if (cmd->tag != NULL)
56721c1c48aSSascha Wildner free(cmd->tag);
56821c1c48aSSascha Wildner AURA_FREE(cmd, command);
56921c1c48aSSascha Wildner cmd = next;
57021c1c48aSSascha Wildner }
57121c1c48aSSascha Wildner AURA_FREE(cmds, commands);
57221c1c48aSSascha Wildner }
573