• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2010 Intel Corp. - All Rights Reserved
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8  *   Boston MA 02111-1307, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12 
13 /*
14  * syslxopt.c
15  *
16  * parse cmdline for extlinux and syslinux installer
17  *
18  */
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <getopt.h>
25 #include <sysexits.h>
26 #include "version.h"
27 #include "syslxcom.h"
28 #include "syslxfs.h"
29 #include "syslxopt.h"
30 
31 /* These are the options we can set their values */
32 struct sys_options opt = {
33     .sectors = 0,
34     .heads = 0,
35     .raid_mode = 0,
36     .stupid_mode = 0,
37     .reset_adv = 0,
38     .set_once = NULL,
39     .update_only = -1,
40     .directory = NULL,
41     .device = NULL,
42     .offset = 0,
43     .menu_save = NULL,
44     .install_mbr = 0,
45     .activate_partition = 0,
46     .force = 0,
47     .bootsecfile = NULL,
48 };
49 
50 const struct option long_options[] = {
51     {"force", 0, NULL, 'f'},	/* DOS/Win32/mtools only */
52     {"install", 0, NULL, 'i'},
53     {"directory", 1, NULL, 'd'},
54     {"offset", 1, NULL, 't'},
55     {"update", 0, NULL, 'U'},
56     {"zipdrive", 0, NULL, 'z'},
57     {"sectors", 1, NULL, 'S'},
58     {"stupid", 0, NULL, 's'},
59     {"heads", 1, NULL, 'H'},
60     {"raid-mode", 0, NULL, 'r'},
61     {"version", 0, NULL, 'v'},
62     {"help", 0, NULL, 'h'},
63     {"once", 1, NULL, OPT_ONCE},
64     {"clear-once", 0, NULL, 'O'},
65     {"reset-adv", 0, NULL, OPT_RESET_ADV},
66     {"menu-save", 1, NULL, 'M'},
67     {"mbr", 0, NULL, 'm'},	/* DOS/Win32 only */
68     {"active", 0, NULL, 'a'},	/* DOS/Win32 only */
69     {"device", 1, NULL, OPT_DEVICE},
70     {NULL, 0, NULL, 0}
71 };
72 
73 const char short_options[] = "t:fid:UuzsS:H:rvho:OM:ma";
74 
usage(int rv,enum syslinux_mode mode)75 void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode)
76 {
77     switch (mode) {
78     case MODE_SYSLINUX:
79 	/* For unmounted fs installation (syslinux) */
80 	fprintf(stderr,
81 	    "Usage: %s [options] device\n"
82 	    "  --offset     -t  Offset of the file system on the device \n"
83 	    "  --directory  -d  Directory for installation target\n",
84 	    program);
85 	break;
86 
87     case MODE_EXTLINUX:
88 	/* Mounted fs installation (extlinux) */
89 	/* Actually extlinux can also use -d to provide a directory too... */
90 	fprintf(stderr,
91 	    "Usage: %s [options] directory\n"
92 	    "  --device         Force use of a specific block device (experts only)\n",
93 	    program);
94 	break;
95 
96     case MODE_SYSLINUX_DOSWIN:
97 	/* For fs installation under Windows (syslinux.exe) */
98 	fprintf(stderr,
99 	    "Usage: %s [options] <drive>: [bootsecfile]\n"
100 	    "  --directory  -d  Directory for installation target\n",
101 	    program);
102 	break;
103     }
104 
105     fprintf(stderr,
106 	    "  --install    -i  Install over the current bootsector\n"
107 	    "  --update     -U  Update a previous installation\n"
108 	    "  --zip        -z  Force zipdrive geometry (-H 64 -S 32)\n"
109 	    "  --sectors=#  -S  Force the number of sectors per track\n"
110 	    "  --heads=#    -H  Force number of heads\n"
111 	    "  --stupid     -s  Slow, safe and stupid mode\n"
112 	    "  --raid       -r  Fall back to the next device on boot failure\n"
113 	    "  --once=...   %s  Execute a command once upon boot\n"
114 	    "  --clear-once -O  Clear the boot-once command\n"
115 	    "  --reset-adv      Reset auxilliary data\n",
116 	    mode == MODE_SYSLINUX  ? "  " : "-o");
117     /*
118      * Have to chop this roughly in half for the DOS installer due
119      * to limited output buffer size
120      */
121     fprintf(stderr,
122 	    "  --menu-save= -M  Set the label to select as default on the next boot\n");
123     if (mode == MODE_SYSLINUX_DOSWIN)
124 	fprintf(stderr,
125 		"  --mbr        -m  Install an MBR\n"
126 		"  --active     -a  Mark partition as active\n");
127 
128     if (mode == MODE_SYSLINUX_DOSWIN || mode == MODE_SYSLINUX)
129 	fprintf(stderr,
130 		"  --force      -f  Ignore precautions\n");
131 
132     exit(rv);
133 }
134 
parse_options(int argc,char * argv[],enum syslinux_mode mode)135 void parse_options(int argc, char *argv[], enum syslinux_mode mode)
136 {
137     int o;
138 
139     program = argv[0];
140     while ((o = getopt_long(argc, argv, short_options,
141 			    long_options, NULL)) != EOF) {
142 	switch (o) {
143 	case 'f':
144 	    opt.force = 1;
145 	    break;
146 	case 'z':
147 	    opt.heads = 64;
148 	    opt.sectors = 32;
149 	    break;
150 	case 'S':
151 	    opt.sectors = strtoul(optarg, NULL, 0);
152 	    if (opt.sectors < 1 || opt.sectors > 63) {
153 		fprintf(stderr,
154 			"%s: invalid number of sectors: %u (must be 1-63)\n",
155 			program, opt.sectors);
156 		exit(EX_USAGE);
157 	    }
158 	    break;
159 	case 'H':
160 	    opt.heads = strtoul(optarg, NULL, 0);
161 	    if (opt.heads < 1 || opt.heads > 256) {
162 		fprintf(stderr,
163 			"%s: invalid number of heads: %u (must be 1-256)\n",
164 			program, opt.heads);
165 		exit(EX_USAGE);
166 	    }
167 	    break;
168 	case 'r':
169 	    opt.raid_mode = 1;
170 	    break;
171 	case 's':
172 	    opt.stupid_mode = 1;
173 	    break;
174 	case 'i':
175 	    opt.update_only = 0;
176 	    break;
177 	case 'u':
178 	case 'U':
179 	    opt.update_only = 1;
180 	    break;
181 	case 'h':
182 	    usage(0, mode);
183 	    break;
184 	case 'o':
185 	    if (mode == MODE_SYSLINUX) {
186 		fprintf(stderr,	"%s: -o will change meaning in a future version, use -t or --offset\n", program);
187 		goto opt_offset;
188 	    }
189 	    /* else fall through */
190 	case OPT_ONCE:
191 	    opt.set_once = optarg;
192 	    break;
193 	case 't':
194 	opt_offset:
195 	    opt.offset = strtoul(optarg, NULL, 0);
196 	    break;
197 	case 'O':
198 	    opt.set_once = "";
199 	    break;
200 	case 'd':
201 	    opt.directory = optarg;
202 	    break;
203 	case OPT_RESET_ADV:
204 	    opt.reset_adv = 1;
205 	    break;
206 	case 'M':
207 	    opt.menu_save = optarg;
208 	    break;
209 	case 'm':
210 	    opt.install_mbr = 1;
211 	    break;
212 	case 'a':
213 	    opt.activate_partition = 1;
214 	    break;
215 	case OPT_DEVICE:
216 	    if (mode != MODE_EXTLINUX)
217 		usage(EX_USAGE, mode);
218 	    opt.device = optarg;
219 	    break;
220 	case 'v':
221 	    fprintf(stderr,
222 		    "%s " VERSION_STR "  Copyright 1994-" YEAR_STR
223 		    " H. Peter Anvin et al\n", program);
224 	    exit(0);
225 	default:
226 	    fprintf(stderr, "%s: Unknown option: -%c\n", program, optopt);
227 	    usage(EX_USAGE, mode);
228 	}
229     }
230 
231     switch (mode) {
232     case MODE_SYSLINUX:
233     case MODE_SYSLINUX_DOSWIN:
234 	opt.device = argv[optind++];
235 	break;
236     case MODE_EXTLINUX:
237 	if (!opt.directory)
238 	    opt.directory = argv[optind++];
239 	break;
240     }
241 
242     if (argv[optind] && (mode == MODE_SYSLINUX_DOSWIN))
243 	/* Allow for the boot-sector argument */
244 	opt.bootsecfile = argv[optind++];
245     if (argv[optind])
246 	usage(EX_USAGE, mode);	/* Excess arguments */
247 }
248 
249 /*
250  * Make any user-specified ADV modifications in memory
251  */
modify_adv(void)252 int modify_adv(void)
253 {
254     int rv = 0;
255 
256     if (opt.reset_adv)
257 	syslinux_reset_adv(syslinux_adv);
258 
259     if (opt.set_once) {
260 	if (syslinux_setadv(ADV_BOOTONCE, strlen(opt.set_once), opt.set_once)) {
261 	    fprintf(stderr, "%s: not enough space for boot-once command\n",
262 		    program);
263 	    rv = -1;
264 	}
265     }
266     if (opt.menu_save) {
267         if (syslinux_setadv(ADV_MENUSAVE, strlen(opt.menu_save), opt.menu_save)) {
268 	    fprintf(stderr, "%s: not enough space for menu-save label\n",
269 		    program);
270 	    rv = -1;
271         }
272     }
273 
274     return rv;
275 }
276