1/*
2 * $FreeBSD$
3 *
4 * Jordan Hubbard
5 *
6 * My contributions are in the public domain.
7 *
8 * Parts of this file are also blatently stolen from Poul-Henning Kamp's
9 * previous version of sysinstall, and as such fall under his "BEERWARE license"
10 * so buy him a beer if you like it!  Buy him a beer for me, too!
11 * Heck, get him completely drunk and send me pictures! :-)
12 */
13
14#include "sade.h"
15#include <signal.h>
16#include <termios.h>
17#include <sys/param.h>
18#include <sys/reboot.h>
19#include <sys/consio.h>
20#include <sys/fcntl.h>
21#include <sys/ioctl.h>
22#include <sys/mount.h>
23#include <sys/stat.h>
24#include <sys/sysctl.h>
25#include <ufs/ufs/ufsmount.h>
26
27
28/* Where we stick our temporary expanded doc file */
29#define	DOC_TMP_DIR	"/tmp/.doc"
30#define	DOC_TMP_FILE	"/tmp/.doc/doc.tmp"
31
32/*
33 * Handle interrupt signals - this probably won't work in all cases
34 * due to our having bogotified the internal state of dialog or curses,
35 * but we'll give it a try.
36 */
37static int
38intr_continue(dialogMenuItem *self)
39{
40    return DITEM_LEAVE_MENU;
41}
42
43static int
44intr_restart(dialogMenuItem *self)
45{
46    int ret, fd, fdmax;
47
48    free_variables();
49    fdmax = getdtablesize();
50    for (fd = 3; fd < fdmax; fd++)
51	close(fd);
52    ret = execl(StartName, StartName, "-restart", (char *)NULL);
53    msgDebug("execl failed (%s)\n", strerror(errno));
54    /* NOTREACHED */
55    return -1;
56}
57
58static dialogMenuItem intrmenu[] = {
59    { "Restart", "Restart the program", NULL, intr_restart, NULL, NULL, 0, 0, 0, 0 },
60    { "Continue", "Continue without restarting", NULL, intr_continue, NULL, NULL, 0, 0, 0, 0 },
61};
62
63
64static void
65handle_intr(int sig)
66{
67    WINDOW *save = savescr();
68
69    use_helpline(NULL);
70    use_helpfile(NULL);
71    if (OnVTY) {
72        ioctl(0, VT_ACTIVATE, 1);       /* Switch back */
73        msgInfo(NULL);
74    }
75    (void)dialog_menu("Installation interrupt",
76		     "Do you want to abort the installation?",
77		     -1, -1, 2, -2, intrmenu, NULL, NULL, NULL);
78    restorescr(save);
79}
80
81/* Expand a file into a convenient location, nuking it each time */
82static char *
83expand(char *fname)
84{
85    char *gunzip = "/usr/bin/gunzip";
86
87    if (!directory_exists(DOC_TMP_DIR)) {
88	Mkdir(DOC_TMP_DIR);
89	if (chown(DOC_TMP_DIR, 0, 0) < 0)
90	    return NULL;
91	if (chmod(DOC_TMP_DIR, S_IRWXU) < 0)
92	    return NULL;
93    }
94    else
95	unlink(DOC_TMP_FILE);
96    if (!file_readable(fname) || vsystem("%s < %s > %s", gunzip, fname, DOC_TMP_FILE))
97	return NULL;
98    return DOC_TMP_FILE;
99}
100
101/* Initialize system defaults */
102void
103systemInitialize(int argc, char **argv)
104{
105    size_t i;
106    int boothowto;
107    sigset_t signalset;
108
109    signal(SIGINT, SIG_IGN);
110    globalsInit();
111
112    i = sizeof(boothowto);
113    if (!sysctlbyname("debug.boothowto", &boothowto, &i, NULL, 0) &&
114        (i == sizeof(boothowto)) && (boothowto & RB_VERBOSE))
115	variable_set2(VAR_DEBUG, "YES", 0);
116
117    if (set_termcap() == -1) {
118	printf("Can't find terminal entry\n");
119	exit(-1);
120    }
121
122    /* XXX - libdialog has particularly bad return value checking */
123    init_dialog();
124
125    /* If we haven't crashed I guess dialog is running ! */
126    DialogActive = TRUE;
127
128    /* Make sure HOME is set for those utilities that need it */
129    signal(SIGINT, handle_intr);
130    /*
131     * Make sure we can be interrupted even if we were re-executed
132     * from an interrupt.
133     */
134    sigemptyset(&signalset);
135    sigaddset(&signalset, SIGINT);
136    sigprocmask(SIG_UNBLOCK, &signalset, NULL);
137
138    (void)vsystem("rm -rf %s", DOC_TMP_DIR);
139}
140
141/* Run some general command */
142int
143systemExecute(char *command)
144{
145    int status;
146    struct termios foo;
147    WINDOW *w = savescr();
148
149    dialog_clear();
150    dialog_update();
151    end_dialog();
152    DialogActive = FALSE;
153    if (tcgetattr(0, &foo) != -1) {
154	foo.c_cc[VERASE] = '\010';
155	tcsetattr(0, TCSANOW, &foo);
156    }
157    if (!Fake)
158	status = system(command);
159    else {
160	status = 0;
161	msgDebug("systemExecute:  Faked execution of `%s'\n", command);
162    }
163    DialogActive = TRUE;
164    restorescr(w);
165    return status;
166}
167
168/* suspend/resume libdialog/curses screen */
169static    WINDOW *oldW;
170
171void
172systemSuspendDialog(void)
173{
174
175    oldW  = savescr();
176    dialog_clear();
177    dialog_update();
178    end_dialog();
179    DialogActive = FALSE;
180}
181
182void
183systemResumeDialog(void)
184{
185
186    DialogActive = TRUE;
187    restorescr(oldW);
188}
189
190/* Display a help file in a filebox */
191int
192systemDisplayHelp(char *file)
193{
194    char *fname = NULL;
195    char buf[FILENAME_MAX];
196    int ret = 0;
197    WINDOW *w = savescr();
198
199		printf("zzz");
200    fname = systemHelpFile(file, buf);
201    if (!fname) {
202	snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file);
203	use_helpfile(NULL);
204	use_helpline(NULL);
205	dialog_mesgbox("Sorry!", buf, -1, -1);
206	ret = 1;
207    }
208    else {
209	use_helpfile(NULL);
210	use_helpline(NULL);
211	dialog_textbox(file, fname, LINES, COLS);
212    }
213    restorescr(w);
214    return ret;
215}
216
217char *
218systemHelpFile(char *file, char *buf)
219{
220    if (!file)
221	return NULL;
222    if (file[0] == '/')
223	return file;
224    snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file);
225    if (file_readable(buf))
226	return expand(buf);
227    snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp", file);
228    if (file_readable(buf))
229	return expand(buf);
230    snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file);
231    if (file_readable(buf))
232	return expand(buf);
233    snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT", file);
234    if (file_readable(buf))
235	return expand(buf);
236    snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/%s/help/%s.hlp", ProgName,
237	file);
238    if (file_readable(buf))
239	return buf;
240    snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/%s/help/%s.TXT", ProgName,
241	file);
242    if (file_readable(buf))
243	return buf;
244    return NULL;
245}
246
247int
248vsystem(const char *fmt, ...)
249{
250    va_list args;
251    int pstat;
252    pid_t pid;
253    int omask;
254    sig_t intsave, quitsave;
255    char *cmd;
256    int i;
257    struct stat sb;
258
259    cmd = (char *)alloca(FILENAME_MAX);
260    cmd[0] = '\0';
261    va_start(args, fmt);
262    vsnprintf(cmd, FILENAME_MAX, fmt, args);
263    va_end(args);
264
265    omask = sigblock(sigmask(SIGCHLD));
266    if (Fake) {
267	msgDebug("vsystem:  Faked execution of `%s'\n", cmd);
268	return 0;
269    }
270    if (isDebug())
271	msgDebug("Executing command `%s'\n", cmd);
272    pid = fork();
273    if (pid == -1) {
274	(void)sigsetmask(omask);
275	i = 127;
276    }
277    else if (!pid) {	/* Junior */
278	(void)sigsetmask(omask);
279	if (DebugFD != -1) {
280	    dup2(DebugFD, 0);
281	    dup2(DebugFD, 1);
282	    dup2(DebugFD, 2);
283	}
284	else {
285	    close(1); open("/dev/null", O_WRONLY);
286	    dup2(1, 2);
287	}
288	if (stat("/stand/sh", &sb) == 0)
289	    execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL);
290	else
291	    execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
292	exit(1);
293    }
294    else {
295	intsave = signal(SIGINT, SIG_IGN);
296	quitsave = signal(SIGQUIT, SIG_IGN);
297	pid = waitpid(pid, &pstat, 0);
298	(void)sigsetmask(omask);
299	(void)signal(SIGINT, intsave);
300	(void)signal(SIGQUIT, quitsave);
301	i = (pid == -1) ? -1 : WEXITSTATUS(pstat);
302	if (isDebug())
303	    msgDebug("Command `%s' returns status of %d\n", cmd, i);
304    }
305    return i;
306}
307
308