18348Sjkh/*
28348Sjkh * The new sysinstall program.
38348Sjkh *
48348Sjkh * This is probably the last program in the `sysinstall' line - the next
58348Sjkh * generation being essentially a complete rewrite.
68348Sjkh *
750479Speter * $FreeBSD$
88348Sjkh *
98348Sjkh * Copyright (c) 1995
108348Sjkh *	Jordan Hubbard.  All rights reserved.
118348Sjkh *
128348Sjkh * Redistribution and use in source and binary forms, with or without
138348Sjkh * modification, are permitted provided that the following conditions
148348Sjkh * are met:
158348Sjkh * 1. Redistributions of source code must retain the above copyright
168881Srgrimes *    notice, this list of conditions and the following disclaimer,
178881Srgrimes *    verbatim and that no modifications are made prior to this
188348Sjkh *    point in the file.
198348Sjkh * 2. Redistributions in binary form must reproduce the above copyright
208348Sjkh *    notice, this list of conditions and the following disclaimer in the
218348Sjkh *    documentation and/or other materials provided with the distribution.
228348Sjkh *
238348Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
248348Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
258348Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
268348Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
278348Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
288348Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
298348Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
308348Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
318348Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
328348Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
338348Sjkh * SUCH DAMAGE.
348348Sjkh *
358348Sjkh */
368348Sjkh
378348Sjkh#include "sysinstall.h"
388348Sjkh
398348Sjkh#define MAX_NUM_COMMANDS	10
408348Sjkh
418348Sjkhtypedef struct {
428348Sjkh    char key[FILENAME_MAX];
438549Sjkh    struct {
448549Sjkh	enum { CMD_SHELL, CMD_FUNCTION } type;
458549Sjkh	void *ptr, *data;
468549Sjkh    } cmds[MAX_NUM_COMMANDS];
478348Sjkh    int ncmds;
488348Sjkh} Command;
498348Sjkh
508348Sjkh#define MAX_CMDS	200
518348Sjkhstatic Command *commandStack[MAX_CMDS];
528348Sjkhint numCommands;
538348Sjkh
548549Sjkh/* Nuke the command stack */
558348Sjkhvoid
568348Sjkhcommand_clear(void)
578348Sjkh{
588348Sjkh    int i, j;
598348Sjkh
608348Sjkh    for (i = 0; i < numCommands; i++)
618348Sjkh	for (j = 0; j < commandStack[i]->ncmds; j++)
628549Sjkh	    if (commandStack[i]->cmds[j].type == CMD_SHELL)
638549Sjkh		free(commandStack[i]->cmds[j].ptr);
648348Sjkh    free(commandStack[i]);
658348Sjkh    numCommands = 0;
668348Sjkh}
678348Sjkh
6810882Speterstatic void
6910882Speteraddit(char *key, int type, void *cmd, void *data)
708348Sjkh{
718348Sjkh    int i;
728348Sjkh
7312661Speter    /* First, look for the key already present and add a command to it if found */
748348Sjkh    for (i = 0; i < numCommands; i++) {
758348Sjkh	if (!strcmp(commandStack[i]->key, key)) {
768348Sjkh	    if (commandStack[i]->ncmds == MAX_NUM_COMMANDS)
7710882Speter		msgFatal("More than %d commands stacked up behind %s??", MAX_NUM_COMMANDS, key);
7810882Speter	    commandStack[i]->cmds[commandStack[i]->ncmds].type = type;
7910882Speter	    commandStack[i]->cmds[commandStack[i]->ncmds].ptr = cmd;
8010882Speter	    commandStack[i]->cmds[commandStack[i]->ncmds].data = data;
818549Sjkh	    ++(commandStack[i]->ncmds);
828348Sjkh	    return;
838348Sjkh	}
848348Sjkh    }
858549Sjkh    if (numCommands == MAX_CMDS)
868549Sjkh	msgFatal("More than %d commands accumulated??", MAX_CMDS);
878549Sjkh
888348Sjkh    /* If we fell to here, it's a new key */
898348Sjkh    commandStack[numCommands] = safe_malloc(sizeof(Command));
908348Sjkh    strcpy(commandStack[numCommands]->key, key);
918348Sjkh    commandStack[numCommands]->ncmds = 1;
9210882Speter    commandStack[numCommands]->cmds[0].type = type;
9310882Speter    commandStack[numCommands]->cmds[0].ptr = cmd;
9412661Speter    commandStack[numCommands]->cmds[0].data = data;
9512661Speter    ++numCommands;
968549Sjkh}
978549Sjkh
988549Sjkh/* Add a shell command under a given key */
998549Sjkhvoid
10010882Spetercommand_shell_add(char *key, char *fmt, ...)
1018549Sjkh{
10210882Speter    va_list args;
10310882Speter    char *cmd;
1048549Sjkh
10512661Speter    cmd = (char *)safe_malloc(256);
10610882Speter    va_start(args, fmt);
10712661Speter    vsnprintf(cmd, 256, fmt, args);
10810882Speter    va_end(args);
1098549Sjkh
11010882Speter    addit(key, CMD_SHELL, cmd, NULL);
1118348Sjkh}
1128348Sjkh
11310882Speter/* Add a shell command under a given key */
11410882Spetervoid
11510882Spetercommand_func_add(char *key, commandFunc func, void *data)
11610882Speter{
11710882Speter    addit(key, CMD_FUNCTION, func, data);
11810882Speter}
11910882Speter
1208348Sjkhstatic int
12112661Spetersort_compare(Command *p1, Command *p2)
1228348Sjkh{
12312661Speter    if (!p1 && !p2)
12412661Speter	return 0;
12512661Speter    else if (!p1 && p2)	/* NULL has a "greater" value for commands */
12612661Speter	return 1;
12712661Speter    else if (p1 && !p2)
12812661Speter	return -1;
12912661Speter    else
13012661Speter	return strcmp(p1->key, p2->key);
1318348Sjkh}
1328348Sjkh
1338348Sjkhvoid
1348348Sjkhcommand_sort(void)
1358348Sjkh{
13612661Speter    int i, j;
13712661Speter
13812661Speter    commandStack[numCommands] = NULL;
13912661Speter    /* Just do a crude bubble sort since the list is small */
14012661Speter    for (i = 0; i < numCommands; i++) {
14112661Speter	for (j = 0; j < numCommands; j++) {
14212661Speter	    if (sort_compare(commandStack[j], commandStack[j + 1]) > 0) {
14312661Speter		Command *tmp = commandStack[j];
14412661Speter
14512661Speter		commandStack[j] = commandStack[j + 1];
14612661Speter		commandStack[j + 1] = tmp;
14712661Speter	    }
14812661Speter	}
14912661Speter    }
1508348Sjkh}
1518348Sjkh
1528549Sjkh/* Run all accumulated commands in sorted order */
1538348Sjkhvoid
1548348Sjkhcommand_execute(void)
1558348Sjkh{
1568452Sjkh    int i, j, ret;
1578549Sjkh    commandFunc func;
1588348Sjkh
1598348Sjkh    for (i = 0; i < numCommands; i++) {
1608348Sjkh	for (j = 0; j < commandStack[i]->ncmds; j++) {
1618556Sjkh	    /* If it's a shell command, run system on it */
1628556Sjkh	    if (commandStack[i]->cmds[j].type == CMD_SHELL) {
16383844Smurray		msgNotify("Doing %s", (char *)commandStack[i]->cmds[j].ptr);
16479304Skris		ret = vsystem("%s", (char *)commandStack[i]->cmds[j].ptr);
1658837Sjkh		if (isDebug())
16683844Smurray		    msgDebug("Command `%s' returns status %d\n",
16783844Smurray		        (char *)commandStack[i]->cmds[j].ptr, ret);
1688549Sjkh	    }
1698549Sjkh	    else {
17083844Smurray		/* It's a function pointer - call it with the key and
17183844Smurray                   the data */
1728556Sjkh		func = (commandFunc)commandStack[i]->cmds[j].ptr;
17312661Speter		if (isDebug())
174106279Skuriyama		    msgDebug("%p: Execute(%s, %s)\n",
17583844Smurray		        func, commandStack[i]->key,
17683844Smurray			(char *)commandStack[i]->cmds[j].data);
1778589Sjkh		ret = (*func)(commandStack[i]->key, commandStack[i]->cmds[j].data);
1788837Sjkh		if (isDebug())
17983844Smurray		    msgDebug("Function @ %p returns status %d\n",
18083844Smurray		        commandStack[i]->cmds[j].ptr, ret);
1818549Sjkh	    }
1828348Sjkh	}
1838348Sjkh    }
1848348Sjkh}
185