1/* Copyright (C) 1995 Florian La Roche */
2/* Who wants to help coding? I don't like doing this... */
3
4/* You can just start setup as normal user and see how far it is coded
5   right now. This will do a fake installation and won't actually chnage
6   any data on your computer. */
7
8/* TODO: write a good package selection code
9         change functions to return better error code
10 */
11
12/* Show an extra text-box with the contents of all external commands,
13   before they are executed. So you can abort the installation, if any
14   wrong commands are to be executed. (So don't format wrong partition.) */
15#define VERBOSE 1
16
17/* If defined, don't actually execute any comands and don't actually modify
18   any files. So you can test any possible installation without doing any
19   damage to your computer.
20   The file FDISK.TEST is used instead of real "fdisk -l" output, so that
21   it can be started as normal user. */
22#define DEBUG_THIS 1
23
24#include <dialog.h>
25
26/* max length of a partition name like e.g. '/dev/hda1' */
27#define MAX_DEV_NAME 25
28
29/* max number of possible Linux/Swap/MsDos partitions */
30#define MAX_PARTS 20
31
32char *progname = NULL;
33
34static void
35error(const char *s)
36{
37    fprintf(stderr, "%s: %s\n", progname, s);
38    exit(1);
39}
40
41static int
42my_system(const char *s,...)
43{
44    int ret, i;
45    va_list ap;
46    char sh[200];
47
48    va_start(ap, s);
49    vsprintf(sh, s, ap);
50    va_end(ap);
51
52#ifdef	VERBOSE
53    i = dialog_msgbox("I will run the following command:", sh, 10, 65, 1);
54    dialog_clear();
55#ifdef DEBUG_THIS
56    return 0;
57#endif
58#endif
59    ret = system(sh);
60    if (!(ret >> 8))
61	return 0;
62    i = dialog_msgbox("Error-Exit on the following command:",
63		      sh, 12, 73, 1);
64    dialog_clear();
65    return 1;
66}
67
68/* We support to install from DOS/Linux-partitions. */
69enum partition_type {
70    MsDos,
71    Linux,
72    Swap
73};
74
75struct partition {
76    enum partition_type type;
77    char name[MAX_DEV_NAME];
78    int blocks;
79    int flag;
80} partitions[MAX_PARTS];
81int num_partition = 0;
82int num_linux = 0;
83int num_swap = 0;
84int num_msdos = 0;
85
86static int
87get_line(char *line, int size, FILE * f)
88{
89    char *ptr = line;
90    int c;
91
92    if (feof(f))
93	return -1;
94    while (size-- && ((c = getc(f)) != EOF) && (c != '\n'))
95	*ptr++ = c;
96    *ptr++ = '\0';
97    return (int) (ptr - line);
98}
99
100static void
101read_partitions(void)
102{
103    FILE *f;
104    char line[200];
105    int length;
106#ifndef DEBUG_THIS
107    int ret = system("fdisk -l 2>/dev/null 1>/tmp/fdisk.output");
108    if ((ret >> 8) != 0) {
109	error("fdisk didn't run");
110    }
111    if ((f = fopen("/tmp/fdisk.output", "r")) == NULL)
112#else
113    if ((f = fopen("FDISK.TEST", "r")) == NULL)
114#endif
115	error("cannot read fdisk output");
116
117    while (num_partition <= MAX_PARTS
118	   && (length = get_line(line, 200, f)) >= 0) {
119	if (strncmp(line, "/dev/", 5) == 0) {
120	    int n = 0;
121	    char *s = line + 5;
122	    char *t = partitions[num_partition].name;
123	    strcpy(t, "/dev/");
124	    t += 5;
125	    while (n < MAX_DEV_NAME && *s != '\0'
126		   && !isspace((unsigned char) *s)) {
127		*t++ = *s++;
128		n++;
129	    }
130	    *t = '\0';
131	    /* Read the size of the partition. */
132	    t = line + 37;
133	    while (isspace((unsigned char) *t))
134		t++;
135	    partitions[num_partition].blocks = atoi(t);
136	    if (strstr(line, "Linux native")) {
137		partitions[num_partition].type = Linux;
138		num_partition++;
139		num_linux++;
140	    } else if (strstr(line, "Linux swap")) {
141		partitions[num_partition].type = Swap;
142		num_partition++;
143		num_swap++;
144	    } else if (strstr(line, "DOS")) {
145		partitions[num_partition].type = MsDos;
146		num_partition++;
147		num_msdos++;
148	    }
149	}
150    }
151    fclose(f);
152#ifndef DEBUG_THIS
153    unlink("/tmp/fdisk.output");
154#endif
155}
156
157static int
158select_partition(const char *title, const char *prompt, int y, int x)
159{
160    int i, num, ret;
161    char info[MAX_PARTS][40];
162    char *items[MAX_PARTS * 2];
163    int num_pa[MAX_PARTS];
164
165    num = 0;
166    for (i = 0; i < num_partition; i++) {
167	if (partitions[i].type == Linux) {
168	    items[num * 2] = partitions[i].name;
169	    sprintf(info[num], "Linux partition with %d blocks",
170		    partitions[i].blocks);
171	    items[num * 2 + 1] = info[num];
172	    num_pa[num] = i;
173	    num++;
174	}
175    }
176    ret = dialog_menu(title, prompt, y + num, x, num, num, items);
177    dialog_clear();
178    if (ret >= 0)		/* item selected */
179	ret = num_pa[ret];
180    return ret;
181}
182
183static int
184select_install_partition(void)
185{
186    return select_partition("Select Install Partition",
187			    "\\nWhere do you want to install Linux?\\n", 9, 60);
188}
189
190static int
191select_source_partition(void)
192{
193    return select_partition("Select Source Partition",
194			    "\\nOn which partition is the source?\\n", 9, 60);
195}
196
197const char *null = ">/dev/null 2>/dev/null";
198const char *install_partition = NULL;
199
200static void
201extract_packages(const char *source_path)
202{
203#ifndef	DEBUG_THIS
204    FILE *f;
205#endif
206
207    if (my_system("mkdir -p /install/var/installed/packages %s", null))
208	return;
209    if (my_system("cd /install; for i in /source%s/*.tgz; do "
210		  "tar xzplvvkf $i >> var/installed/packages/base "
211		  "2>>var/installed/packages/ERROR; done", source_path))
212	return;
213#ifndef	DEBUG_THIS
214    if ((f = fopen("/install/etc/fstab", "w")) == NULL) {
215	/* i = */ dialog_msgbox("Error", "Cannot write /etc/fstab",
216				12, 40, 1);
217	return;
218    }
219    fprintf(f, "%s / ext2 defaults 1 1\n", install_partition);
220    fprintf(f, "none /proc proc defaults 0 2\n");
221    /* XXX write swap-partitions */
222    fclose(f);
223#endif
224}
225
226static void
227install_premounted(void)
228{
229    extract_packages("");
230}
231
232static void
233install_harddisk(void)
234{
235    const char *name;
236    int part, ret;
237
238    if ((part = select_source_partition()) <= -1)
239	return;
240    name = partitions[part].name;
241
242    if (my_system("mount -t ext2 %s /source %s", name, null))
243	return;
244    ret = dialog_inputbox("Path in partition",
245			  "Please enter the directory in which the "
246			  "source files are.", 13, 50, "", FALSE);
247    dialog_clear();
248    if (ret != 0)
249	return;
250    /* XXX strdup */
251    extract_packages(strdup(dialog_input_result));
252    if (my_system("umount /source %s", null))
253	return;
254}
255
256static void
257install_nfs(void)
258{
259    if (my_system("ifconfig eth0 134.96.81.36 netmask 255.255.255.224 "
260		  "broadcast 134.96.81.63 %s", null))
261	return;
262    if (my_system("route add -net 134.96.81.32 %s", null))
263	return;
264    if (my_system("mount -t nfs 134.96.81.38:"
265		  "/local/ftp/pub/linux/ELF.binary/tar /source %s", null))
266	return;
267    extract_packages("/base");
268    if (my_system("umount /source %s", null))
269	return;
270    if (my_system("ifconfig eth0 down %s", null))
271	return;
272}
273
274static void
275main_install(void)
276{
277    int part, ret;
278    const char *name;
279    char *items1[] =
280    {
281	"1", "Harddisk Install",
282	"2", "Network Install(NFS)",
283	"3", "Premounted on /source"
284    };
285
286    if (num_linux == 0) {
287	/* XXX */
288	return;
289    }
290    if ((part = select_install_partition()) <= -1)
291	return;
292    install_partition = name = partitions[part].name;
293    if (my_system("mke2fs %s %s", name, null))
294	return;
295    if (my_system("mount -t ext2 %s /install %s", name, null))
296	return;
297    ret = dialog_menu("Choose install medium",
298		      "\\nPlease say from where you want to install.\\n",
299		      12, 62, 3, 3, items1);
300    dialog_clear();
301    switch (ret) {
302    case 0:
303	install_harddisk();
304	break;
305    case 1:
306	install_nfs();
307	break;
308    case 2:
309	install_premounted();
310	break;
311    case -2:			/* cancel */
312    case -1:
313	break;			/* esc */
314    }
315    if (my_system("umount /install %s", null))
316	return;
317}
318
319int
320main(int argc, char **argv)
321{
322    int stop = 0;
323    int ret;
324    char *items1[] =
325    {
326	"1", "Display a help text",
327	"2", "Start an installation",
328	"3", "Exit to the shell"
329    };
330
331    progname = argv[0];
332
333    read_partitions();
334    if (num_linux == 0) {
335	printf("\n\nPlease start \"fdisk\" or \"cfdisk\" and create a"
336	       "\nnative Linux-partition to install Linux on.\n\n");
337	exit(1);
338    }
339
340    init_dialog();
341
342    while (!stop) {
343	ret = dialog_menu("Linux Install Utility",
344			  "\\nCopyright (C) 1995 Florian La Roche\\n"
345			  "\\nPre-Alpha version, be careful, read the doc!!!"
346			  "\\nemail: florian@jurix.jura.uni-sb.de, "
347			  "flla@stud.uni-sb.de\\n",
348			  15, 64, 3, 3, items1);
349	dialog_clear();
350	switch (ret) {
351	case 0:
352	    ret = dialog_textbox("Help Text",
353				 "setup.help", 20, 70);
354	    dialog_clear();
355	    break;
356	case 1:
357	    main_install();
358	    break;
359	case 2:
360	    stop = 1;
361	    break;
362	case -2:		/* cancel */
363	case -1:
364	    stop = 1;		/* esc */
365	}
366    }
367    end_dialog();
368    printf("\nExecute \"reboot\" to restart your computer...\n");
369
370    exit(0);
371}
372