Home | History | Annotate | Download | only in libinstaller
      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 
     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 
    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  */
    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