10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
55589Ssy25831 * Common Development and Distribution License (the "License").
65589Ssy25831 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12947SEnrico.Perla@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include <stdio.h>
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include <libgen.h>
280Sstevel@tonic-gate #include <malloc.h>
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <fcntl.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <strings.h>
33*12947SEnrico.Perla@Sun.COM #include <libintl.h>
34*12947SEnrico.Perla@Sun.COM #include <locale.h>
35*12947SEnrico.Perla@Sun.COM #include <errno.h>
36*12947SEnrico.Perla@Sun.COM #include <libfdisk.h>
37*12947SEnrico.Perla@Sun.COM #include <stdarg.h>
38*12947SEnrico.Perla@Sun.COM #include <assert.h>
39*12947SEnrico.Perla@Sun.COM
400Sstevel@tonic-gate #include <sys/mount.h>
410Sstevel@tonic-gate #include <sys/mnttab.h>
420Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
435589Ssy25831 #include <sys/dkio.h>
445589Ssy25831 #include <sys/vtoc.h>
45*12947SEnrico.Perla@Sun.COM #include <sys/types.h>
46*12947SEnrico.Perla@Sun.COM #include <sys/stat.h>
47*12947SEnrico.Perla@Sun.COM #include <sys/multiboot.h>
48*12947SEnrico.Perla@Sun.COM #include <sys/sysmacros.h>
490Sstevel@tonic-gate
500Sstevel@tonic-gate #include "message.h"
51*12947SEnrico.Perla@Sun.COM #include "installgrub.h"
52*12947SEnrico.Perla@Sun.COM #include "./../common/bblk_einfo.h"
53*12947SEnrico.Perla@Sun.COM #include "./../common/boot_utils.h"
54*12947SEnrico.Perla@Sun.COM #include "./../common/mboot_extra.h"
550Sstevel@tonic-gate
560Sstevel@tonic-gate #ifndef TEXT_DOMAIN
570Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD"
580Sstevel@tonic-gate #endif
590Sstevel@tonic-gate
60*12947SEnrico.Perla@Sun.COM /*
61*12947SEnrico.Perla@Sun.COM * Variables to track installgrub desired mode of operation.
62*12947SEnrico.Perla@Sun.COM * 'nowrite' and 'boot_debug' come from boot_common.h.
63*12947SEnrico.Perla@Sun.COM */
64*12947SEnrico.Perla@Sun.COM static boolean_t write_mbr = B_FALSE;
65*12947SEnrico.Perla@Sun.COM static boolean_t force_mbr = B_FALSE;
66*12947SEnrico.Perla@Sun.COM static boolean_t force_update = B_FALSE;
67*12947SEnrico.Perla@Sun.COM static boolean_t do_getinfo = B_FALSE;
68*12947SEnrico.Perla@Sun.COM static boolean_t do_version = B_FALSE;
69*12947SEnrico.Perla@Sun.COM static boolean_t do_mirror_bblk = B_FALSE;
70*12947SEnrico.Perla@Sun.COM static boolean_t strip = B_FALSE;
71*12947SEnrico.Perla@Sun.COM static boolean_t verbose_dump = B_FALSE;
720Sstevel@tonic-gate
73*12947SEnrico.Perla@Sun.COM /* Installing the bootblock is the default operation. */
74*12947SEnrico.Perla@Sun.COM static boolean_t do_install = B_TRUE;
75*12947SEnrico.Perla@Sun.COM
76*12947SEnrico.Perla@Sun.COM /* Versioning string, if present. */
77*12947SEnrico.Perla@Sun.COM static char *update_str;
780Sstevel@tonic-gate
79*12947SEnrico.Perla@Sun.COM /*
80*12947SEnrico.Perla@Sun.COM * Temporary buffer to store the first 32K of data looking for a multiboot
81*12947SEnrico.Perla@Sun.COM * signature.
82*12947SEnrico.Perla@Sun.COM */
83*12947SEnrico.Perla@Sun.COM char mboot_scan[MBOOT_SCAN_SIZE];
848434SEnrico.Perla@Sun.COM
85*12947SEnrico.Perla@Sun.COM /* Function prototypes. */
86*12947SEnrico.Perla@Sun.COM static void check_options(char *);
87*12947SEnrico.Perla@Sun.COM static int handle_install(char *, char **);
88*12947SEnrico.Perla@Sun.COM static int handle_mirror(char *, char **);
89*12947SEnrico.Perla@Sun.COM static int handle_getinfo(char *, char **);
90*12947SEnrico.Perla@Sun.COM static int commit_to_disk(ig_data_t *, char *);
91*12947SEnrico.Perla@Sun.COM static int init_device(ig_device_t *, char *path);
92*12947SEnrico.Perla@Sun.COM static void cleanup_device(ig_device_t *);
93*12947SEnrico.Perla@Sun.COM static void cleanup_stage2(ig_stage2_t *);
94*12947SEnrico.Perla@Sun.COM static int get_start_sector(ig_device_t *);
95*12947SEnrico.Perla@Sun.COM static int get_disk_fd(ig_device_t *device);
96*12947SEnrico.Perla@Sun.COM static int get_raw_partition_fd(ig_device_t *);
97*12947SEnrico.Perla@Sun.COM static char *get_raw_partition_path(ig_device_t *);
98*12947SEnrico.Perla@Sun.COM static boolean_t gather_stage2_from_dev(ig_data_t *);
99*12947SEnrico.Perla@Sun.COM static int propagate_bootblock(ig_data_t *, ig_data_t *, char *);
100*12947SEnrico.Perla@Sun.COM static int find_x86_bootpar(struct mboot *, int *, uint32_t *);
101*12947SEnrico.Perla@Sun.COM static int copy_stage2_to_pcfs(ig_data_t *);
102*12947SEnrico.Perla@Sun.COM static int write_stage2(ig_data_t *);
103*12947SEnrico.Perla@Sun.COM static int write_stage1(ig_data_t *);
1040Sstevel@tonic-gate static void usage(char *);
105*12947SEnrico.Perla@Sun.COM static int read_stage1_from_file(char *, ig_data_t *);
106*12947SEnrico.Perla@Sun.COM static int read_stage2_from_file(char *, ig_data_t *);
107*12947SEnrico.Perla@Sun.COM static int read_stage1_from_disk(int, char *);
108*12947SEnrico.Perla@Sun.COM static int read_stage2_from_disk(int, ig_stage2_t *);
109*12947SEnrico.Perla@Sun.COM static int prepare_stage1(ig_data_t *);
110*12947SEnrico.Perla@Sun.COM static int prepare_stage2(ig_data_t *, char *);
111*12947SEnrico.Perla@Sun.COM static void prepare_fake_multiboot(ig_stage2_t *);
112*12947SEnrico.Perla@Sun.COM static void add_stage2_einfo(ig_stage2_t *, char *updt_str);
113*12947SEnrico.Perla@Sun.COM static boolean_t is_update_necessary(ig_data_t *, char *);
1140Sstevel@tonic-gate
1157563SPrasad.Singamsetty@Sun.COM extern int read_stage2_blocklist(int, unsigned int *);
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate int
main(int argc,char * argv[])1180Sstevel@tonic-gate main(int argc, char *argv[])
1190Sstevel@tonic-gate {
120*12947SEnrico.Perla@Sun.COM int opt;
121*12947SEnrico.Perla@Sun.COM int params = 3;
122*12947SEnrico.Perla@Sun.COM int ret;
123*12947SEnrico.Perla@Sun.COM char **handle_args;
124*12947SEnrico.Perla@Sun.COM char *progname;
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1270Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1280Sstevel@tonic-gate
129*12947SEnrico.Perla@Sun.COM /*
130*12947SEnrico.Perla@Sun.COM * retro-compatibility: installing the bootblock is the default
131*12947SEnrico.Perla@Sun.COM * and there is no switch for it.
132*12947SEnrico.Perla@Sun.COM */
133*12947SEnrico.Perla@Sun.COM do_install = B_TRUE;
134*12947SEnrico.Perla@Sun.COM
135*12947SEnrico.Perla@Sun.COM while ((opt = getopt(argc, argv, "dVMFfmneiu:")) != EOF) {
1360Sstevel@tonic-gate switch (opt) {
1370Sstevel@tonic-gate case 'm':
138*12947SEnrico.Perla@Sun.COM write_mbr = B_TRUE;
1390Sstevel@tonic-gate break;
1400Sstevel@tonic-gate case 'n':
141*12947SEnrico.Perla@Sun.COM nowrite = B_TRUE;
1420Sstevel@tonic-gate break;
1430Sstevel@tonic-gate case 'f':
144*12947SEnrico.Perla@Sun.COM force_mbr = B_TRUE;
1450Sstevel@tonic-gate break;
1468434SEnrico.Perla@Sun.COM case 'i':
147*12947SEnrico.Perla@Sun.COM do_getinfo = B_TRUE;
148*12947SEnrico.Perla@Sun.COM do_install = B_FALSE;
1498434SEnrico.Perla@Sun.COM params = 1;
1508434SEnrico.Perla@Sun.COM break;
151*12947SEnrico.Perla@Sun.COM case 'V':
152*12947SEnrico.Perla@Sun.COM verbose_dump = B_TRUE;
153*12947SEnrico.Perla@Sun.COM break;
154*12947SEnrico.Perla@Sun.COM case 'd':
155*12947SEnrico.Perla@Sun.COM boot_debug = B_TRUE;
156*12947SEnrico.Perla@Sun.COM break;
157*12947SEnrico.Perla@Sun.COM case 'F':
158*12947SEnrico.Perla@Sun.COM force_update = B_TRUE;
159*12947SEnrico.Perla@Sun.COM break;
1608434SEnrico.Perla@Sun.COM case 'e':
161*12947SEnrico.Perla@Sun.COM strip = B_TRUE;
162*12947SEnrico.Perla@Sun.COM break;
163*12947SEnrico.Perla@Sun.COM case 'M':
164*12947SEnrico.Perla@Sun.COM do_mirror_bblk = B_TRUE;
165*12947SEnrico.Perla@Sun.COM do_install = B_FALSE;
166*12947SEnrico.Perla@Sun.COM params = 2;
1678434SEnrico.Perla@Sun.COM break;
168*12947SEnrico.Perla@Sun.COM case 'u':
169*12947SEnrico.Perla@Sun.COM do_version = B_TRUE;
170*12947SEnrico.Perla@Sun.COM
171*12947SEnrico.Perla@Sun.COM update_str = malloc(strlen(optarg) + 1);
172*12947SEnrico.Perla@Sun.COM if (update_str == NULL) {
173*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to "
174*12947SEnrico.Perla@Sun.COM "allocate memory\n"));
175*12947SEnrico.Perla@Sun.COM exit(BC_ERROR);
176*12947SEnrico.Perla@Sun.COM }
177*12947SEnrico.Perla@Sun.COM (void) strlcpy(update_str, optarg, strlen(optarg) + 1);
1788434SEnrico.Perla@Sun.COM break;
1790Sstevel@tonic-gate default:
1800Sstevel@tonic-gate /* fall through to process non-optional args */
1810Sstevel@tonic-gate break;
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate /* check arguments */
1868434SEnrico.Perla@Sun.COM if (argc != optind + params) {
1870Sstevel@tonic-gate usage(argv[0]);
188*12947SEnrico.Perla@Sun.COM exit(BC_ERROR);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate
191*12947SEnrico.Perla@Sun.COM /*
192*12947SEnrico.Perla@Sun.COM * clean up options (and bail out if an unrecoverable combination is
193*12947SEnrico.Perla@Sun.COM * requested.
194*12947SEnrico.Perla@Sun.COM */
195*12947SEnrico.Perla@Sun.COM progname = argv[0];
196*12947SEnrico.Perla@Sun.COM check_options(progname);
197*12947SEnrico.Perla@Sun.COM handle_args = argv + optind;
198*12947SEnrico.Perla@Sun.COM
199*12947SEnrico.Perla@Sun.COM if (nowrite)
200*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, DRY_RUN);
201*12947SEnrico.Perla@Sun.COM
202*12947SEnrico.Perla@Sun.COM if (do_getinfo) {
203*12947SEnrico.Perla@Sun.COM ret = handle_getinfo(progname, handle_args);
204*12947SEnrico.Perla@Sun.COM } else if (do_mirror_bblk) {
205*12947SEnrico.Perla@Sun.COM ret = handle_mirror(progname, handle_args);
206*12947SEnrico.Perla@Sun.COM } else {
207*12947SEnrico.Perla@Sun.COM ret = handle_install(progname, handle_args);
208*12947SEnrico.Perla@Sun.COM }
209*12947SEnrico.Perla@Sun.COM return (ret);
210*12947SEnrico.Perla@Sun.COM }
211*12947SEnrico.Perla@Sun.COM
212*12947SEnrico.Perla@Sun.COM #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n")
213*12947SEnrico.Perla@Sun.COM static void
check_options(char * progname)214*12947SEnrico.Perla@Sun.COM check_options(char *progname)
215*12947SEnrico.Perla@Sun.COM {
216*12947SEnrico.Perla@Sun.COM if (do_getinfo && do_mirror_bblk) {
217*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Only one of -M and -i can be "
218*12947SEnrico.Perla@Sun.COM "specified at the same time\n"));
219*12947SEnrico.Perla@Sun.COM usage(progname);
220*12947SEnrico.Perla@Sun.COM exit(BC_ERROR);
221*12947SEnrico.Perla@Sun.COM }
222*12947SEnrico.Perla@Sun.COM
223*12947SEnrico.Perla@Sun.COM if (do_mirror_bblk) {
224*12947SEnrico.Perla@Sun.COM /*
225*12947SEnrico.Perla@Sun.COM * -u and -F may actually reflect a user intent that is not
226*12947SEnrico.Perla@Sun.COM * correct with this command (mirror can be interpreted
227*12947SEnrico.Perla@Sun.COM * "similar" to install. Emit a message and continue.
228*12947SEnrico.Perla@Sun.COM * -e and -V have no meaning, be quiet here and only report the
229*12947SEnrico.Perla@Sun.COM * incongruence if a debug output is requested.
230*12947SEnrico.Perla@Sun.COM */
231*12947SEnrico.Perla@Sun.COM if (do_version) {
232*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, MEANINGLESS_OPT, "-u");
233*12947SEnrico.Perla@Sun.COM do_version = B_FALSE;
2348434SEnrico.Perla@Sun.COM }
235*12947SEnrico.Perla@Sun.COM if (force_update) {
236*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, MEANINGLESS_OPT, "-F");
237*12947SEnrico.Perla@Sun.COM force_update = B_FALSE;
238*12947SEnrico.Perla@Sun.COM }
239*12947SEnrico.Perla@Sun.COM if (strip || verbose_dump) {
240*12947SEnrico.Perla@Sun.COM BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
241*12947SEnrico.Perla@Sun.COM strip = B_FALSE;
242*12947SEnrico.Perla@Sun.COM verbose_dump = B_FALSE;
2438434SEnrico.Perla@Sun.COM }
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate
246*12947SEnrico.Perla@Sun.COM if (do_getinfo) {
247*12947SEnrico.Perla@Sun.COM if (write_mbr || force_mbr || do_version || force_update) {
248*12947SEnrico.Perla@Sun.COM BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
249*12947SEnrico.Perla@Sun.COM write_mbr = force_mbr = do_version = B_FALSE;
250*12947SEnrico.Perla@Sun.COM force_update = B_FALSE;
251*12947SEnrico.Perla@Sun.COM }
252*12947SEnrico.Perla@Sun.COM }
253*12947SEnrico.Perla@Sun.COM }
254*12947SEnrico.Perla@Sun.COM
255*12947SEnrico.Perla@Sun.COM /*
256*12947SEnrico.Perla@Sun.COM * Install a new stage1/stage2 pair on the specified device. handle_install()
257*12947SEnrico.Perla@Sun.COM * expects argv to contain 3 parameters (the path to stage1, the path to stage2,
258*12947SEnrico.Perla@Sun.COM * the target device).
259*12947SEnrico.Perla@Sun.COM *
260*12947SEnrico.Perla@Sun.COM * Returns: BC_SUCCESS - if the installation is successful
261*12947SEnrico.Perla@Sun.COM * BC_ERROR - if the installation failed
262*12947SEnrico.Perla@Sun.COM * BC_NOUPDT - if no installation was performed because the GRUB
263*12947SEnrico.Perla@Sun.COM * version currently installed is more recent than the
264*12947SEnrico.Perla@Sun.COM * supplied one.
265*12947SEnrico.Perla@Sun.COM *
266*12947SEnrico.Perla@Sun.COM */
267*12947SEnrico.Perla@Sun.COM static int
handle_install(char * progname,char ** argv)268*12947SEnrico.Perla@Sun.COM handle_install(char *progname, char **argv)
269*12947SEnrico.Perla@Sun.COM {
270*12947SEnrico.Perla@Sun.COM ig_data_t install_data;
271*12947SEnrico.Perla@Sun.COM char *stage1_path = NULL;
272*12947SEnrico.Perla@Sun.COM char *stage2_path = NULL;
273*12947SEnrico.Perla@Sun.COM char *device_path = NULL;
274*12947SEnrico.Perla@Sun.COM int ret = BC_ERROR;
2750Sstevel@tonic-gate
276*12947SEnrico.Perla@Sun.COM stage1_path = strdup(argv[0]);
277*12947SEnrico.Perla@Sun.COM stage2_path = strdup(argv[1]);
278*12947SEnrico.Perla@Sun.COM device_path = strdup(argv[2]);
279*12947SEnrico.Perla@Sun.COM
280*12947SEnrico.Perla@Sun.COM bzero(&install_data, sizeof (ig_data_t));
281*12947SEnrico.Perla@Sun.COM
282*12947SEnrico.Perla@Sun.COM if (!stage1_path || !stage2_path || !device_path) {
283*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Missing parameter"));
284*12947SEnrico.Perla@Sun.COM usage(progname);
285*12947SEnrico.Perla@Sun.COM goto out;
286*12947SEnrico.Perla@Sun.COM }
287*12947SEnrico.Perla@Sun.COM
288*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("stage1 path: %s, stage2 path: %s, device: %s\n",
289*12947SEnrico.Perla@Sun.COM stage1_path, stage2_path, device_path);
290*12947SEnrico.Perla@Sun.COM
291*12947SEnrico.Perla@Sun.COM if (init_device(&install_data.device, device_path) != BC_SUCCESS) {
292*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to gather device "
293*12947SEnrico.Perla@Sun.COM "information for %s\n"), device_path);
294*12947SEnrico.Perla@Sun.COM goto out;
295*12947SEnrico.Perla@Sun.COM }
296*12947SEnrico.Perla@Sun.COM
297*12947SEnrico.Perla@Sun.COM /* read in stage1 and stage2. */
298*12947SEnrico.Perla@Sun.COM if (read_stage1_from_file(stage1_path, &install_data) != BC_SUCCESS) {
299*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error opening %s\n"),
300*12947SEnrico.Perla@Sun.COM stage1_path);
301*12947SEnrico.Perla@Sun.COM goto out_dev;
302*12947SEnrico.Perla@Sun.COM }
303*12947SEnrico.Perla@Sun.COM
304*12947SEnrico.Perla@Sun.COM if (read_stage2_from_file(stage2_path, &install_data) != BC_SUCCESS) {
305*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error opening %s\n"),
306*12947SEnrico.Perla@Sun.COM stage2_path);
307*12947SEnrico.Perla@Sun.COM goto out_dev;
3088434SEnrico.Perla@Sun.COM }
3098434SEnrico.Perla@Sun.COM
310*12947SEnrico.Perla@Sun.COM /* We do not support versioning on PCFS. */
311*12947SEnrico.Perla@Sun.COM if (is_bootpar(install_data.device.type) && do_version)
312*12947SEnrico.Perla@Sun.COM do_version = B_FALSE;
313*12947SEnrico.Perla@Sun.COM
314*12947SEnrico.Perla@Sun.COM /*
315*12947SEnrico.Perla@Sun.COM * is_update_necessary() will take care of checking if versioning and/or
316*12947SEnrico.Perla@Sun.COM * forcing the update have been specified. It will also emit a warning
317*12947SEnrico.Perla@Sun.COM * if a non-versioned update is attempted over a versioned bootblock.
318*12947SEnrico.Perla@Sun.COM */
319*12947SEnrico.Perla@Sun.COM if (!is_update_necessary(&install_data, update_str)) {
320*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("GRUB version installed "
321*12947SEnrico.Perla@Sun.COM "on %s is more recent or identical\n"
322*12947SEnrico.Perla@Sun.COM "Use -F to override or install without the -u option\n"),
323*12947SEnrico.Perla@Sun.COM device_path);
324*12947SEnrico.Perla@Sun.COM ret = BC_NOUPDT;
325*12947SEnrico.Perla@Sun.COM goto out_dev;
326*12947SEnrico.Perla@Sun.COM }
327*12947SEnrico.Perla@Sun.COM /*
328*12947SEnrico.Perla@Sun.COM * We get here if:
329*12947SEnrico.Perla@Sun.COM * - the installed GRUB version is older than the one about to be
330*12947SEnrico.Perla@Sun.COM * installed.
331*12947SEnrico.Perla@Sun.COM * - no versioning string has been passed through the command line.
332*12947SEnrico.Perla@Sun.COM * - a forced update is requested (-F).
333*12947SEnrico.Perla@Sun.COM */
334*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Ready to commit to disk\n");
335*12947SEnrico.Perla@Sun.COM ret = commit_to_disk(&install_data, update_str);
336*12947SEnrico.Perla@Sun.COM
337*12947SEnrico.Perla@Sun.COM out_dev:
338*12947SEnrico.Perla@Sun.COM cleanup_device(&install_data.device);
339*12947SEnrico.Perla@Sun.COM out:
340*12947SEnrico.Perla@Sun.COM free(stage1_path);
341*12947SEnrico.Perla@Sun.COM free(stage2_path);
342*12947SEnrico.Perla@Sun.COM free(device_path);
343*12947SEnrico.Perla@Sun.COM return (ret);
344*12947SEnrico.Perla@Sun.COM }
345*12947SEnrico.Perla@Sun.COM
346*12947SEnrico.Perla@Sun.COM /*
347*12947SEnrico.Perla@Sun.COM * Retrieves from a device the extended information (einfo) associated to the
348*12947SEnrico.Perla@Sun.COM * installed stage2.
349*12947SEnrico.Perla@Sun.COM * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0.
350*12947SEnrico.Perla@Sun.COM * Returns:
351*12947SEnrico.Perla@Sun.COM * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
352*12947SEnrico.Perla@Sun.COM * - BC_ERROR (on error)
353*12947SEnrico.Perla@Sun.COM * - BC_NOEINFO (no extended information available)
354*12947SEnrico.Perla@Sun.COM */
355*12947SEnrico.Perla@Sun.COM static int
handle_getinfo(char * progname,char ** argv)356*12947SEnrico.Perla@Sun.COM handle_getinfo(char *progname, char **argv)
357*12947SEnrico.Perla@Sun.COM {
358*12947SEnrico.Perla@Sun.COM ig_data_t data;
359*12947SEnrico.Perla@Sun.COM ig_stage2_t *stage2 = &data.stage2;
360*12947SEnrico.Perla@Sun.COM ig_device_t *device = &data.device;
361*12947SEnrico.Perla@Sun.COM bblk_einfo_t *einfo;
362*12947SEnrico.Perla@Sun.COM uint8_t flags = 0;
363*12947SEnrico.Perla@Sun.COM uint32_t size;
364*12947SEnrico.Perla@Sun.COM char *device_path;
365*12947SEnrico.Perla@Sun.COM int retval = BC_ERROR;
366*12947SEnrico.Perla@Sun.COM int ret;
367*12947SEnrico.Perla@Sun.COM
368*12947SEnrico.Perla@Sun.COM device_path = strdup(argv[0]);
369*12947SEnrico.Perla@Sun.COM if (!device_path) {
370*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Missing parameter"));
371*12947SEnrico.Perla@Sun.COM usage(progname);
372*12947SEnrico.Perla@Sun.COM goto out;
373*12947SEnrico.Perla@Sun.COM }
374*12947SEnrico.Perla@Sun.COM
375*12947SEnrico.Perla@Sun.COM bzero(&data, sizeof (ig_data_t));
376*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("device path: %s\n", device_path);
377*12947SEnrico.Perla@Sun.COM
378*12947SEnrico.Perla@Sun.COM if (init_device(device, device_path) != BC_SUCCESS) {
379*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to gather device "
380*12947SEnrico.Perla@Sun.COM "information for %s\n"), device_path);
381*12947SEnrico.Perla@Sun.COM goto out_dev;
382*12947SEnrico.Perla@Sun.COM }
383*12947SEnrico.Perla@Sun.COM
384*12947SEnrico.Perla@Sun.COM if (is_bootpar(device->type)) {
385*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Versioning not supported on "
386*12947SEnrico.Perla@Sun.COM "PCFS\n"));
387*12947SEnrico.Perla@Sun.COM goto out_dev;
388*12947SEnrico.Perla@Sun.COM }
3890Sstevel@tonic-gate
390*12947SEnrico.Perla@Sun.COM ret = read_stage2_from_disk(device->part_fd, stage2);
391*12947SEnrico.Perla@Sun.COM if (ret == BC_ERROR) {
392*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error reading stage2 from "
393*12947SEnrico.Perla@Sun.COM "%s\n"), device_path);
394*12947SEnrico.Perla@Sun.COM goto out_dev;
395*12947SEnrico.Perla@Sun.COM }
396*12947SEnrico.Perla@Sun.COM
397*12947SEnrico.Perla@Sun.COM if (ret == BC_NOEXTRA) {
398*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, gettext("No multiboot header found on "
399*12947SEnrico.Perla@Sun.COM "%s, unable to locate extra information area\n"),
400*12947SEnrico.Perla@Sun.COM device_path);
401*12947SEnrico.Perla@Sun.COM retval = BC_NOEINFO;
402*12947SEnrico.Perla@Sun.COM goto out_dev;
403*12947SEnrico.Perla@Sun.COM }
404*12947SEnrico.Perla@Sun.COM
405*12947SEnrico.Perla@Sun.COM einfo = find_einfo(stage2->extra);
406*12947SEnrico.Perla@Sun.COM if (einfo == NULL) {
407*12947SEnrico.Perla@Sun.COM retval = BC_NOEINFO;
408*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("No extended information "
409*12947SEnrico.Perla@Sun.COM "found\n"));
410*12947SEnrico.Perla@Sun.COM goto out_dev;
411*12947SEnrico.Perla@Sun.COM }
412*12947SEnrico.Perla@Sun.COM
413*12947SEnrico.Perla@Sun.COM /* Print the extended information. */
414*12947SEnrico.Perla@Sun.COM if (strip)
415*12947SEnrico.Perla@Sun.COM flags |= EINFO_EASY_PARSE;
416*12947SEnrico.Perla@Sun.COM if (verbose_dump)
417*12947SEnrico.Perla@Sun.COM flags |= EINFO_PRINT_HEADER;
418*12947SEnrico.Perla@Sun.COM
419*12947SEnrico.Perla@Sun.COM size = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8);
420*12947SEnrico.Perla@Sun.COM print_einfo(flags, einfo, size);
421*12947SEnrico.Perla@Sun.COM retval = BC_SUCCESS;
422*12947SEnrico.Perla@Sun.COM
423*12947SEnrico.Perla@Sun.COM out_dev:
424*12947SEnrico.Perla@Sun.COM cleanup_device(&data.device);
425*12947SEnrico.Perla@Sun.COM out:
426*12947SEnrico.Perla@Sun.COM free(device_path);
427*12947SEnrico.Perla@Sun.COM return (retval);
428*12947SEnrico.Perla@Sun.COM }
4298434SEnrico.Perla@Sun.COM
430*12947SEnrico.Perla@Sun.COM /*
431*12947SEnrico.Perla@Sun.COM * Attempt to mirror (propagate) the current stage2 over the attaching disk.
432*12947SEnrico.Perla@Sun.COM *
433*12947SEnrico.Perla@Sun.COM * Returns:
434*12947SEnrico.Perla@Sun.COM * - BC_SUCCESS (a successful propagation happened)
435*12947SEnrico.Perla@Sun.COM * - BC_ERROR (an error occurred)
436*12947SEnrico.Perla@Sun.COM * - BC_NOEXTRA (it is not possible to dump the current bootblock since
437*12947SEnrico.Perla@Sun.COM * there is no multiboot information)
438*12947SEnrico.Perla@Sun.COM */
439*12947SEnrico.Perla@Sun.COM static int
handle_mirror(char * progname,char ** argv)440*12947SEnrico.Perla@Sun.COM handle_mirror(char *progname, char **argv)
441*12947SEnrico.Perla@Sun.COM {
442*12947SEnrico.Perla@Sun.COM ig_data_t curr_data;
443*12947SEnrico.Perla@Sun.COM ig_data_t attach_data;
444*12947SEnrico.Perla@Sun.COM ig_device_t *curr_device = &curr_data.device;
445*12947SEnrico.Perla@Sun.COM ig_device_t *attach_device = &attach_data.device;
446*12947SEnrico.Perla@Sun.COM ig_stage2_t *stage2_curr = &curr_data.stage2;
447*12947SEnrico.Perla@Sun.COM ig_stage2_t *stage2_attach = &attach_data.stage2;
448*12947SEnrico.Perla@Sun.COM bblk_einfo_t *einfo_curr = NULL;
449*12947SEnrico.Perla@Sun.COM char *curr_device_path;
450*12947SEnrico.Perla@Sun.COM char *attach_device_path;
451*12947SEnrico.Perla@Sun.COM char *updt_str = NULL;
452*12947SEnrico.Perla@Sun.COM int retval = BC_ERROR;
453*12947SEnrico.Perla@Sun.COM int ret;
454*12947SEnrico.Perla@Sun.COM
455*12947SEnrico.Perla@Sun.COM curr_device_path = strdup(argv[0]);
456*12947SEnrico.Perla@Sun.COM attach_device_path = strdup(argv[1]);
457*12947SEnrico.Perla@Sun.COM
458*12947SEnrico.Perla@Sun.COM if (!curr_device_path || !attach_device_path) {
459*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Missing parameter"));
460*12947SEnrico.Perla@Sun.COM usage(progname);
461*12947SEnrico.Perla@Sun.COM goto out;
462*12947SEnrico.Perla@Sun.COM }
463*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Current device path is: %s, attaching device path is: "
464*12947SEnrico.Perla@Sun.COM " %s\n", curr_device_path, attach_device_path);
465*12947SEnrico.Perla@Sun.COM
466*12947SEnrico.Perla@Sun.COM bzero(&curr_data, sizeof (ig_data_t));
467*12947SEnrico.Perla@Sun.COM bzero(&attach_data, sizeof (ig_data_t));
468*12947SEnrico.Perla@Sun.COM
469*12947SEnrico.Perla@Sun.COM if (init_device(curr_device, curr_device_path) != BC_SUCCESS) {
470*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to gather device "
471*12947SEnrico.Perla@Sun.COM "information for %s (current device)\n"), curr_device_path);
472*12947SEnrico.Perla@Sun.COM goto out_currdev;
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate
475*12947SEnrico.Perla@Sun.COM if (init_device(attach_device, attach_device_path) != BC_SUCCESS) {
476*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to gather device "
477*12947SEnrico.Perla@Sun.COM "information for %s (attaching device)\n"),
478*12947SEnrico.Perla@Sun.COM attach_device_path);
479*12947SEnrico.Perla@Sun.COM goto out_devs;
480*12947SEnrico.Perla@Sun.COM }
481*12947SEnrico.Perla@Sun.COM
482*12947SEnrico.Perla@Sun.COM if (is_bootpar(curr_device->type) || is_bootpar(attach_device->type)) {
483*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("boot block mirroring is not "
484*12947SEnrico.Perla@Sun.COM "supported on PCFS\n"));
485*12947SEnrico.Perla@Sun.COM goto out_devs;
486*12947SEnrico.Perla@Sun.COM }
4870Sstevel@tonic-gate
488*12947SEnrico.Perla@Sun.COM ret = read_stage2_from_disk(curr_device->part_fd, stage2_curr);
489*12947SEnrico.Perla@Sun.COM if (ret == BC_ERROR) {
490*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error reading first stage2 blocks from %s\n",
491*12947SEnrico.Perla@Sun.COM curr_device->path);
492*12947SEnrico.Perla@Sun.COM retval = BC_ERROR;
493*12947SEnrico.Perla@Sun.COM goto out_devs;
494*12947SEnrico.Perla@Sun.COM }
4950Sstevel@tonic-gate
496*12947SEnrico.Perla@Sun.COM if (ret == BC_NOEXTRA) {
497*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("No multiboot header found on %s, unable to grab "
498*12947SEnrico.Perla@Sun.COM "stage2\n", curr_device->path);
499*12947SEnrico.Perla@Sun.COM retval = BC_NOEXTRA;
500*12947SEnrico.Perla@Sun.COM goto out_devs;
501*12947SEnrico.Perla@Sun.COM }
502*12947SEnrico.Perla@Sun.COM
503*12947SEnrico.Perla@Sun.COM einfo_curr = find_einfo(stage2_curr->extra);
504*12947SEnrico.Perla@Sun.COM if (einfo_curr != NULL)
505*12947SEnrico.Perla@Sun.COM updt_str = einfo_get_string(einfo_curr);
506*12947SEnrico.Perla@Sun.COM
507*12947SEnrico.Perla@Sun.COM write_mbr = B_TRUE;
508*12947SEnrico.Perla@Sun.COM force_mbr = B_TRUE;
509*12947SEnrico.Perla@Sun.COM retval = propagate_bootblock(&curr_data, &attach_data, updt_str);
510*12947SEnrico.Perla@Sun.COM cleanup_stage2(stage2_curr);
511*12947SEnrico.Perla@Sun.COM cleanup_stage2(stage2_attach);
5120Sstevel@tonic-gate
513*12947SEnrico.Perla@Sun.COM out_devs:
514*12947SEnrico.Perla@Sun.COM cleanup_device(attach_device);
515*12947SEnrico.Perla@Sun.COM out_currdev:
516*12947SEnrico.Perla@Sun.COM cleanup_device(curr_device);
517*12947SEnrico.Perla@Sun.COM out:
518*12947SEnrico.Perla@Sun.COM free(curr_device_path);
519*12947SEnrico.Perla@Sun.COM free(attach_device_path);
520*12947SEnrico.Perla@Sun.COM return (retval);
521*12947SEnrico.Perla@Sun.COM }
5228434SEnrico.Perla@Sun.COM
523*12947SEnrico.Perla@Sun.COM static int
commit_to_disk(ig_data_t * install,char * updt_str)524*12947SEnrico.Perla@Sun.COM commit_to_disk(ig_data_t *install, char *updt_str)
525*12947SEnrico.Perla@Sun.COM {
526*12947SEnrico.Perla@Sun.COM assert(install != NULL);
527*12947SEnrico.Perla@Sun.COM /*
528*12947SEnrico.Perla@Sun.COM * vanilla stage1 and stage2 need to be updated at runtime.
529*12947SEnrico.Perla@Sun.COM * Update stage2 before stage1 because stage1 needs to know the first
530*12947SEnrico.Perla@Sun.COM * sector stage2 will be written to.
531*12947SEnrico.Perla@Sun.COM */
532*12947SEnrico.Perla@Sun.COM if (prepare_stage2(install, updt_str) != BC_SUCCESS) {
533*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error building stage2\n"));
534*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
535*12947SEnrico.Perla@Sun.COM }
536*12947SEnrico.Perla@Sun.COM if (prepare_stage1(install) != BC_SUCCESS) {
537*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error building stage1\n"));
538*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
539*12947SEnrico.Perla@Sun.COM }
5400Sstevel@tonic-gate
541*12947SEnrico.Perla@Sun.COM /* Write stage2 out to disk. */
542*12947SEnrico.Perla@Sun.COM if (write_stage2(install) != BC_SUCCESS) {
543*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error writing stage2 to "
544*12947SEnrico.Perla@Sun.COM "disk\n"));
545*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
546*12947SEnrico.Perla@Sun.COM }
547*12947SEnrico.Perla@Sun.COM
548*12947SEnrico.Perla@Sun.COM /* Write stage1 to disk and, if requested, to the MBR. */
549*12947SEnrico.Perla@Sun.COM if (write_stage1(install) != BC_SUCCESS) {
550*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error writing stage1 to "
551*12947SEnrico.Perla@Sun.COM "disk\n"));
552*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
553*12947SEnrico.Perla@Sun.COM }
554*12947SEnrico.Perla@Sun.COM
555*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate
558*12947SEnrico.Perla@Sun.COM /*
559*12947SEnrico.Perla@Sun.COM * Propagate the bootblock on the source disk to the destination disk and
560*12947SEnrico.Perla@Sun.COM * version it with 'updt_str' in the process. Since we cannot trust any data
561*12947SEnrico.Perla@Sun.COM * on the attaching disk, we do not perform any specific check on a potential
562*12947SEnrico.Perla@Sun.COM * target extended information structure and we just blindly update.
563*12947SEnrico.Perla@Sun.COM */
564*12947SEnrico.Perla@Sun.COM static int
propagate_bootblock(ig_data_t * source,ig_data_t * target,char * updt_str)565*12947SEnrico.Perla@Sun.COM propagate_bootblock(ig_data_t *source, ig_data_t *target, char *updt_str)
5660Sstevel@tonic-gate {
567*12947SEnrico.Perla@Sun.COM ig_device_t *src_device = &source->device;
568*12947SEnrico.Perla@Sun.COM ig_device_t *dest_device = &target->device;
569*12947SEnrico.Perla@Sun.COM ig_stage2_t *src_stage2 = &source->stage2;
570*12947SEnrico.Perla@Sun.COM ig_stage2_t *dest_stage2 = &target->stage2;
571*12947SEnrico.Perla@Sun.COM uint32_t buf_size;
572*12947SEnrico.Perla@Sun.COM int retval;
573*12947SEnrico.Perla@Sun.COM
574*12947SEnrico.Perla@Sun.COM assert(source != NULL);
575*12947SEnrico.Perla@Sun.COM assert(target != NULL);
576*12947SEnrico.Perla@Sun.COM
577*12947SEnrico.Perla@Sun.COM /* read in stage1 from the source disk. */
578*12947SEnrico.Perla@Sun.COM if (read_stage1_from_disk(src_device->part_fd, target->stage1_buf)
579*12947SEnrico.Perla@Sun.COM != BC_SUCCESS)
580*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
581*12947SEnrico.Perla@Sun.COM
582*12947SEnrico.Perla@Sun.COM /* Prepare target stage2 for commit_to_disk. */
583*12947SEnrico.Perla@Sun.COM cleanup_stage2(dest_stage2);
584*12947SEnrico.Perla@Sun.COM
585*12947SEnrico.Perla@Sun.COM if (updt_str != NULL)
586*12947SEnrico.Perla@Sun.COM do_version = B_TRUE;
587*12947SEnrico.Perla@Sun.COM else
588*12947SEnrico.Perla@Sun.COM do_version = B_FALSE;
589*12947SEnrico.Perla@Sun.COM
590*12947SEnrico.Perla@Sun.COM buf_size = src_stage2->file_size + SECTOR_SIZE;
591*12947SEnrico.Perla@Sun.COM
592*12947SEnrico.Perla@Sun.COM dest_stage2->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE);
593*12947SEnrico.Perla@Sun.COM dest_stage2->buf = malloc(dest_stage2->buf_size);
594*12947SEnrico.Perla@Sun.COM if (dest_stage2->buf == NULL) {
595*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failed"));
596*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
597*12947SEnrico.Perla@Sun.COM }
598*12947SEnrico.Perla@Sun.COM dest_stage2->file = dest_stage2->buf;
599*12947SEnrico.Perla@Sun.COM dest_stage2->file_size = src_stage2->file_size;
600*12947SEnrico.Perla@Sun.COM memcpy(dest_stage2->file, src_stage2->file, dest_stage2->file_size);
601*12947SEnrico.Perla@Sun.COM dest_stage2->extra = dest_stage2->buf +
602*12947SEnrico.Perla@Sun.COM P2ROUNDUP(dest_stage2->file_size, 8);
603*12947SEnrico.Perla@Sun.COM
604*12947SEnrico.Perla@Sun.COM /* If we get down here we do have a mboot structure. */
605*12947SEnrico.Perla@Sun.COM assert(src_stage2->mboot);
606*12947SEnrico.Perla@Sun.COM
607*12947SEnrico.Perla@Sun.COM dest_stage2->mboot_off = src_stage2->mboot_off;
608*12947SEnrico.Perla@Sun.COM dest_stage2->mboot = (multiboot_header_t *)(dest_stage2->buf +
609*12947SEnrico.Perla@Sun.COM dest_stage2->mboot_off);
610*12947SEnrico.Perla@Sun.COM
611*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, gettext("Propagating %s stage1/stage2 to %s\n"),
612*12947SEnrico.Perla@Sun.COM src_device->path, dest_device->path);
613*12947SEnrico.Perla@Sun.COM retval = commit_to_disk(target, updt_str);
614*12947SEnrico.Perla@Sun.COM
615*12947SEnrico.Perla@Sun.COM return (retval);
616*12947SEnrico.Perla@Sun.COM }
617*12947SEnrico.Perla@Sun.COM
618*12947SEnrico.Perla@Sun.COM /*
619*12947SEnrico.Perla@Sun.COM * open the device and fill the various members of ig_device_t.
620*12947SEnrico.Perla@Sun.COM */
621*12947SEnrico.Perla@Sun.COM static int
init_device(ig_device_t * device,char * path)622*12947SEnrico.Perla@Sun.COM init_device(ig_device_t *device, char *path)
623*12947SEnrico.Perla@Sun.COM {
624*12947SEnrico.Perla@Sun.COM bzero(device, sizeof (*device));
625*12947SEnrico.Perla@Sun.COM device->part_fd = -1;
626*12947SEnrico.Perla@Sun.COM device->disk_fd = -1;
627*12947SEnrico.Perla@Sun.COM device->path_p0 = NULL;
628*12947SEnrico.Perla@Sun.COM
629*12947SEnrico.Perla@Sun.COM device->path = strdup(path);
630*12947SEnrico.Perla@Sun.COM if (device->path == NULL) {
631*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failed"));
632*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
633*12947SEnrico.Perla@Sun.COM }
6340Sstevel@tonic-gate
635*12947SEnrico.Perla@Sun.COM if (strstr(device->path, "diskette")) {
636*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("installing GRUB to a floppy "
637*12947SEnrico.Perla@Sun.COM "disk is no longer supported\n"));
638*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
639*12947SEnrico.Perla@Sun.COM }
640*12947SEnrico.Perla@Sun.COM
641*12947SEnrico.Perla@Sun.COM /* Detect if the target device is a pcfs partition. */
642*12947SEnrico.Perla@Sun.COM if (strstr(device->path, "p0:boot"))
643*12947SEnrico.Perla@Sun.COM device->type = IG_DEV_X86BOOTPAR;
644*12947SEnrico.Perla@Sun.COM
645*12947SEnrico.Perla@Sun.COM if (get_disk_fd(device) != BC_SUCCESS)
646*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
647*12947SEnrico.Perla@Sun.COM
648*12947SEnrico.Perla@Sun.COM /* read in the device boot sector. */
649*12947SEnrico.Perla@Sun.COM if (read(device->disk_fd, device->boot_sector, SECTOR_SIZE)
650*12947SEnrico.Perla@Sun.COM != SECTOR_SIZE) {
651*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error reading boot sector\n"));
652*12947SEnrico.Perla@Sun.COM perror("read");
653*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
654*12947SEnrico.Perla@Sun.COM }
655*12947SEnrico.Perla@Sun.COM
656*12947SEnrico.Perla@Sun.COM if (get_raw_partition_fd(device) != BC_SUCCESS)
657*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
658*12947SEnrico.Perla@Sun.COM
659*12947SEnrico.Perla@Sun.COM if (get_start_sector(device) != BC_SUCCESS)
660*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
661*12947SEnrico.Perla@Sun.COM
662*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
663*12947SEnrico.Perla@Sun.COM }
664*12947SEnrico.Perla@Sun.COM
665*12947SEnrico.Perla@Sun.COM static void
cleanup_device(ig_device_t * device)666*12947SEnrico.Perla@Sun.COM cleanup_device(ig_device_t *device)
667*12947SEnrico.Perla@Sun.COM {
668*12947SEnrico.Perla@Sun.COM if (device->path)
669*12947SEnrico.Perla@Sun.COM free(device->path);
670*12947SEnrico.Perla@Sun.COM if (device->path_p0)
671*12947SEnrico.Perla@Sun.COM free(device->path_p0);
6720Sstevel@tonic-gate
673*12947SEnrico.Perla@Sun.COM if (device->part_fd != -1)
674*12947SEnrico.Perla@Sun.COM (void) close(device->part_fd);
675*12947SEnrico.Perla@Sun.COM if (device->disk_fd != -1)
676*12947SEnrico.Perla@Sun.COM (void) close(device->disk_fd);
677*12947SEnrico.Perla@Sun.COM
678*12947SEnrico.Perla@Sun.COM bzero(device, sizeof (ig_device_t));
679*12947SEnrico.Perla@Sun.COM device->part_fd = -1;
680*12947SEnrico.Perla@Sun.COM device->disk_fd = -1;
681*12947SEnrico.Perla@Sun.COM }
682*12947SEnrico.Perla@Sun.COM
683*12947SEnrico.Perla@Sun.COM static void
cleanup_stage2(ig_stage2_t * stage2)684*12947SEnrico.Perla@Sun.COM cleanup_stage2(ig_stage2_t *stage2)
685*12947SEnrico.Perla@Sun.COM {
686*12947SEnrico.Perla@Sun.COM if (stage2->buf)
687*12947SEnrico.Perla@Sun.COM free(stage2->buf);
688*12947SEnrico.Perla@Sun.COM bzero(stage2, sizeof (ig_stage2_t));
689*12947SEnrico.Perla@Sun.COM }
690*12947SEnrico.Perla@Sun.COM
691*12947SEnrico.Perla@Sun.COM static int
get_start_sector(ig_device_t * device)692*12947SEnrico.Perla@Sun.COM get_start_sector(ig_device_t *device)
693*12947SEnrico.Perla@Sun.COM {
694*12947SEnrico.Perla@Sun.COM uint32_t secnum = 0, numsec = 0;
695*12947SEnrico.Perla@Sun.COM int i, pno, rval, log_part = 0;
696*12947SEnrico.Perla@Sun.COM struct mboot *mboot;
697*12947SEnrico.Perla@Sun.COM struct ipart *part;
698*12947SEnrico.Perla@Sun.COM ext_part_t *epp;
699*12947SEnrico.Perla@Sun.COM struct part_info dkpi;
700*12947SEnrico.Perla@Sun.COM struct extpart_info edkpi;
701*12947SEnrico.Perla@Sun.COM
702*12947SEnrico.Perla@Sun.COM mboot = (struct mboot *)device->boot_sector;
703*12947SEnrico.Perla@Sun.COM
704*12947SEnrico.Perla@Sun.COM if (is_bootpar(device->type)) {
705*12947SEnrico.Perla@Sun.COM if (find_x86_bootpar(mboot, &pno, &secnum) != BC_SUCCESS) {
706*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, NOBOOTPAR);
707*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
708*12947SEnrico.Perla@Sun.COM } else {
709*12947SEnrico.Perla@Sun.COM device->start_sector = secnum;
710*12947SEnrico.Perla@Sun.COM device->partition = pno;
711*12947SEnrico.Perla@Sun.COM goto found_part;
71210568SVikram.Hegde@Sun.COM }
71310568SVikram.Hegde@Sun.COM }
71410568SVikram.Hegde@Sun.COM
71510568SVikram.Hegde@Sun.COM /*
716*12947SEnrico.Perla@Sun.COM * Search for Solaris fdisk partition
71710568SVikram.Hegde@Sun.COM * Get the solaris partition information from the device
71810568SVikram.Hegde@Sun.COM * and compare the offset of S2 with offset of solaris partition
71910568SVikram.Hegde@Sun.COM * from fdisk partition table.
72010568SVikram.Hegde@Sun.COM */
721*12947SEnrico.Perla@Sun.COM if (ioctl(device->part_fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
722*12947SEnrico.Perla@Sun.COM if (ioctl(device->part_fd, DKIOCPARTINFO, &dkpi) < 0) {
72310568SVikram.Hegde@Sun.COM (void) fprintf(stderr, PART_FAIL);
724*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
72510568SVikram.Hegde@Sun.COM } else {
72610568SVikram.Hegde@Sun.COM edkpi.p_start = dkpi.p_start;
7275589Ssy25831 }
7285589Ssy25831 }
7295589Ssy25831
73010568SVikram.Hegde@Sun.COM for (i = 0; i < FD_NUMPART; i++) {
73110568SVikram.Hegde@Sun.COM part = (struct ipart *)mboot->parts + i;
73210568SVikram.Hegde@Sun.COM
73310568SVikram.Hegde@Sun.COM if (part->relsect == 0) {
73410568SVikram.Hegde@Sun.COM (void) fprintf(stderr, BAD_PART, i);
735*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
73610568SVikram.Hegde@Sun.COM }
73710568SVikram.Hegde@Sun.COM
73810568SVikram.Hegde@Sun.COM if (edkpi.p_start >= part->relsect &&
73910568SVikram.Hegde@Sun.COM edkpi.p_start < (part->relsect + part->numsect)) {
74010568SVikram.Hegde@Sun.COM /* Found the partition */
74110568SVikram.Hegde@Sun.COM break;
74210568SVikram.Hegde@Sun.COM }
74310568SVikram.Hegde@Sun.COM }
74410568SVikram.Hegde@Sun.COM
74510568SVikram.Hegde@Sun.COM if (i == FD_NUMPART) {
74610568SVikram.Hegde@Sun.COM /* No solaris fdisk partitions (primary or logical) */
74710568SVikram.Hegde@Sun.COM (void) fprintf(stderr, NOSOLPAR);
748*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
74910568SVikram.Hegde@Sun.COM }
75010568SVikram.Hegde@Sun.COM
75110568SVikram.Hegde@Sun.COM /*
75210568SVikram.Hegde@Sun.COM * We have found a Solaris fdisk partition (primary or extended)
75310568SVikram.Hegde@Sun.COM * Handle the simple case first: Solaris in a primary partition
75410568SVikram.Hegde@Sun.COM */
75510568SVikram.Hegde@Sun.COM if (!fdisk_is_dos_extended(part->systid)) {
756*12947SEnrico.Perla@Sun.COM device->start_sector = part->relsect;
757*12947SEnrico.Perla@Sun.COM device->partition = i;
75810568SVikram.Hegde@Sun.COM goto found_part;
75910568SVikram.Hegde@Sun.COM }
76010568SVikram.Hegde@Sun.COM
76110568SVikram.Hegde@Sun.COM /*
76210568SVikram.Hegde@Sun.COM * Solaris in a logical partition. Find that partition in the
76310568SVikram.Hegde@Sun.COM * extended part.
76410568SVikram.Hegde@Sun.COM */
765*12947SEnrico.Perla@Sun.COM if ((rval = libfdisk_init(&epp, device->path_p0, NULL, FDISK_READ_DISK))
76610021SSheshadri.Vasudevan@Sun.COM != FDISK_SUCCESS) {
76710021SSheshadri.Vasudevan@Sun.COM switch (rval) {
76810021SSheshadri.Vasudevan@Sun.COM /*
76911246SSharath.Srinivasan@Sun.COM * The first 3 cases are not an error per-se, just that
77010568SVikram.Hegde@Sun.COM * there is no Solaris logical partition
77110021SSheshadri.Vasudevan@Sun.COM */
77210021SSheshadri.Vasudevan@Sun.COM case FDISK_EBADLOGDRIVE:
77310021SSheshadri.Vasudevan@Sun.COM case FDISK_ENOLOGDRIVE:
77411246SSharath.Srinivasan@Sun.COM case FDISK_EBADMAGIC:
77510568SVikram.Hegde@Sun.COM (void) fprintf(stderr, NOSOLPAR);
776*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
77710021SSheshadri.Vasudevan@Sun.COM case FDISK_ENOVGEOM:
77810021SSheshadri.Vasudevan@Sun.COM (void) fprintf(stderr, NO_VIRT_GEOM);
779*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
78010021SSheshadri.Vasudevan@Sun.COM case FDISK_ENOPGEOM:
78110021SSheshadri.Vasudevan@Sun.COM (void) fprintf(stderr, NO_PHYS_GEOM);
782*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
78310021SSheshadri.Vasudevan@Sun.COM case FDISK_ENOLGEOM:
78410021SSheshadri.Vasudevan@Sun.COM (void) fprintf(stderr, NO_LABEL_GEOM);
785*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
78610021SSheshadri.Vasudevan@Sun.COM default:
78710021SSheshadri.Vasudevan@Sun.COM (void) fprintf(stderr, LIBFDISK_INIT_FAIL);
788*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
78910021SSheshadri.Vasudevan@Sun.COM break;
79010021SSheshadri.Vasudevan@Sun.COM }
79110021SSheshadri.Vasudevan@Sun.COM }
79210021SSheshadri.Vasudevan@Sun.COM
79310021SSheshadri.Vasudevan@Sun.COM rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
79411246SSharath.Srinivasan@Sun.COM libfdisk_fini(&epp);
79510568SVikram.Hegde@Sun.COM if (rval != FDISK_SUCCESS) {
79610568SVikram.Hegde@Sun.COM /* No solaris logical partition */
79710568SVikram.Hegde@Sun.COM (void) fprintf(stderr, NOSOLPAR);
798*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
79910021SSheshadri.Vasudevan@Sun.COM }
80010021SSheshadri.Vasudevan@Sun.COM
801*12947SEnrico.Perla@Sun.COM device->start_sector = secnum;
802*12947SEnrico.Perla@Sun.COM device->partition = pno - 1;
80310568SVikram.Hegde@Sun.COM log_part = 1;
8045589Ssy25831
80510568SVikram.Hegde@Sun.COM found_part:
8060Sstevel@tonic-gate /* get confirmation for -m */
807*12947SEnrico.Perla@Sun.COM if (write_mbr && !force_mbr) {
8080Sstevel@tonic-gate (void) fprintf(stdout, MBOOT_PROMPT);
8090Sstevel@tonic-gate if (getchar() != 'y') {
810*12947SEnrico.Perla@Sun.COM write_mbr = 0;
8110Sstevel@tonic-gate (void) fprintf(stdout, MBOOT_NOT_UPDATED);
812*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate
81610568SVikram.Hegde@Sun.COM /*
81710568SVikram.Hegde@Sun.COM * Currently if Solaris is in an extended partition we need to
81810568SVikram.Hegde@Sun.COM * write GRUB to the MBR. Check for this.
81910568SVikram.Hegde@Sun.COM */
820*12947SEnrico.Perla@Sun.COM if (log_part && !write_mbr) {
821*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, gettext("Installing Solaris on an "
822*12947SEnrico.Perla@Sun.COM "extended partition... forcing MBR update\n"));
823*12947SEnrico.Perla@Sun.COM write_mbr = 1;
82410021SSheshadri.Vasudevan@Sun.COM }
82510021SSheshadri.Vasudevan@Sun.COM
82610568SVikram.Hegde@Sun.COM /*
82710568SVikram.Hegde@Sun.COM * warn, if Solaris in primary partition and GRUB not in MBR and
82810568SVikram.Hegde@Sun.COM * partition is not active
82910568SVikram.Hegde@Sun.COM */
830*12947SEnrico.Perla@Sun.COM if (!log_part && part->bootid != 128 && !write_mbr) {
831*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, SOLPAR_INACTIVE, device->partition + 1);
832*12947SEnrico.Perla@Sun.COM }
833*12947SEnrico.Perla@Sun.COM
834*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
835*12947SEnrico.Perla@Sun.COM }
836*12947SEnrico.Perla@Sun.COM
837*12947SEnrico.Perla@Sun.COM static int
get_disk_fd(ig_device_t * device)838*12947SEnrico.Perla@Sun.COM get_disk_fd(ig_device_t *device)
839*12947SEnrico.Perla@Sun.COM {
840*12947SEnrico.Perla@Sun.COM int i;
841*12947SEnrico.Perla@Sun.COM char save[2];
842*12947SEnrico.Perla@Sun.COM char *end = NULL;
843*12947SEnrico.Perla@Sun.COM
844*12947SEnrico.Perla@Sun.COM assert(device != NULL);
845*12947SEnrico.Perla@Sun.COM assert(device->path != NULL);
846*12947SEnrico.Perla@Sun.COM
847*12947SEnrico.Perla@Sun.COM if (is_bootpar(device->type)) {
848*12947SEnrico.Perla@Sun.COM end = strstr(device->path, "p0:boot");
849*12947SEnrico.Perla@Sun.COM /* tested at the start of init_device() */
850*12947SEnrico.Perla@Sun.COM assert(end != NULL);
851*12947SEnrico.Perla@Sun.COM /* chop off :boot */
852*12947SEnrico.Perla@Sun.COM save[0] = end[2];
853*12947SEnrico.Perla@Sun.COM end[2] = '\0';
854*12947SEnrico.Perla@Sun.COM } else {
855*12947SEnrico.Perla@Sun.COM i = strlen(device->path);
856*12947SEnrico.Perla@Sun.COM save[0] = device->path[i - 2];
857*12947SEnrico.Perla@Sun.COM save[1] = device->path[i - 1];
858*12947SEnrico.Perla@Sun.COM device->path[i - 2] = 'p';
859*12947SEnrico.Perla@Sun.COM device->path[i - 1] = '0';
860*12947SEnrico.Perla@Sun.COM }
861*12947SEnrico.Perla@Sun.COM
862*12947SEnrico.Perla@Sun.COM if (nowrite)
863*12947SEnrico.Perla@Sun.COM device->disk_fd = open(device->path, O_RDONLY);
864*12947SEnrico.Perla@Sun.COM else
865*12947SEnrico.Perla@Sun.COM device->disk_fd = open(device->path, O_RDWR);
866*12947SEnrico.Perla@Sun.COM
867*12947SEnrico.Perla@Sun.COM device->path_p0 = strdup(device->path);
868*12947SEnrico.Perla@Sun.COM if (device->path_p0 == NULL) {
869*12947SEnrico.Perla@Sun.COM perror("strdup");
870*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
871*12947SEnrico.Perla@Sun.COM }
872*12947SEnrico.Perla@Sun.COM
873*12947SEnrico.Perla@Sun.COM if (is_bootpar(device->type)) {
874*12947SEnrico.Perla@Sun.COM end[2] = save[0];
875*12947SEnrico.Perla@Sun.COM } else {
876*12947SEnrico.Perla@Sun.COM device->path[i - 2] = save[0];
877*12947SEnrico.Perla@Sun.COM device->path[i - 1] = save[1];
878*12947SEnrico.Perla@Sun.COM }
879*12947SEnrico.Perla@Sun.COM
880*12947SEnrico.Perla@Sun.COM if (device->disk_fd == -1) {
881*12947SEnrico.Perla@Sun.COM perror("open");
882*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate
885*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
886*12947SEnrico.Perla@Sun.COM }
887*12947SEnrico.Perla@Sun.COM
888*12947SEnrico.Perla@Sun.COM static void
prepare_fake_multiboot(ig_stage2_t * stage2)889*12947SEnrico.Perla@Sun.COM prepare_fake_multiboot(ig_stage2_t *stage2)
890*12947SEnrico.Perla@Sun.COM {
891*12947SEnrico.Perla@Sun.COM multiboot_header_t *mboot;
892*12947SEnrico.Perla@Sun.COM
893*12947SEnrico.Perla@Sun.COM assert(stage2 != NULL);
894*12947SEnrico.Perla@Sun.COM assert(stage2->mboot != NULL);
895*12947SEnrico.Perla@Sun.COM assert(stage2->buf != NULL);
896*12947SEnrico.Perla@Sun.COM
897*12947SEnrico.Perla@Sun.COM mboot = stage2->mboot;
898*12947SEnrico.Perla@Sun.COM
899*12947SEnrico.Perla@Sun.COM /*
900*12947SEnrico.Perla@Sun.COM * Currently we expect find_multiboot() to have located a multiboot
901*12947SEnrico.Perla@Sun.COM * header with the AOUT kludge flag set.
902*12947SEnrico.Perla@Sun.COM */
903*12947SEnrico.Perla@Sun.COM assert(mboot->flags & BB_MBOOT_AOUT_FLAG);
904*12947SEnrico.Perla@Sun.COM
905*12947SEnrico.Perla@Sun.COM /* Insert the information necessary to locate stage2. */
906*12947SEnrico.Perla@Sun.COM mboot->header_addr = stage2->mboot_off;
907*12947SEnrico.Perla@Sun.COM mboot->load_addr = 0;
908*12947SEnrico.Perla@Sun.COM mboot->load_end_addr = stage2->file_size;
909*12947SEnrico.Perla@Sun.COM }
910*12947SEnrico.Perla@Sun.COM
911*12947SEnrico.Perla@Sun.COM static void
add_stage2_einfo(ig_stage2_t * stage2,char * updt_str)912*12947SEnrico.Perla@Sun.COM add_stage2_einfo(ig_stage2_t *stage2, char *updt_str)
913*12947SEnrico.Perla@Sun.COM {
914*12947SEnrico.Perla@Sun.COM bblk_hs_t hs;
915*12947SEnrico.Perla@Sun.COM uint32_t avail_space;
916*12947SEnrico.Perla@Sun.COM
917*12947SEnrico.Perla@Sun.COM assert(stage2 != NULL);
918*12947SEnrico.Perla@Sun.COM
919*12947SEnrico.Perla@Sun.COM /* Fill bootblock hashing source information. */
920*12947SEnrico.Perla@Sun.COM hs.src_buf = (unsigned char *)stage2->file;
921*12947SEnrico.Perla@Sun.COM hs.src_size = stage2->file_size;
922*12947SEnrico.Perla@Sun.COM /* How much space for the extended information structure? */
923*12947SEnrico.Perla@Sun.COM avail_space = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8);
924*12947SEnrico.Perla@Sun.COM add_einfo(stage2->extra, updt_str, &hs, avail_space);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate
927*12947SEnrico.Perla@Sun.COM
928*12947SEnrico.Perla@Sun.COM static int
write_stage2(ig_data_t * install)929*12947SEnrico.Perla@Sun.COM write_stage2(ig_data_t *install)
930*12947SEnrico.Perla@Sun.COM {
931*12947SEnrico.Perla@Sun.COM ig_device_t *device = &install->device;
932*12947SEnrico.Perla@Sun.COM ig_stage2_t *stage2 = &install->stage2;
933*12947SEnrico.Perla@Sun.COM off_t offset;
934*12947SEnrico.Perla@Sun.COM
935*12947SEnrico.Perla@Sun.COM assert(install != NULL);
936*12947SEnrico.Perla@Sun.COM
937*12947SEnrico.Perla@Sun.COM if (is_bootpar(device->type)) {
938*12947SEnrico.Perla@Sun.COM /*
939*12947SEnrico.Perla@Sun.COM * stage2 is already on the filesystem, we only need to update
940*12947SEnrico.Perla@Sun.COM * the first two blocks (that we have modified during
941*12947SEnrico.Perla@Sun.COM * prepare_stage2())
942*12947SEnrico.Perla@Sun.COM */
943*12947SEnrico.Perla@Sun.COM if (write_out(device->part_fd, stage2->file, SECTOR_SIZE,
944*12947SEnrico.Perla@Sun.COM stage2->pcfs_first_sectors[0] * SECTOR_SIZE)
945*12947SEnrico.Perla@Sun.COM != BC_SUCCESS ||
946*12947SEnrico.Perla@Sun.COM write_out(device->part_fd, stage2->file + SECTOR_SIZE,
947*12947SEnrico.Perla@Sun.COM SECTOR_SIZE, stage2->pcfs_first_sectors[1] * SECTOR_SIZE)
948*12947SEnrico.Perla@Sun.COM != BC_SUCCESS) {
949*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, WRITE_FAIL_STAGE2);
950*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
951*12947SEnrico.Perla@Sun.COM }
952*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, WRITE_STAGE2_PCFS);
953*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
954*12947SEnrico.Perla@Sun.COM }
955*12947SEnrico.Perla@Sun.COM
956*12947SEnrico.Perla@Sun.COM /*
957*12947SEnrico.Perla@Sun.COM * For disk, write stage2 starting at STAGE2_BLKOFF sector.
958*12947SEnrico.Perla@Sun.COM * Note that we use stage2->buf rather than stage2->file, because we
959*12947SEnrico.Perla@Sun.COM * may have extended information after the latter.
960*12947SEnrico.Perla@Sun.COM */
961*12947SEnrico.Perla@Sun.COM offset = STAGE2_BLKOFF * SECTOR_SIZE;
962*12947SEnrico.Perla@Sun.COM if (write_out(device->part_fd, stage2->buf, stage2->buf_size,
963*12947SEnrico.Perla@Sun.COM offset) != BC_SUCCESS) {
964*12947SEnrico.Perla@Sun.COM perror("write");
965*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
966*12947SEnrico.Perla@Sun.COM }
967*12947SEnrico.Perla@Sun.COM
968*12947SEnrico.Perla@Sun.COM /* Simulate the "old" installgrub output. */
969*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, WRITE_STAGE2_DISK, device->partition,
970*12947SEnrico.Perla@Sun.COM (stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF,
971*12947SEnrico.Perla@Sun.COM stage2->first_sector);
972*12947SEnrico.Perla@Sun.COM
973*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
974*12947SEnrico.Perla@Sun.COM }
975*12947SEnrico.Perla@Sun.COM
976*12947SEnrico.Perla@Sun.COM static int
write_stage1(ig_data_t * install)977*12947SEnrico.Perla@Sun.COM write_stage1(ig_data_t *install)
978*12947SEnrico.Perla@Sun.COM {
979*12947SEnrico.Perla@Sun.COM ig_device_t *device = &install->device;
980*12947SEnrico.Perla@Sun.COM
981*12947SEnrico.Perla@Sun.COM assert(install != NULL);
982*12947SEnrico.Perla@Sun.COM
983*12947SEnrico.Perla@Sun.COM if (write_out(device->part_fd, install->stage1_buf,
984*12947SEnrico.Perla@Sun.COM sizeof (install->stage1_buf), 0) != BC_SUCCESS) {
985*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, WRITE_FAIL_PBOOT);
986*12947SEnrico.Perla@Sun.COM perror("write");
987*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
988*12947SEnrico.Perla@Sun.COM }
989*12947SEnrico.Perla@Sun.COM
990*12947SEnrico.Perla@Sun.COM /* Simulate "old" installgrub output. */
991*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, WRITE_PBOOT, device->partition,
992*12947SEnrico.Perla@Sun.COM device->start_sector);
993*12947SEnrico.Perla@Sun.COM
994*12947SEnrico.Perla@Sun.COM if (write_mbr) {
995*12947SEnrico.Perla@Sun.COM if (write_out(device->disk_fd, install->stage1_buf,
996*12947SEnrico.Perla@Sun.COM sizeof (install->stage1_buf), 0) != BC_SUCCESS) {
997*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, WRITE_FAIL_BOOTSEC);
998*12947SEnrico.Perla@Sun.COM perror("write");
999*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1000*12947SEnrico.Perla@Sun.COM }
1001*12947SEnrico.Perla@Sun.COM /* Simulate "old" installgrub output. */
1002*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, WRITE_MBOOT);
1003*12947SEnrico.Perla@Sun.COM }
1004*12947SEnrico.Perla@Sun.COM
1005*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
1006*12947SEnrico.Perla@Sun.COM }
1007*12947SEnrico.Perla@Sun.COM
1008*12947SEnrico.Perla@Sun.COM #define USAGE_STRING "%s [-m|-f|-n|-F|-u verstr] stage1 stage2 device\n" \
1009*12947SEnrico.Perla@Sun.COM "%s -M [-n] device1 device2\n" \
1010*12947SEnrico.Perla@Sun.COM "%s [-V|-e] -i device\n" \
1011*12947SEnrico.Perla@Sun.COM
1012*12947SEnrico.Perla@Sun.COM #define CANON_USAGE_STR gettext(USAGE_STRING)
1013*12947SEnrico.Perla@Sun.COM
10140Sstevel@tonic-gate static void
usage(char * progname)10150Sstevel@tonic-gate usage(char *progname)
10160Sstevel@tonic-gate {
1017*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
10188434SEnrico.Perla@Sun.COM }
10198434SEnrico.Perla@Sun.COM
10208434SEnrico.Perla@Sun.COM
10218434SEnrico.Perla@Sun.COM static int
read_stage1_from_file(char * path,ig_data_t * dest)1022*12947SEnrico.Perla@Sun.COM read_stage1_from_file(char *path, ig_data_t *dest)
10238434SEnrico.Perla@Sun.COM {
1024*12947SEnrico.Perla@Sun.COM int fd;
1025*12947SEnrico.Perla@Sun.COM
1026*12947SEnrico.Perla@Sun.COM assert(dest);
1027*12947SEnrico.Perla@Sun.COM
1028*12947SEnrico.Perla@Sun.COM /* read the stage1 file from filesystem */
1029*12947SEnrico.Perla@Sun.COM fd = open(path, O_RDONLY);
1030*12947SEnrico.Perla@Sun.COM if (fd == -1 ||
1031*12947SEnrico.Perla@Sun.COM read(fd, dest->stage1_buf, SECTOR_SIZE) != SECTOR_SIZE) {
1032*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, READ_FAIL_STAGE1, path);
1033*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1034*12947SEnrico.Perla@Sun.COM }
1035*12947SEnrico.Perla@Sun.COM (void) close(fd);
1036*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
1037*12947SEnrico.Perla@Sun.COM }
1038*12947SEnrico.Perla@Sun.COM
1039*12947SEnrico.Perla@Sun.COM static int
read_stage2_from_file(char * path,ig_data_t * dest)1040*12947SEnrico.Perla@Sun.COM read_stage2_from_file(char *path, ig_data_t *dest)
1041*12947SEnrico.Perla@Sun.COM {
1042*12947SEnrico.Perla@Sun.COM int fd;
10438434SEnrico.Perla@Sun.COM struct stat sb;
1044*12947SEnrico.Perla@Sun.COM ig_stage2_t *stage2 = &dest->stage2;
1045*12947SEnrico.Perla@Sun.COM ig_device_t *device = &dest->device;
1046*12947SEnrico.Perla@Sun.COM uint32_t buf_size;
1047*12947SEnrico.Perla@Sun.COM
1048*12947SEnrico.Perla@Sun.COM assert(dest);
1049*12947SEnrico.Perla@Sun.COM assert(stage2->buf == NULL);
1050*12947SEnrico.Perla@Sun.COM
1051*12947SEnrico.Perla@Sun.COM fd = open(path, O_RDONLY);
1052*12947SEnrico.Perla@Sun.COM if (fstat(fd, &sb) == -1) {
1053*12947SEnrico.Perla@Sun.COM perror("fstat");
1054*12947SEnrico.Perla@Sun.COM goto out;
1055*12947SEnrico.Perla@Sun.COM }
1056*12947SEnrico.Perla@Sun.COM
1057*12947SEnrico.Perla@Sun.COM stage2->file_size = sb.st_size;
1058*12947SEnrico.Perla@Sun.COM
1059*12947SEnrico.Perla@Sun.COM if (!is_bootpar(device->type)) {
1060*12947SEnrico.Perla@Sun.COM /*
1061*12947SEnrico.Perla@Sun.COM * buffer size needs to account for stage2 plus the extra
1062*12947SEnrico.Perla@Sun.COM * versioning information at the end of it. We reserve one
1063*12947SEnrico.Perla@Sun.COM * extra sector (plus we round up to the next sector boundary).
1064*12947SEnrico.Perla@Sun.COM */
1065*12947SEnrico.Perla@Sun.COM buf_size = stage2->file_size + SECTOR_SIZE;
1066*12947SEnrico.Perla@Sun.COM } else {
1067*12947SEnrico.Perla@Sun.COM /* In the PCFS case we only need to read in stage2. */
1068*12947SEnrico.Perla@Sun.COM buf_size = stage2->file_size;
1069*12947SEnrico.Perla@Sun.COM }
1070*12947SEnrico.Perla@Sun.COM
1071*12947SEnrico.Perla@Sun.COM stage2->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE);
1072*12947SEnrico.Perla@Sun.COM
1073*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("stage2 buffer size = %d (%d sectors)\n", stage2->buf_size,
1074*12947SEnrico.Perla@Sun.COM stage2->buf_size / SECTOR_SIZE);
1075*12947SEnrico.Perla@Sun.COM
1076*12947SEnrico.Perla@Sun.COM stage2->buf = malloc(stage2->buf_size);
1077*12947SEnrico.Perla@Sun.COM if (stage2->buf == NULL) {
1078*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failed"));
1079*12947SEnrico.Perla@Sun.COM goto out_fd;
1080*12947SEnrico.Perla@Sun.COM }
1081*12947SEnrico.Perla@Sun.COM
1082*12947SEnrico.Perla@Sun.COM stage2->file = stage2->buf;
1083*12947SEnrico.Perla@Sun.COM
1084*12947SEnrico.Perla@Sun.COM /*
1085*12947SEnrico.Perla@Sun.COM * Extra information (e.g. the versioning structure) is placed at the
1086*12947SEnrico.Perla@Sun.COM * end of stage2, aligned on a 8-byte boundary.
1087*12947SEnrico.Perla@Sun.COM */
1088*12947SEnrico.Perla@Sun.COM if (!(is_bootpar(device->type)))
1089*12947SEnrico.Perla@Sun.COM stage2->extra = stage2->file + P2ROUNDUP(stage2->file_size, 8);
1090*12947SEnrico.Perla@Sun.COM
1091*12947SEnrico.Perla@Sun.COM if (lseek(fd, 0, SEEK_SET) == -1) {
1092*12947SEnrico.Perla@Sun.COM perror("lseek");
1093*12947SEnrico.Perla@Sun.COM goto out_alloc;
1094*12947SEnrico.Perla@Sun.COM }
10958434SEnrico.Perla@Sun.COM
1096*12947SEnrico.Perla@Sun.COM if (read(fd, stage2->file, stage2->file_size) < 0) {
1097*12947SEnrico.Perla@Sun.COM perror(gettext("unable to read stage2"));
1098*12947SEnrico.Perla@Sun.COM goto out_alloc;
1099*12947SEnrico.Perla@Sun.COM }
1100*12947SEnrico.Perla@Sun.COM
1101*12947SEnrico.Perla@Sun.COM (void) close(fd);
1102*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
1103*12947SEnrico.Perla@Sun.COM
1104*12947SEnrico.Perla@Sun.COM out_alloc:
1105*12947SEnrico.Perla@Sun.COM free(stage2->buf);
1106*12947SEnrico.Perla@Sun.COM stage2->buf = NULL;
1107*12947SEnrico.Perla@Sun.COM out_fd:
1108*12947SEnrico.Perla@Sun.COM (void) close(fd);
1109*12947SEnrico.Perla@Sun.COM out:
1110*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1111*12947SEnrico.Perla@Sun.COM }
1112*12947SEnrico.Perla@Sun.COM
1113*12947SEnrico.Perla@Sun.COM static int
prepare_stage1(ig_data_t * install)1114*12947SEnrico.Perla@Sun.COM prepare_stage1(ig_data_t *install)
1115*12947SEnrico.Perla@Sun.COM {
1116*12947SEnrico.Perla@Sun.COM ig_device_t *device = &install->device;
1117*12947SEnrico.Perla@Sun.COM
1118*12947SEnrico.Perla@Sun.COM assert(install != NULL);
1119*12947SEnrico.Perla@Sun.COM
1120*12947SEnrico.Perla@Sun.COM /* If PCFS add the BIOS Parameter Block. */
1121*12947SEnrico.Perla@Sun.COM if (is_bootpar(device->type)) {
1122*12947SEnrico.Perla@Sun.COM char bpb_sect[SECTOR_SIZE];
1123*12947SEnrico.Perla@Sun.COM
1124*12947SEnrico.Perla@Sun.COM if (pread(device->part_fd, bpb_sect, SECTOR_SIZE, 0)
1125*12947SEnrico.Perla@Sun.COM != SECTOR_SIZE) {
1126*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, READ_FAIL_BPB);
1127*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1128*12947SEnrico.Perla@Sun.COM }
1129*12947SEnrico.Perla@Sun.COM bcopy(bpb_sect + STAGE1_BPB_OFFSET,
1130*12947SEnrico.Perla@Sun.COM install->stage1_buf + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
1131*12947SEnrico.Perla@Sun.COM }
1132*12947SEnrico.Perla@Sun.COM
1133*12947SEnrico.Perla@Sun.COM /* copy MBR to stage1 in case of overwriting MBR sector. */
1134*12947SEnrico.Perla@Sun.COM bcopy(device->boot_sector + BOOTSZ, install->stage1_buf + BOOTSZ,
1135*12947SEnrico.Perla@Sun.COM SECTOR_SIZE - BOOTSZ);
1136*12947SEnrico.Perla@Sun.COM /* modify default stage1 file generated by GRUB. */
1137*12947SEnrico.Perla@Sun.COM *((unsigned char *)(install->stage1_buf + STAGE1_FORCE_LBA)) = 1;
1138*12947SEnrico.Perla@Sun.COM *((ulong_t *)(install->stage1_buf + STAGE1_STAGE2_SECTOR))
1139*12947SEnrico.Perla@Sun.COM = install->stage2.first_sector;
1140*12947SEnrico.Perla@Sun.COM *((ushort_t *)(install->stage1_buf + STAGE1_STAGE2_ADDRESS))
1141*12947SEnrico.Perla@Sun.COM = STAGE2_MEMADDR;
1142*12947SEnrico.Perla@Sun.COM *((ushort_t *)(install->stage1_buf + STAGE1_STAGE2_SEGMENT))
1143*12947SEnrico.Perla@Sun.COM = STAGE2_MEMADDR >> 4;
1144*12947SEnrico.Perla@Sun.COM
1145*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
1146*12947SEnrico.Perla@Sun.COM }
11478434SEnrico.Perla@Sun.COM
1148*12947SEnrico.Perla@Sun.COM /*
1149*12947SEnrico.Perla@Sun.COM * Grab stage1 from the specified device file descriptor.
1150*12947SEnrico.Perla@Sun.COM */
1151*12947SEnrico.Perla@Sun.COM static int
read_stage1_from_disk(int dev_fd,char * stage1_buf)1152*12947SEnrico.Perla@Sun.COM read_stage1_from_disk(int dev_fd, char *stage1_buf)
1153*12947SEnrico.Perla@Sun.COM {
1154*12947SEnrico.Perla@Sun.COM assert(stage1_buf != NULL);
1155*12947SEnrico.Perla@Sun.COM
1156*12947SEnrico.Perla@Sun.COM if (read_in(dev_fd, stage1_buf, SECTOR_SIZE, 0) != BC_SUCCESS) {
1157*12947SEnrico.Perla@Sun.COM perror(gettext("Unable to read stage1 from disk"));
1158*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1159*12947SEnrico.Perla@Sun.COM }
1160*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
1161*12947SEnrico.Perla@Sun.COM }
1162*12947SEnrico.Perla@Sun.COM
1163*12947SEnrico.Perla@Sun.COM static int
read_stage2_from_disk(int dev_fd,ig_stage2_t * stage2)1164*12947SEnrico.Perla@Sun.COM read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2)
1165*12947SEnrico.Perla@Sun.COM {
1166*12947SEnrico.Perla@Sun.COM uint32_t size;
1167*12947SEnrico.Perla@Sun.COM uint32_t buf_size;
1168*12947SEnrico.Perla@Sun.COM uint32_t mboot_off;
1169*12947SEnrico.Perla@Sun.COM multiboot_header_t *mboot;
1170*12947SEnrico.Perla@Sun.COM
1171*12947SEnrico.Perla@Sun.COM assert(stage2 != NULL);
1172*12947SEnrico.Perla@Sun.COM assert(dev_fd != -1);
1173*12947SEnrico.Perla@Sun.COM
1174*12947SEnrico.Perla@Sun.COM if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan),
1175*12947SEnrico.Perla@Sun.COM STAGE2_BLKOFF * SECTOR_SIZE) != BC_SUCCESS) {
1176*12947SEnrico.Perla@Sun.COM perror(gettext("Error reading stage2 sectors"));
1177*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1178*12947SEnrico.Perla@Sun.COM }
1179*12947SEnrico.Perla@Sun.COM
1180*12947SEnrico.Perla@Sun.COM /* No multiboot means no chance of knowing stage2 size */
1181*12947SEnrico.Perla@Sun.COM if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off)
1182*12947SEnrico.Perla@Sun.COM != BC_SUCCESS) {
1183*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Unable to find multiboot header\n");
1184*12947SEnrico.Perla@Sun.COM return (BC_NOEXTRA);
1185*12947SEnrico.Perla@Sun.COM }
1186*12947SEnrico.Perla@Sun.COM mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
1187*12947SEnrico.Perla@Sun.COM
1188*12947SEnrico.Perla@Sun.COM /*
1189*12947SEnrico.Perla@Sun.COM * Unfilled mboot values mean an older version of installgrub installed
1190*12947SEnrico.Perla@Sun.COM * the stage2. Again we have no chance of knowing stage2 size.
1191*12947SEnrico.Perla@Sun.COM */
1192*12947SEnrico.Perla@Sun.COM if (mboot->load_end_addr == 0 ||
1193*12947SEnrico.Perla@Sun.COM mboot->load_end_addr < mboot->load_addr)
1194*12947SEnrico.Perla@Sun.COM return (BC_NOEXTRA);
1195*12947SEnrico.Perla@Sun.COM
1196*12947SEnrico.Perla@Sun.COM /*
1197*12947SEnrico.Perla@Sun.COM * Currently, the amount of space reserved for extra information
1198*12947SEnrico.Perla@Sun.COM * is "fixed". We may have to scan for the terminating extra payload
1199*12947SEnrico.Perla@Sun.COM * in the future.
1200*12947SEnrico.Perla@Sun.COM */
1201*12947SEnrico.Perla@Sun.COM size = mboot->load_end_addr - mboot->load_addr;
1202*12947SEnrico.Perla@Sun.COM buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
1203*12947SEnrico.Perla@Sun.COM
1204*12947SEnrico.Perla@Sun.COM stage2->buf = malloc(buf_size);
1205*12947SEnrico.Perla@Sun.COM if (stage2->buf == NULL) {
1206*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failed"));
1207*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1208*12947SEnrico.Perla@Sun.COM }
1209*12947SEnrico.Perla@Sun.COM stage2->buf_size = buf_size;
12108434SEnrico.Perla@Sun.COM
1211*12947SEnrico.Perla@Sun.COM if (read_in(dev_fd, stage2->buf, buf_size, STAGE2_BLKOFF *
1212*12947SEnrico.Perla@Sun.COM SECTOR_SIZE) != BC_SUCCESS) {
1213*12947SEnrico.Perla@Sun.COM perror("read");
1214*12947SEnrico.Perla@Sun.COM free(stage2->buf);
1215*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1216*12947SEnrico.Perla@Sun.COM }
1217*12947SEnrico.Perla@Sun.COM
1218*12947SEnrico.Perla@Sun.COM /* Update pointers. */
1219*12947SEnrico.Perla@Sun.COM stage2->file = stage2->buf;
1220*12947SEnrico.Perla@Sun.COM stage2->file_size = size;
1221*12947SEnrico.Perla@Sun.COM stage2->mboot_off = mboot_off;
1222*12947SEnrico.Perla@Sun.COM stage2->mboot = (multiboot_header_t *)(stage2->buf + stage2->mboot_off);
1223*12947SEnrico.Perla@Sun.COM stage2->extra = stage2->buf + P2ROUNDUP(stage2->file_size, 8);
1224*12947SEnrico.Perla@Sun.COM
1225*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
1226*12947SEnrico.Perla@Sun.COM }
1227*12947SEnrico.Perla@Sun.COM
1228*12947SEnrico.Perla@Sun.COM static boolean_t
is_update_necessary(ig_data_t * data,char * updt_str)1229*12947SEnrico.Perla@Sun.COM is_update_necessary(ig_data_t *data, char *updt_str)
1230*12947SEnrico.Perla@Sun.COM {
1231*12947SEnrico.Perla@Sun.COM bblk_einfo_t *einfo;
1232*12947SEnrico.Perla@Sun.COM bblk_hs_t stage2_hs;
1233*12947SEnrico.Perla@Sun.COM ig_stage2_t stage2_disk;
1234*12947SEnrico.Perla@Sun.COM ig_stage2_t *stage2_file = &data->stage2;
1235*12947SEnrico.Perla@Sun.COM ig_device_t *device = &data->device;
1236*12947SEnrico.Perla@Sun.COM int dev_fd = device->part_fd;
1237*12947SEnrico.Perla@Sun.COM
1238*12947SEnrico.Perla@Sun.COM assert(data != NULL);
1239*12947SEnrico.Perla@Sun.COM assert(device->part_fd != -1);
1240*12947SEnrico.Perla@Sun.COM
1241*12947SEnrico.Perla@Sun.COM bzero(&stage2_disk, sizeof (ig_stage2_t));
12428434SEnrico.Perla@Sun.COM
1243*12947SEnrico.Perla@Sun.COM /* Gather stage2 (if present) from the target device. */
1244*12947SEnrico.Perla@Sun.COM if (read_stage2_from_disk(dev_fd, &stage2_disk) != BC_SUCCESS) {
1245*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Unable to read stage2 from %s\n", device->path);
1246*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("No multiboot wrapped stage2 on %s\n", device->path);
1247*12947SEnrico.Perla@Sun.COM return (B_TRUE);
1248*12947SEnrico.Perla@Sun.COM }
1249*12947SEnrico.Perla@Sun.COM
1250*12947SEnrico.Perla@Sun.COM /*
1251*12947SEnrico.Perla@Sun.COM * Look for the extended information structure in the extra payload
1252*12947SEnrico.Perla@Sun.COM * area.
1253*12947SEnrico.Perla@Sun.COM */
1254*12947SEnrico.Perla@Sun.COM einfo = find_einfo(stage2_disk.extra);
1255*12947SEnrico.Perla@Sun.COM if (einfo == NULL) {
1256*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("No extended information available\n");
1257*12947SEnrico.Perla@Sun.COM return (B_TRUE);
1258*12947SEnrico.Perla@Sun.COM }
1259*12947SEnrico.Perla@Sun.COM
1260*12947SEnrico.Perla@Sun.COM if (!do_version || updt_str == NULL) {
1261*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, "WARNING: target device %s has a "
1262*12947SEnrico.Perla@Sun.COM "versioned stage2 that is going to be overwritten by a non "
1263*12947SEnrico.Perla@Sun.COM "versioned one\n", device->path);
1264*12947SEnrico.Perla@Sun.COM return (B_TRUE);
1265*12947SEnrico.Perla@Sun.COM }
1266*12947SEnrico.Perla@Sun.COM
1267*12947SEnrico.Perla@Sun.COM if (force_update) {
1268*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
1269*12947SEnrico.Perla@Sun.COM return (B_TRUE);
1270*12947SEnrico.Perla@Sun.COM }
1271*12947SEnrico.Perla@Sun.COM
1272*12947SEnrico.Perla@Sun.COM /* Compare the two extended information structures. */
1273*12947SEnrico.Perla@Sun.COM stage2_hs.src_buf = (unsigned char *)stage2_file->file;
1274*12947SEnrico.Perla@Sun.COM stage2_hs.src_size = stage2_file->file_size;
1275*12947SEnrico.Perla@Sun.COM
1276*12947SEnrico.Perla@Sun.COM return (einfo_should_update(einfo, &stage2_hs, updt_str));
12778434SEnrico.Perla@Sun.COM }
12788434SEnrico.Perla@Sun.COM
12798434SEnrico.Perla@Sun.COM
12800Sstevel@tonic-gate #define START_BLOCK(pos) (*(ulong_t *)(pos))
12810Sstevel@tonic-gate #define NUM_BLOCK(pos) (*(ushort_t *)((pos) + 4))
12820Sstevel@tonic-gate #define START_SEG(pos) (*(ushort_t *)((pos) + 6))
12830Sstevel@tonic-gate
1284*12947SEnrico.Perla@Sun.COM static int
prepare_stage2(ig_data_t * install,char * updt_str)1285*12947SEnrico.Perla@Sun.COM prepare_stage2(ig_data_t *install, char *updt_str)
12860Sstevel@tonic-gate {
1287*12947SEnrico.Perla@Sun.COM ig_device_t *device = &install->device;
1288*12947SEnrico.Perla@Sun.COM ig_stage2_t *stage2 = &install->stage2;
1289*12947SEnrico.Perla@Sun.COM uint32_t mboot_off = 0;
1290*12947SEnrico.Perla@Sun.COM
1291*12947SEnrico.Perla@Sun.COM assert(install != NULL);
1292*12947SEnrico.Perla@Sun.COM assert(stage2->file != NULL);
12938434SEnrico.Perla@Sun.COM
1294*12947SEnrico.Perla@Sun.COM /* New stage2 files come with an embedded stage2. */
1295*12947SEnrico.Perla@Sun.COM if (find_multiboot(stage2->file, stage2->file_size, &mboot_off)
1296*12947SEnrico.Perla@Sun.COM != BC_SUCCESS) {
1297*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("WARNING: no multiboot structure found in stage2, "
1298*12947SEnrico.Perla@Sun.COM "are you using an old GRUB stage2?\n");
1299*12947SEnrico.Perla@Sun.COM if (do_version == B_TRUE) {
1300*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Versioning requested "
1301*12947SEnrico.Perla@Sun.COM "but stage2 does not support it.. skipping.\n"));
1302*12947SEnrico.Perla@Sun.COM do_version = B_FALSE;
1303*12947SEnrico.Perla@Sun.COM }
1304*12947SEnrico.Perla@Sun.COM } else {
1305*12947SEnrico.Perla@Sun.COM /* Keep track of where the multiboot header is. */
1306*12947SEnrico.Perla@Sun.COM stage2->mboot_off = mboot_off;
1307*12947SEnrico.Perla@Sun.COM stage2->mboot = (multiboot_header_t *)(stage2->file +
1308*12947SEnrico.Perla@Sun.COM mboot_off);
1309*12947SEnrico.Perla@Sun.COM if (do_version) {
1310*12947SEnrico.Perla@Sun.COM /*
1311*12947SEnrico.Perla@Sun.COM * Adding stage2 information needs to happen before
1312*12947SEnrico.Perla@Sun.COM * we modify the copy of stage2 we have in memory, so
1313*12947SEnrico.Perla@Sun.COM * that the hashing reflects the one of the file.
1314*12947SEnrico.Perla@Sun.COM * An error here is not fatal.
1315*12947SEnrico.Perla@Sun.COM */
1316*12947SEnrico.Perla@Sun.COM add_stage2_einfo(stage2, updt_str);
1317*12947SEnrico.Perla@Sun.COM }
1318*12947SEnrico.Perla@Sun.COM /*
1319*12947SEnrico.Perla@Sun.COM * Fill multiboot information. We add them even without
1320*12947SEnrico.Perla@Sun.COM * versioning to support as much as possible mirroring.
1321*12947SEnrico.Perla@Sun.COM */
1322*12947SEnrico.Perla@Sun.COM prepare_fake_multiboot(stage2);
13238434SEnrico.Perla@Sun.COM }
13240Sstevel@tonic-gate
1325*12947SEnrico.Perla@Sun.COM if (is_bootpar(device->type)) {
1326*12947SEnrico.Perla@Sun.COM uint32_t blocklist[SECTOR_SIZE / sizeof (uint32_t)];
1327*12947SEnrico.Perla@Sun.COM uint32_t install_addr = STAGE2_MEMADDR + SECTOR_SIZE;
1328*12947SEnrico.Perla@Sun.COM int i = 0;
1329*12947SEnrico.Perla@Sun.COM uchar_t *pos;
13300Sstevel@tonic-gate
1331*12947SEnrico.Perla@Sun.COM bzero(blocklist, sizeof (blocklist));
1332*12947SEnrico.Perla@Sun.COM if (read_stage2_blocklist(device->part_fd, blocklist) != 0) {
1333*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error reading pcfs "
1334*12947SEnrico.Perla@Sun.COM "stage2 blocklist\n"));
1335*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1336*12947SEnrico.Perla@Sun.COM }
13370Sstevel@tonic-gate
1338*12947SEnrico.Perla@Sun.COM pos = (uchar_t *)stage2->file + STAGE2_BLOCKLIST;
1339*12947SEnrico.Perla@Sun.COM stage2->first_sector = device->start_sector + blocklist[0];
1340*12947SEnrico.Perla@Sun.COM stage2->pcfs_first_sectors[0] = blocklist[0];
1341*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
1342*12947SEnrico.Perla@Sun.COM
1343*12947SEnrico.Perla@Sun.COM
13440Sstevel@tonic-gate if (blocklist[1] > 1) {
13450Sstevel@tonic-gate blocklist[0]++;
13460Sstevel@tonic-gate blocklist[1]--;
13470Sstevel@tonic-gate } else {
13480Sstevel@tonic-gate i += 2;
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate
1351*12947SEnrico.Perla@Sun.COM stage2->pcfs_first_sectors[1] = blocklist[i];
13520Sstevel@tonic-gate
13530Sstevel@tonic-gate while (blocklist[i]) {
13540Sstevel@tonic-gate if (START_BLOCK(pos - 8) != 0 &&
13550Sstevel@tonic-gate START_BLOCK(pos - 8) != blocklist[i + 2]) {
13560Sstevel@tonic-gate (void) fprintf(stderr, PCFS_FRAGMENTED);
1357*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
13580Sstevel@tonic-gate }
1359*12947SEnrico.Perla@Sun.COM START_BLOCK(pos) = blocklist[i] + device->start_sector;
13600Sstevel@tonic-gate START_SEG(pos) = (ushort_t)(install_addr >> 4);
13610Sstevel@tonic-gate NUM_BLOCK(pos) = blocklist[i + 1];
13620Sstevel@tonic-gate install_addr += blocklist[i + 1] * SECTOR_SIZE;
13630Sstevel@tonic-gate pos -= 8;
13640Sstevel@tonic-gate i += 2;
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate } else {
1367*12947SEnrico.Perla@Sun.COM /* Solaris VTOC */
1368*12947SEnrico.Perla@Sun.COM stage2->first_sector = device->start_sector + STAGE2_BLKOFF;
1369*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
13700Sstevel@tonic-gate /*
13710Sstevel@tonic-gate * In a solaris partition, stage2 is written to contiguous
13720Sstevel@tonic-gate * blocks. So we update the starting block only.
13730Sstevel@tonic-gate */
1374*12947SEnrico.Perla@Sun.COM *((ulong_t *)(stage2->file + STAGE2_BLOCKLIST)) =
1375*12947SEnrico.Perla@Sun.COM stage2->first_sector + 1;
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate
1378*12947SEnrico.Perla@Sun.COM /* force lba and set disk partition */
1379*12947SEnrico.Perla@Sun.COM *((unsigned char *) (stage2->file + STAGE2_FORCE_LBA)) = 1;
1380*12947SEnrico.Perla@Sun.COM *((long *)(stage2->file + STAGE2_INSTALLPART))
1381*12947SEnrico.Perla@Sun.COM = (device->partition << 16) | (device->slice << 8) | 0xff;
13820Sstevel@tonic-gate
1383*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
1384*12947SEnrico.Perla@Sun.COM }
1385*12947SEnrico.Perla@Sun.COM
1386*12947SEnrico.Perla@Sun.COM static int
find_x86_bootpar(struct mboot * mboot,int * part_num,uint32_t * start_sect)1387*12947SEnrico.Perla@Sun.COM find_x86_bootpar(struct mboot *mboot, int *part_num, uint32_t *start_sect)
1388*12947SEnrico.Perla@Sun.COM {
1389*12947SEnrico.Perla@Sun.COM int i;
13900Sstevel@tonic-gate
1391*12947SEnrico.Perla@Sun.COM for (i = 0; i < FD_NUMPART; i++) {
1392*12947SEnrico.Perla@Sun.COM struct ipart *part;
1393*12947SEnrico.Perla@Sun.COM
1394*12947SEnrico.Perla@Sun.COM part = (struct ipart *)mboot->parts + i;
1395*12947SEnrico.Perla@Sun.COM if (part->systid == 0xbe) {
1396*12947SEnrico.Perla@Sun.COM if (start_sect)
1397*12947SEnrico.Perla@Sun.COM *start_sect = part->relsect;
1398*12947SEnrico.Perla@Sun.COM if (part_num)
1399*12947SEnrico.Perla@Sun.COM *part_num = i;
1400*12947SEnrico.Perla@Sun.COM /* solaris boot part */
1401*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
14020Sstevel@tonic-gate }
14030Sstevel@tonic-gate }
1404*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate
14070Sstevel@tonic-gate static char *
get_raw_partition_path(ig_device_t * device)1408*12947SEnrico.Perla@Sun.COM get_raw_partition_path(ig_device_t *device)
14090Sstevel@tonic-gate {
1410*12947SEnrico.Perla@Sun.COM char *raw;
1411*12947SEnrico.Perla@Sun.COM int len;
14120Sstevel@tonic-gate
1413*12947SEnrico.Perla@Sun.COM if (is_bootpar(device->type)) {
1414*12947SEnrico.Perla@Sun.COM int part;
1415*12947SEnrico.Perla@Sun.COM struct mboot *mboot;
14160Sstevel@tonic-gate
1417*12947SEnrico.Perla@Sun.COM mboot = (struct mboot *)device->boot_sector;
1418*12947SEnrico.Perla@Sun.COM if (find_x86_bootpar(mboot, &part, NULL) != BC_SUCCESS) {
1419*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, BOOTPAR_NOTFOUND,
1420*12947SEnrico.Perla@Sun.COM device->path_p0);
1421*12947SEnrico.Perla@Sun.COM return (NULL);
14220Sstevel@tonic-gate }
14230Sstevel@tonic-gate
1424*12947SEnrico.Perla@Sun.COM raw = strdup(device->path_p0);
1425*12947SEnrico.Perla@Sun.COM if (raw == NULL) {
1426*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failed"));
1427*12947SEnrico.Perla@Sun.COM return (NULL);
14280Sstevel@tonic-gate }
1429*12947SEnrico.Perla@Sun.COM
1430*12947SEnrico.Perla@Sun.COM raw[strlen(raw) - 2] = '1' + part;
14310Sstevel@tonic-gate return (raw);
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate /* For disk, remember slice and return whole fdisk partition */
1435*12947SEnrico.Perla@Sun.COM raw = strdup(device->path);
1436*12947SEnrico.Perla@Sun.COM if (raw == NULL) {
1437*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failed"));
1438*12947SEnrico.Perla@Sun.COM return (NULL);
1439*12947SEnrico.Perla@Sun.COM }
1440*12947SEnrico.Perla@Sun.COM
14410Sstevel@tonic-gate len = strlen(raw);
14420Sstevel@tonic-gate if (raw[len - 2] != 's' || raw[len - 1] == '2') {
14430Sstevel@tonic-gate (void) fprintf(stderr, NOT_ROOT_SLICE);
1444*12947SEnrico.Perla@Sun.COM free(raw);
1445*12947SEnrico.Perla@Sun.COM return (NULL);
14460Sstevel@tonic-gate }
1447*12947SEnrico.Perla@Sun.COM device->slice = atoi(&raw[len - 1]);
14480Sstevel@tonic-gate
14490Sstevel@tonic-gate raw[len - 2] = 's';
14500Sstevel@tonic-gate raw[len - 1] = '2';
1451*12947SEnrico.Perla@Sun.COM
14520Sstevel@tonic-gate return (raw);
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate
1455*12947SEnrico.Perla@Sun.COM static int
get_raw_partition_fd(ig_device_t * device)1456*12947SEnrico.Perla@Sun.COM get_raw_partition_fd(ig_device_t *device)
1457*12947SEnrico.Perla@Sun.COM {
1458*12947SEnrico.Perla@Sun.COM struct stat stat = {0};
1459*12947SEnrico.Perla@Sun.COM char *raw;
1460*12947SEnrico.Perla@Sun.COM
1461*12947SEnrico.Perla@Sun.COM raw = get_raw_partition_path(device);
1462*12947SEnrico.Perla@Sun.COM if (raw == NULL)
1463*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1464*12947SEnrico.Perla@Sun.COM
1465*12947SEnrico.Perla@Sun.COM if (nowrite)
1466*12947SEnrico.Perla@Sun.COM device->part_fd = open(raw, O_RDONLY);
1467*12947SEnrico.Perla@Sun.COM else
1468*12947SEnrico.Perla@Sun.COM device->part_fd = open(raw, O_RDWR);
1469*12947SEnrico.Perla@Sun.COM
1470*12947SEnrico.Perla@Sun.COM if (device->part_fd < 0 || fstat(device->part_fd, &stat) != 0) {
1471*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, OPEN_FAIL, raw);
1472*12947SEnrico.Perla@Sun.COM free(raw);
1473*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1474*12947SEnrico.Perla@Sun.COM }
1475*12947SEnrico.Perla@Sun.COM
1476*12947SEnrico.Perla@Sun.COM if (S_ISCHR(stat.st_mode) == 0) {
1477*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, NOT_RAW_DEVICE, raw);
1478*12947SEnrico.Perla@Sun.COM (void) close(device->part_fd);
1479*12947SEnrico.Perla@Sun.COM device->part_fd = -1;
1480*12947SEnrico.Perla@Sun.COM free(raw);
1481*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
1482*12947SEnrico.Perla@Sun.COM }
1483*12947SEnrico.Perla@Sun.COM
1484*12947SEnrico.Perla@Sun.COM free(raw);
1485*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS);
1486*12947SEnrico.Perla@Sun.COM }
1487*12947SEnrico.Perla@Sun.COM
14880Sstevel@tonic-gate #define TMP_MNTPT "/tmp/installgrub_pcfs"
1489*12947SEnrico.Perla@Sun.COM static int
copy_stage2_to_pcfs(ig_data_t * install)1490*12947SEnrico.Perla@Sun.COM copy_stage2_to_pcfs(ig_data_t *install)
14910Sstevel@tonic-gate {
1492*12947SEnrico.Perla@Sun.COM FILE *mntfp;
1493*12947SEnrico.Perla@Sun.COM int pcfs_fp;
1494*12947SEnrico.Perla@Sun.COM int status = BC_ERROR;
1495*12947SEnrico.Perla@Sun.COM char buf[SECTOR_SIZE];
1496*12947SEnrico.Perla@Sun.COM char *cp;
1497*12947SEnrico.Perla@Sun.COM struct mnttab mp = {0}, mpref = {0};
1498*12947SEnrico.Perla@Sun.COM ig_device_t *device = &install->device;
1499*12947SEnrico.Perla@Sun.COM ig_stage2_t *stage2 = &install->stage2;
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate /* convert raw to block device name by removing the first 'r' */
1502*12947SEnrico.Perla@Sun.COM (void) strncpy(buf, device->path, sizeof (buf));
15030Sstevel@tonic-gate buf[sizeof (buf) - 1] = 0;
15040Sstevel@tonic-gate cp = strchr(buf, 'r');
15050Sstevel@tonic-gate if (cp == NULL) {
1506*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, CONVERT_FAIL, device->path);
1507*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
15080Sstevel@tonic-gate }
15090Sstevel@tonic-gate do {
15100Sstevel@tonic-gate *cp = *(cp + 1);
15110Sstevel@tonic-gate } while (*(++cp));
15120Sstevel@tonic-gate
15130Sstevel@tonic-gate /* get the mount point, if any */
15140Sstevel@tonic-gate mntfp = fopen("/etc/mnttab", "r");
15150Sstevel@tonic-gate if (mntfp == NULL) {
15160Sstevel@tonic-gate (void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab");
1517*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
15180Sstevel@tonic-gate }
15190Sstevel@tonic-gate
15200Sstevel@tonic-gate mpref.mnt_special = buf;
15210Sstevel@tonic-gate if (getmntany(mntfp, &mp, &mpref) != 0) {
15220Sstevel@tonic-gate char cmd[128];
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate /* not mounted, try remount */
15250Sstevel@tonic-gate (void) mkdir(TMP_MNTPT, S_IRWXU);
15260Sstevel@tonic-gate (void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s",
15270Sstevel@tonic-gate buf, TMP_MNTPT);
15280Sstevel@tonic-gate (void) system(cmd);
15290Sstevel@tonic-gate rewind(mntfp);
15300Sstevel@tonic-gate bzero(&mp, sizeof (mp));
15310Sstevel@tonic-gate if (getmntany(mntfp, &mp, &mpref) != 0) {
15320Sstevel@tonic-gate (void) fprintf(stderr, MOUNT_FAIL, buf);
1533*12947SEnrico.Perla@Sun.COM return (BC_ERROR);
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf),
15380Sstevel@tonic-gate "%s/boot", mp.mnt_mountp);
15390Sstevel@tonic-gate (void) mkdir(buf, S_IRWXU);
15400Sstevel@tonic-gate (void) strcat(buf, "/grub");
15410Sstevel@tonic-gate (void) mkdir(buf, S_IRWXU);
15420Sstevel@tonic-gate
15430Sstevel@tonic-gate (void) strcat(buf, "/stage2");
15440Sstevel@tonic-gate pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU);
15450Sstevel@tonic-gate if (pcfs_fp == -1) {
15460Sstevel@tonic-gate (void) fprintf(stderr, OPEN_FAIL_FILE, buf);
15470Sstevel@tonic-gate perror("open:");
1548*12947SEnrico.Perla@Sun.COM goto out;
15490Sstevel@tonic-gate }
15500Sstevel@tonic-gate
1551*12947SEnrico.Perla@Sun.COM /* write stage2 to the pcfs mounted filesystem. */
1552*12947SEnrico.Perla@Sun.COM if (write(pcfs_fp, stage2->file, stage2->file_size)
1553*12947SEnrico.Perla@Sun.COM != stage2->file_size) {
1554*12947SEnrico.Perla@Sun.COM perror(gettext("Error writing stage2"));
1555*12947SEnrico.Perla@Sun.COM goto out;
15560Sstevel@tonic-gate }
1557*12947SEnrico.Perla@Sun.COM
1558*12947SEnrico.Perla@Sun.COM status = BC_SUCCESS;
1559*12947SEnrico.Perla@Sun.COM out_fd:
15600Sstevel@tonic-gate (void) close(pcfs_fp);
1561*12947SEnrico.Perla@Sun.COM out:
15620Sstevel@tonic-gate (void) umount(TMP_MNTPT);
1563*12947SEnrico.Perla@Sun.COM (void) rmdir(TMP_MNTPT);
1564*12947SEnrico.Perla@Sun.COM return (status);
15650Sstevel@tonic-gate }
1566