144da779fSWilliam Kucharski /*
244da779fSWilliam Kucharski * CDDL HEADER START
344da779fSWilliam Kucharski *
444da779fSWilliam Kucharski * The contents of this file are subject to the terms of the
544da779fSWilliam Kucharski * Common Development and Distribution License (the "License").
644da779fSWilliam Kucharski * You may not use this file except in compliance with the License.
744da779fSWilliam Kucharski *
844da779fSWilliam Kucharski * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
944da779fSWilliam Kucharski * or http://www.opensolaris.org/os/licensing.
1044da779fSWilliam Kucharski * See the License for the specific language governing permissions
1144da779fSWilliam Kucharski * and limitations under the License.
1244da779fSWilliam Kucharski *
1344da779fSWilliam Kucharski * When distributing Covered Code, include this CDDL HEADER in each
1444da779fSWilliam Kucharski * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1544da779fSWilliam Kucharski * If applicable, add the following below this CDDL HEADER, with the
1644da779fSWilliam Kucharski * fields enclosed by brackets "[]" replaced with your own identifying
1744da779fSWilliam Kucharski * information: Portions Copyright [yyyy] [name of copyright owner]
1844da779fSWilliam Kucharski *
1944da779fSWilliam Kucharski * CDDL HEADER END
2044da779fSWilliam Kucharski */
21*23a1cceaSRoger A. Faulkner
2244da779fSWilliam Kucharski /*
23*23a1cceaSRoger A. Faulkner * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2444da779fSWilliam Kucharski */
2544da779fSWilliam Kucharski
2644da779fSWilliam Kucharski #include <stdio.h>
2744da779fSWilliam Kucharski #include <errno.h>
2844da779fSWilliam Kucharski #include <stdlib.h>
2944da779fSWilliam Kucharski #include <string.h>
3044da779fSWilliam Kucharski #include <unistd.h>
3144da779fSWilliam Kucharski #include <alloca.h>
3244da779fSWilliam Kucharski #include <ctype.h>
3344da779fSWilliam Kucharski #include <sys/types.h>
3444da779fSWilliam Kucharski
3544da779fSWilliam Kucharski #include "message.h"
3644da779fSWilliam Kucharski #include "bootadm.h"
3744da779fSWilliam Kucharski
3844da779fSWilliam Kucharski #define HYPER_KERNEL_DIR "/platform/i86xpv/kernel"
3944da779fSWilliam Kucharski #define METAL_KERNEL_DIR "/platform/i86pc/kernel"
4044da779fSWilliam Kucharski
4144da779fSWilliam Kucharski #define BOOTRC_FILE "/boot/solaris/bootenv.rc"
4244da779fSWilliam Kucharski #define ZFS_BOOTSTR "$ZFS-BOOTFS"
4344da779fSWilliam Kucharski
4444da779fSWilliam Kucharski #define BFLAG "-B"
4544da779fSWilliam Kucharski #define DEFAULT_SERIAL "9600,8,n,1"
4644da779fSWilliam Kucharski
4744da779fSWilliam Kucharski #define TTYXMODE_TO_COMNUM(ttyxmode) ((int)(*((ttyxmode) + 3) - '`'))
4844da779fSWilliam Kucharski #define COMNAME_TO_COMNUM(comname) ((int)(*((comname) + 3) - '0'))
4944da779fSWilliam Kucharski
5044da779fSWilliam Kucharski #define WHITESPC(x) (x)
5144da779fSWilliam Kucharski
5244da779fSWilliam Kucharski static char *serial_config[2] = { NULL, NULL };
5344da779fSWilliam Kucharski static char *console_dev = NULL;
5444da779fSWilliam Kucharski
55772d6a58SWilliam Kucharski static char *bootenv_rc_serial[2] = { NULL, NULL };
56772d6a58SWilliam Kucharski static char *bootenv_rc_console = NULL;
57772d6a58SWilliam Kucharski
5844da779fSWilliam Kucharski static unsigned zfs_boot = 0;
5944da779fSWilliam Kucharski
6044da779fSWilliam Kucharski /*
6144da779fSWilliam Kucharski * Append the string pointed to by "str" to the string pointed to by "orig"
6244da779fSWilliam Kucharski * adding the delimeter "delim" in between.
6344da779fSWilliam Kucharski *
6466b6aef6SWilliam Kucharski * Return a pointer to the new string or NULL, if we were passed a bad string.
6544da779fSWilliam Kucharski */
6644da779fSWilliam Kucharski static char *
append_str(char * orig,char * str,char * delim)6744da779fSWilliam Kucharski append_str(char *orig, char *str, char *delim)
6844da779fSWilliam Kucharski {
6944da779fSWilliam Kucharski char *newstr;
7044da779fSWilliam Kucharski int len;
7144da779fSWilliam Kucharski
7266b6aef6SWilliam Kucharski if ((str == NULL) || (delim == NULL))
7344da779fSWilliam Kucharski return (NULL);
7444da779fSWilliam Kucharski
7566b6aef6SWilliam Kucharski if ((orig == NULL) || (*orig == NULL)) {
7666b6aef6SWilliam Kucharski /*
7766b6aef6SWilliam Kucharski * Return a pointer to a copy of the path so a caller can
7866b6aef6SWilliam Kucharski * always rely upon being able to free() a returned pointer.
7966b6aef6SWilliam Kucharski */
8044da779fSWilliam Kucharski return (s_strdup(str));
8166b6aef6SWilliam Kucharski }
8244da779fSWilliam Kucharski
8344da779fSWilliam Kucharski len = strlen(orig) + strlen(str) + strlen(delim) + 1;
8466b6aef6SWilliam Kucharski if ((newstr = malloc(len)) == NULL) {
8566b6aef6SWilliam Kucharski bam_error(NO_MEM, len);
8666b6aef6SWilliam Kucharski bam_exit(1);
8766b6aef6SWilliam Kucharski }
8844da779fSWilliam Kucharski
8944da779fSWilliam Kucharski (void) snprintf(newstr, len, "%s%s%s", orig, delim, str);
9044da779fSWilliam Kucharski return (newstr);
9144da779fSWilliam Kucharski }
9244da779fSWilliam Kucharski
9344da779fSWilliam Kucharski /*
9444da779fSWilliam Kucharski * Replace the substring "old_str" in a path with the substring "new_str"
9544da779fSWilliam Kucharski *
9666b6aef6SWilliam Kucharski * Return a pointer to the modified string.
9744da779fSWilliam Kucharski */
9844da779fSWilliam Kucharski static char *
modify_path(char * path,char * old_str,char * new_str)9944da779fSWilliam Kucharski modify_path(char *path, char *old_str, char *new_str)
10044da779fSWilliam Kucharski {
10144da779fSWilliam Kucharski char *newpath;
10244da779fSWilliam Kucharski char *pc;
10366b6aef6SWilliam Kucharski int len;
10444da779fSWilliam Kucharski
10566b6aef6SWilliam Kucharski /*
10666b6aef6SWilliam Kucharski * Return a pointer to a copy of the path so a caller can always rely
10766b6aef6SWilliam Kucharski * upon being able to free() a returned pointer.
10866b6aef6SWilliam Kucharski */
10966b6aef6SWilliam Kucharski if ((pc = strstr(path, old_str)) == NULL)
11066b6aef6SWilliam Kucharski return (s_strdup(path));
11144da779fSWilliam Kucharski
11244da779fSWilliam Kucharski /*
11344da779fSWilliam Kucharski * Allocate space for duplicate of path with name changes and
11444da779fSWilliam Kucharski * NULL terminating byte
11544da779fSWilliam Kucharski */
11666b6aef6SWilliam Kucharski len = strlen(path) - strlen(old_str) + strlen(new_str) + 1;
11766b6aef6SWilliam Kucharski
11866b6aef6SWilliam Kucharski if ((newpath = malloc(len)) == NULL) {
11966b6aef6SWilliam Kucharski bam_error(NO_MEM, len);
12066b6aef6SWilliam Kucharski bam_exit(1);
12144da779fSWilliam Kucharski }
12244da779fSWilliam Kucharski
12366b6aef6SWilliam Kucharski (void) strlcpy(newpath, path, (pc - path) + 1);
12466b6aef6SWilliam Kucharski pc += strlen(old_str);
12544da779fSWilliam Kucharski
12644da779fSWilliam Kucharski (void) strcat(newpath, new_str);
12766b6aef6SWilliam Kucharski (void) strcat(newpath, pc);
12866b6aef6SWilliam Kucharski return (newpath);
12944da779fSWilliam Kucharski }
13044da779fSWilliam Kucharski
13144da779fSWilliam Kucharski /*
13244da779fSWilliam Kucharski * Set "token" to be the the string starting from the pointer "str" delimited
13344da779fSWilliam Kucharski * by any character in the string "delim" or the end of the string, but IGNORE
13444da779fSWilliam Kucharski * any characters between single or double quotes.
13544da779fSWilliam Kucharski *
13644da779fSWilliam Kucharski * Return a pointer to the next non-whitespace character after the delimiter
13744da779fSWilliam Kucharski * or NULL if we hit the end of the string. Also return NULL upon failure to
13844da779fSWilliam Kucharski * find any characters from the delimeter string or upon failure to allocate
13944da779fSWilliam Kucharski * memory for the new token string.
14044da779fSWilliam Kucharski */
14144da779fSWilliam Kucharski static char *
get_token(char ** token,char * str,char * delim)14244da779fSWilliam Kucharski get_token(char **token, char *str, char *delim)
14344da779fSWilliam Kucharski {
14444da779fSWilliam Kucharski char *dp;
14544da779fSWilliam Kucharski char *start = str;
14644da779fSWilliam Kucharski unsigned len;
14744da779fSWilliam Kucharski
14844da779fSWilliam Kucharski *token = NULL;
14944da779fSWilliam Kucharski
15044da779fSWilliam Kucharski if ((str == NULL) || (*str == NULL))
15144da779fSWilliam Kucharski return (NULL);
15244da779fSWilliam Kucharski
15344da779fSWilliam Kucharski do {
15444da779fSWilliam Kucharski if ((*str == '\'') || (*str == '"')) {
15544da779fSWilliam Kucharski char quote = *str++;
15644da779fSWilliam Kucharski
15744da779fSWilliam Kucharski while ((*str != NULL) && (*str != quote))
15844da779fSWilliam Kucharski str++;
15944da779fSWilliam Kucharski
16044da779fSWilliam Kucharski /* no matching quote found in string */
16144da779fSWilliam Kucharski if (*str++ == NULL)
16244da779fSWilliam Kucharski return (NULL);
16344da779fSWilliam Kucharski }
16444da779fSWilliam Kucharski
16544da779fSWilliam Kucharski /* look for a character from the delimiter string */
16644da779fSWilliam Kucharski for (dp = delim; ((*dp != NULL) && (*dp != *str)); dp++)
16744da779fSWilliam Kucharski ;
16844da779fSWilliam Kucharski
16944da779fSWilliam Kucharski if (*dp != NULL) {
17044da779fSWilliam Kucharski len = str - start + 1;
17144da779fSWilliam Kucharski
17244da779fSWilliam Kucharski /* found a delimiter, so create a token string */
17344da779fSWilliam Kucharski if ((*token = malloc(len)) == NULL) {
17444da779fSWilliam Kucharski bam_error(NO_MEM, len);
17566b6aef6SWilliam Kucharski bam_exit(1);
17644da779fSWilliam Kucharski }
17744da779fSWilliam Kucharski
17844da779fSWilliam Kucharski (void) strlcpy(*token, start, len);
17944da779fSWilliam Kucharski
18044da779fSWilliam Kucharski while (isspace((int)*++str))
18144da779fSWilliam Kucharski ;
18244da779fSWilliam Kucharski
18344da779fSWilliam Kucharski return (str);
18444da779fSWilliam Kucharski }
18544da779fSWilliam Kucharski } while (*str++ != NULL);
18644da779fSWilliam Kucharski
18744da779fSWilliam Kucharski /* if we hit the end of the string, the token is the whole string */
18844da779fSWilliam Kucharski *token = s_strdup(start);
18944da779fSWilliam Kucharski return (NULL);
19044da779fSWilliam Kucharski }
19144da779fSWilliam Kucharski
19244da779fSWilliam Kucharski /*
19344da779fSWilliam Kucharski * Convert a metal "console" device name to an equivalent one suitable for
19444da779fSWilliam Kucharski * use with the hypervisor.
19544da779fSWilliam Kucharski *
19644da779fSWilliam Kucharski * Default to "vga" if we can't parse the console device.
19744da779fSWilliam Kucharski */
19844da779fSWilliam Kucharski static void
console_metal_to_hyper(char * console)19944da779fSWilliam Kucharski console_metal_to_hyper(char *console)
20044da779fSWilliam Kucharski {
20144da779fSWilliam Kucharski if ((*console == '\'') || (*console == '"'))
20244da779fSWilliam Kucharski console++;
20344da779fSWilliam Kucharski
20444da779fSWilliam Kucharski if (strncmp(console, "ttya", 4) == 0)
20544da779fSWilliam Kucharski console_dev = "console=com1";
20644da779fSWilliam Kucharski else if (strncmp(console, "ttyb", 4) == 0)
20744da779fSWilliam Kucharski console_dev = "console=com2";
20844da779fSWilliam Kucharski else
20944da779fSWilliam Kucharski console_dev = "console=vga";
21044da779fSWilliam Kucharski }
21144da779fSWilliam Kucharski
21244da779fSWilliam Kucharski static int
set_serial_rate(int com,char * rate)21344da779fSWilliam Kucharski set_serial_rate(int com, char *rate)
21444da779fSWilliam Kucharski {
21544da779fSWilliam Kucharski char **rp = &serial_config[com - 1];
21644da779fSWilliam Kucharski
217772d6a58SWilliam Kucharski if ((com < 1) || (com > 2))
218772d6a58SWilliam Kucharski return (-1);
219772d6a58SWilliam Kucharski
22044da779fSWilliam Kucharski /*
22144da779fSWilliam Kucharski * If rate is a NULL pointer, erase any existing serial configuration
22244da779fSWilliam Kucharski * for this serial port.
22344da779fSWilliam Kucharski */
22444da779fSWilliam Kucharski if (rate == NULL) {
22544da779fSWilliam Kucharski if (*rp != NULL) {
22644da779fSWilliam Kucharski free(*rp);
22744da779fSWilliam Kucharski *rp = NULL;
22844da779fSWilliam Kucharski }
22944da779fSWilliam Kucharski return (0);
23044da779fSWilliam Kucharski }
23144da779fSWilliam Kucharski
23266b6aef6SWilliam Kucharski *rp = s_realloc(*rp, strlen(rate) + 1);
23344da779fSWilliam Kucharski (void) strcpy(*rp, rate);
23444da779fSWilliam Kucharski return (0);
23544da779fSWilliam Kucharski }
23644da779fSWilliam Kucharski
23744da779fSWilliam Kucharski /*
23844da779fSWilliam Kucharski * Convert "metal" serial port parameters to values compatible with the
23944da779fSWilliam Kucharski * hypervisor.
24044da779fSWilliam Kucharski *
24144da779fSWilliam Kucharski * Return 0 on success, otherwise -1.
24244da779fSWilliam Kucharski */
24344da779fSWilliam Kucharski static int
serial_metal_to_hyper(char * metal_port,char * metal_serial)24444da779fSWilliam Kucharski serial_metal_to_hyper(char *metal_port, char *metal_serial)
24544da779fSWilliam Kucharski {
24644da779fSWilliam Kucharski #define COM_RATE_LEN 16 /* strlen("com1=115200,8n1") */
24744da779fSWilliam Kucharski
24844da779fSWilliam Kucharski char com_rate[COM_RATE_LEN];
24944da779fSWilliam Kucharski
25044da779fSWilliam Kucharski unsigned com, baud, bits, stop;
25144da779fSWilliam Kucharski char parity, handshake;
25244da779fSWilliam Kucharski
25344da779fSWilliam Kucharski if ((strcmp(metal_port, "ttya-mode") == 0) ||
25444da779fSWilliam Kucharski (strcmp(metal_port, "ttyb-mode") == 0))
25544da779fSWilliam Kucharski com = TTYXMODE_TO_COMNUM(metal_port);
25644da779fSWilliam Kucharski else
25744da779fSWilliam Kucharski return (-1);
25844da779fSWilliam Kucharski
25944da779fSWilliam Kucharski if ((*metal_serial == '\'') || (*metal_serial == '"'))
26044da779fSWilliam Kucharski metal_serial++;
26144da779fSWilliam Kucharski
26244da779fSWilliam Kucharski /*
26344da779fSWilliam Kucharski * Check if it's specified as the default rate; if so it defaults to
26444da779fSWilliam Kucharski * "auto" and we need not set it for they hypervisor.
26544da779fSWilliam Kucharski */
26644da779fSWilliam Kucharski if (strncmp(metal_serial, DEFAULT_SERIAL,
26744da779fSWilliam Kucharski strlen(DEFAULT_SERIAL)) == 0) {
26844da779fSWilliam Kucharski (void) set_serial_rate(com, NULL);
26944da779fSWilliam Kucharski return (0);
27044da779fSWilliam Kucharski }
27144da779fSWilliam Kucharski
27244da779fSWilliam Kucharski /* read the serial port format as set forth in common/io/asy.c */
27344da779fSWilliam Kucharski if (sscanf(metal_serial, "%u,%u,%c,%u,%c", &baud, &bits, &parity, &stop,
27444da779fSWilliam Kucharski &handshake) != 5)
27544da779fSWilliam Kucharski return (-1);
27644da779fSWilliam Kucharski
27744da779fSWilliam Kucharski /* validate serial port parameters */
27844da779fSWilliam Kucharski if (((bits < 5) || (bits > 8)) || (stop > 1) ||
27944da779fSWilliam Kucharski ((parity != 'n') && (parity != 'e') && (parity != 'o')) ||
28044da779fSWilliam Kucharski ((handshake != '-') && (handshake != 'h') && (handshake != 's')))
28144da779fSWilliam Kucharski return (-1);
28244da779fSWilliam Kucharski
28344da779fSWilliam Kucharski /* validate baud rate */
28444da779fSWilliam Kucharski switch (baud) {
28544da779fSWilliam Kucharski case 150:
28644da779fSWilliam Kucharski case 300:
28744da779fSWilliam Kucharski case 600:
28844da779fSWilliam Kucharski case 1200:
28944da779fSWilliam Kucharski case 2400:
29044da779fSWilliam Kucharski case 4800:
29144da779fSWilliam Kucharski case 9600:
29244da779fSWilliam Kucharski case 19200:
29344da779fSWilliam Kucharski case 38400:
29444da779fSWilliam Kucharski case 57600:
29544da779fSWilliam Kucharski case 115200:
29644da779fSWilliam Kucharski break;
29744da779fSWilliam Kucharski
29844da779fSWilliam Kucharski default:
29944da779fSWilliam Kucharski return (-1);
30044da779fSWilliam Kucharski }
30144da779fSWilliam Kucharski
30244da779fSWilliam Kucharski /*
30344da779fSWilliam Kucharski * The hypervisor has no way to specify a handshake method, so it gets
30444da779fSWilliam Kucharski * quietly dropped in the conversion.
30544da779fSWilliam Kucharski */
30644da779fSWilliam Kucharski (void) snprintf(com_rate, COM_RATE_LEN, "com%d=%u,%u%c%u", com, baud,
30744da779fSWilliam Kucharski bits, parity, stop);
30844da779fSWilliam Kucharski (void) set_serial_rate(com, com_rate);
30944da779fSWilliam Kucharski return (0);
31044da779fSWilliam Kucharski }
31144da779fSWilliam Kucharski
31244da779fSWilliam Kucharski /*
31344da779fSWilliam Kucharski * Convert "name=value" metal options to values suitable for use with the
31444da779fSWilliam Kucharski * hypervisor.
31544da779fSWilliam Kucharski *
31644da779fSWilliam Kucharski * Our main concerns are the console device and serial port settings.
31744da779fSWilliam Kucharski *
31844da779fSWilliam Kucharski * Return values:
31944da779fSWilliam Kucharski *
32044da779fSWilliam Kucharski * -1: Unparseable line
32144da779fSWilliam Kucharski * 0: Success
32244da779fSWilliam Kucharski * (n > 0): A property unimportant to us
32344da779fSWilliam Kucharski */
32444da779fSWilliam Kucharski static int
cvt_metal_option(char * optstr)32544da779fSWilliam Kucharski cvt_metal_option(char *optstr)
32644da779fSWilliam Kucharski {
32744da779fSWilliam Kucharski char *value;
32844da779fSWilliam Kucharski unsigned namlen;
32944da779fSWilliam Kucharski
33044da779fSWilliam Kucharski if (strcmp(optstr, ZFS_BOOTSTR) == 0) {
33144da779fSWilliam Kucharski zfs_boot = 1;
33244da779fSWilliam Kucharski return (0);
33344da779fSWilliam Kucharski }
33444da779fSWilliam Kucharski
33544da779fSWilliam Kucharski if ((value = strchr(optstr, '=')) == NULL)
33644da779fSWilliam Kucharski return (-1);
33744da779fSWilliam Kucharski
33844da779fSWilliam Kucharski namlen = value - optstr;
33944da779fSWilliam Kucharski
34044da779fSWilliam Kucharski if (*++value == NULL)
34144da779fSWilliam Kucharski return (1);
34244da779fSWilliam Kucharski
34344da779fSWilliam Kucharski if (strncmp(optstr, "console", namlen) == 0) {
34444da779fSWilliam Kucharski console_metal_to_hyper(value);
34544da779fSWilliam Kucharski return (0);
34644da779fSWilliam Kucharski }
34744da779fSWilliam Kucharski
34844da779fSWilliam Kucharski if ((strncmp(optstr, "ttya-mode", namlen) == 0) ||
34944da779fSWilliam Kucharski (strncmp(optstr, "ttyb-mode", namlen) == 0)) {
350*23a1cceaSRoger A. Faulkner char *port = strndupa(optstr, namlen);
35144da779fSWilliam Kucharski
35244da779fSWilliam Kucharski return (serial_metal_to_hyper(port, value));
35344da779fSWilliam Kucharski }
35444da779fSWilliam Kucharski
35544da779fSWilliam Kucharski return (1);
35644da779fSWilliam Kucharski }
35744da779fSWilliam Kucharski
35844da779fSWilliam Kucharski /*
35944da779fSWilliam Kucharski * Convert "name=value" properties for use with a bare metal kernel
36044da779fSWilliam Kucharski *
36144da779fSWilliam Kucharski * Our main concerns are the console setting and serial port modes.
36244da779fSWilliam Kucharski *
36344da779fSWilliam Kucharski * Return values:
36444da779fSWilliam Kucharski *
36544da779fSWilliam Kucharski * -1: Unparseable line
36644da779fSWilliam Kucharski * 0: Success
36744da779fSWilliam Kucharski * (n > 0): A property unimportant to us
36844da779fSWilliam Kucharski */
36944da779fSWilliam Kucharski static int
cvt_hyper_option(char * optstr)37044da779fSWilliam Kucharski cvt_hyper_option(char *optstr)
37144da779fSWilliam Kucharski {
372772d6a58SWilliam Kucharski #define SER_LEN 15 /* strlen("115200,8,n,1,-") + 1 */
37344da779fSWilliam Kucharski
37444da779fSWilliam Kucharski char ser[SER_LEN];
37544da779fSWilliam Kucharski char *value;
37644da779fSWilliam Kucharski
37744da779fSWilliam Kucharski unsigned namlen;
37844da779fSWilliam Kucharski
37944da779fSWilliam Kucharski unsigned baud;
38044da779fSWilliam Kucharski char bits, parity, stop;
38144da779fSWilliam Kucharski
38244da779fSWilliam Kucharski if (strcmp(optstr, ZFS_BOOTSTR) == 0) {
38344da779fSWilliam Kucharski zfs_boot = 1;
38444da779fSWilliam Kucharski return (0);
38544da779fSWilliam Kucharski }
38644da779fSWilliam Kucharski
38744da779fSWilliam Kucharski /*
38844da779fSWilliam Kucharski * If there's no "=" in the token, it's likely a standalone
38944da779fSWilliam Kucharski * hypervisor token we don't care about (e.g. "noreboot" or
39044da779fSWilliam Kucharski * "nosmp") so we ignore it.
39144da779fSWilliam Kucharski */
39244da779fSWilliam Kucharski if ((value = strchr(optstr, '=')) == NULL)
39344da779fSWilliam Kucharski return (1);
39444da779fSWilliam Kucharski
39544da779fSWilliam Kucharski namlen = value - optstr;
39644da779fSWilliam Kucharski
39744da779fSWilliam Kucharski if (*++value == NULL)
39844da779fSWilliam Kucharski return (1);
39944da779fSWilliam Kucharski
40044da779fSWilliam Kucharski /*
40144da779fSWilliam Kucharski * Note that we use strncmp against the values because the
40244da779fSWilliam Kucharski * hypervisor allows setting console parameters for both the
40344da779fSWilliam Kucharski * console and debugger via the format:
40444da779fSWilliam Kucharski *
40544da779fSWilliam Kucharski * console=cons_dev,debug_dev
40644da779fSWilliam Kucharski *
40744da779fSWilliam Kucharski * and we only care about "cons_dev."
40844da779fSWilliam Kucharski *
40944da779fSWilliam Kucharski * This also allows us to extract "comN" from hypervisor constructs
41044da779fSWilliam Kucharski * like "com1H" or "com2L," concepts unsupported on bare metal kernels.
41144da779fSWilliam Kucharski *
41244da779fSWilliam Kucharski * Default the console device to "text" if it was "vga" or was
41344da779fSWilliam Kucharski * unparseable.
41444da779fSWilliam Kucharski */
41544da779fSWilliam Kucharski if (strncmp(optstr, "console", namlen) == 0) {
41644da779fSWilliam Kucharski /* ignore the "console=hypervisor" option */
41744da779fSWilliam Kucharski if (strcmp(value, "hypervisor") == 0)
41844da779fSWilliam Kucharski return (0);
41944da779fSWilliam Kucharski
42044da779fSWilliam Kucharski if (strncmp(value, "com1", 4) == 0)
421772d6a58SWilliam Kucharski console_dev = "ttya";
42244da779fSWilliam Kucharski else if (strncmp(value, "com2", 4) == 0)
423772d6a58SWilliam Kucharski console_dev = "ttyb";
42444da779fSWilliam Kucharski else
425772d6a58SWilliam Kucharski console_dev = "text";
42644da779fSWilliam Kucharski }
42744da779fSWilliam Kucharski
42844da779fSWilliam Kucharski /* serial port parameter conversion */
42944da779fSWilliam Kucharski
43044da779fSWilliam Kucharski if ((strncmp(optstr, "com1", namlen) == 0) ||
43144da779fSWilliam Kucharski (strncmp(optstr, "com2", namlen) == 0)) {
43244da779fSWilliam Kucharski unsigned com = COMNAME_TO_COMNUM(optstr);
43344da779fSWilliam Kucharski
43444da779fSWilliam Kucharski /*
43544da779fSWilliam Kucharski * Check if it's "auto" - if so, use the default setting
43644da779fSWilliam Kucharski * of "9600,8,n,1,-".
43744da779fSWilliam Kucharski *
43844da779fSWilliam Kucharski * We can't just assume the serial port will default to
43944da779fSWilliam Kucharski * "9600,8,n,1" as there could be a directive in bootenv.rc
44044da779fSWilliam Kucharski * that would set it to some other value and we want the serial
44144da779fSWilliam Kucharski * parameters to be the same as that used by the hypervisor.
44244da779fSWilliam Kucharski */
44344da779fSWilliam Kucharski if (strcmp(value, "auto") == 0) {
444772d6a58SWilliam Kucharski (void) snprintf(ser, SER_LEN, "9600,8,n,1,-");
445772d6a58SWilliam Kucharski } else {
44644da779fSWilliam Kucharski /*
447772d6a58SWilliam Kucharski * Extract the "B,PS" setting from the com line; ignore
448772d6a58SWilliam Kucharski * other settings like io_base or IRQ.
44944da779fSWilliam Kucharski */
45044da779fSWilliam Kucharski if (sscanf(value, "%u,%c%c%c", &baud, &bits, &parity,
45144da779fSWilliam Kucharski &stop) != 4)
45244da779fSWilliam Kucharski return (-1);
45344da779fSWilliam Kucharski
45444da779fSWilliam Kucharski /* validate serial port parameters */
45544da779fSWilliam Kucharski if (((stop != '0') && (stop != '1')) ||
45644da779fSWilliam Kucharski ((bits < '5') && (bits > '8')) ||
457772d6a58SWilliam Kucharski ((parity != 'n') && (parity != 'e') &&
458772d6a58SWilliam Kucharski (parity != 'o')))
45944da779fSWilliam Kucharski return (-1);
46044da779fSWilliam Kucharski
46144da779fSWilliam Kucharski /* validate baud rate */
46244da779fSWilliam Kucharski switch (baud) {
46344da779fSWilliam Kucharski case 150:
46444da779fSWilliam Kucharski case 300:
46544da779fSWilliam Kucharski case 600:
46644da779fSWilliam Kucharski case 1200:
46744da779fSWilliam Kucharski case 2400:
46844da779fSWilliam Kucharski case 4800:
46944da779fSWilliam Kucharski case 19200:
47044da779fSWilliam Kucharski case 38400:
47144da779fSWilliam Kucharski case 57600:
47244da779fSWilliam Kucharski case 115200:
47344da779fSWilliam Kucharski break;
47444da779fSWilliam Kucharski
47544da779fSWilliam Kucharski default:
47644da779fSWilliam Kucharski return (-1);
47744da779fSWilliam Kucharski }
47844da779fSWilliam Kucharski
47944da779fSWilliam Kucharski /*
480772d6a58SWilliam Kucharski * As the hypervisor has no way to denote handshaking
481772d6a58SWilliam Kucharski * in its serial port settings, emit a metal serial
482772d6a58SWilliam Kucharski * port configuration with none as well.
48344da779fSWilliam Kucharski */
484772d6a58SWilliam Kucharski (void) snprintf(ser, SER_LEN, "%u,%c,%c,%c,-", baud,
485772d6a58SWilliam Kucharski bits, parity, stop);
486772d6a58SWilliam Kucharski }
48744da779fSWilliam Kucharski
48844da779fSWilliam Kucharski if (set_serial_rate(com, ser) != 0)
48944da779fSWilliam Kucharski return (-1);
49044da779fSWilliam Kucharski
49144da779fSWilliam Kucharski return (0);
49244da779fSWilliam Kucharski }
49344da779fSWilliam Kucharski
49444da779fSWilliam Kucharski return (1);
49544da779fSWilliam Kucharski }
49644da779fSWilliam Kucharski
49744da779fSWilliam Kucharski /*
49844da779fSWilliam Kucharski * Parse a hardware kernel's "kernel$" specifier into parameters we can then
49944da779fSWilliam Kucharski * use to construct an appropriate "module$" line that can be used to specify
50044da779fSWilliam Kucharski * how to boot the hypervisor's dom0.
50144da779fSWilliam Kucharski *
50266b6aef6SWilliam Kucharski * Return values:
50366b6aef6SWilliam Kucharski *
50466b6aef6SWilliam Kucharski * -1: error parsing kernel path
50566b6aef6SWilliam Kucharski * 0: success
50666b6aef6SWilliam Kucharski * 1: kernel already a hypervisor kernel
50744da779fSWilliam Kucharski */
50844da779fSWilliam Kucharski static int
cvt_metal_kernel(char * kernstr,char ** path)50944da779fSWilliam Kucharski cvt_metal_kernel(char *kernstr, char **path)
51044da779fSWilliam Kucharski {
51144da779fSWilliam Kucharski char *token, *parsestr;
51244da779fSWilliam Kucharski
51366b6aef6SWilliam Kucharski parsestr = get_token(path, kernstr, " \t,");
51466b6aef6SWilliam Kucharski if (*path == NULL)
51566b6aef6SWilliam Kucharski return (-1);
51644da779fSWilliam Kucharski
51744da779fSWilliam Kucharski /*
51844da779fSWilliam Kucharski * If the metal kernel specified contains the name of the hypervisor,
51944da779fSWilliam Kucharski * we're probably trying to convert an entry already setup to run the
52044da779fSWilliam Kucharski * hypervisor, so error out now.
52144da779fSWilliam Kucharski */
52244da779fSWilliam Kucharski if (strstr(*path, XEN_MENU) != NULL) {
52344da779fSWilliam Kucharski bam_error(ALREADY_HYPER);
52466b6aef6SWilliam Kucharski free(*path);
52566b6aef6SWilliam Kucharski *path = NULL;
52666b6aef6SWilliam Kucharski return (1);
52744da779fSWilliam Kucharski }
52844da779fSWilliam Kucharski
52944da779fSWilliam Kucharski /* if the path was the last item on the line, that's OK. */
53044da779fSWilliam Kucharski if ((parsestr = get_token(&token, parsestr, " \t,")) == NULL) {
53144da779fSWilliam Kucharski if (token != NULL)
53244da779fSWilliam Kucharski free(token);
53344da779fSWilliam Kucharski return (0);
53444da779fSWilliam Kucharski }
53544da779fSWilliam Kucharski
53644da779fSWilliam Kucharski /* if the next token is "-B" process boot options */
53744da779fSWilliam Kucharski if (strncmp(token, BFLAG, strlen(BFLAG)) != 0) {
53844da779fSWilliam Kucharski free(token);
53944da779fSWilliam Kucharski return (0);
54044da779fSWilliam Kucharski }
54144da779fSWilliam Kucharski
54266b6aef6SWilliam Kucharski free(token);
54366b6aef6SWilliam Kucharski
54444da779fSWilliam Kucharski while ((parsestr = get_token(&token, parsestr, ",")) != NULL) {
54544da779fSWilliam Kucharski (void) cvt_metal_option(token);
54644da779fSWilliam Kucharski free(token);
54744da779fSWilliam Kucharski }
54844da779fSWilliam Kucharski
54944da779fSWilliam Kucharski if (token != NULL) {
55044da779fSWilliam Kucharski (void) cvt_metal_option(token);
55144da779fSWilliam Kucharski free(token);
55244da779fSWilliam Kucharski }
55344da779fSWilliam Kucharski
55444da779fSWilliam Kucharski return (0);
55544da779fSWilliam Kucharski }
55644da779fSWilliam Kucharski
55744da779fSWilliam Kucharski /*
55844da779fSWilliam Kucharski * Parse a hypervisor's "kernel$" line into parameters that can be used to
55944da779fSWilliam Kucharski * help build an appropriate "kernel$" line for booting a bare metal kernel.
56044da779fSWilliam Kucharski *
56144da779fSWilliam Kucharski * Return 0 on success, non-zero on failure.
56244da779fSWilliam Kucharski */
56344da779fSWilliam Kucharski static int
cvt_hyper_kernel(char * kernel)56444da779fSWilliam Kucharski cvt_hyper_kernel(char *kernel)
56544da779fSWilliam Kucharski {
56644da779fSWilliam Kucharski char *token, *parsestr;
56744da779fSWilliam Kucharski
56866b6aef6SWilliam Kucharski parsestr = get_token(&token, kernel, " \t,");
56966b6aef6SWilliam Kucharski
57066b6aef6SWilliam Kucharski if (token == NULL)
57166b6aef6SWilliam Kucharski return (-1);
57244da779fSWilliam Kucharski
57344da779fSWilliam Kucharski /*
57444da779fSWilliam Kucharski * If the hypervisor kernel specified lives in the metal kernel
57544da779fSWilliam Kucharski * directory, we're probably trying to convert an entry already setup
57644da779fSWilliam Kucharski * to run on bare metal, so error out now.
57744da779fSWilliam Kucharski */
57844da779fSWilliam Kucharski if (strncmp(token, METAL_KERNEL_DIR, strlen(METAL_KERNEL_DIR)) == 0) {
57944da779fSWilliam Kucharski bam_error(ALREADY_METAL);
58066b6aef6SWilliam Kucharski free(token);
58144da779fSWilliam Kucharski return (-1);
58244da779fSWilliam Kucharski }
58344da779fSWilliam Kucharski
58444da779fSWilliam Kucharski free(token);
58544da779fSWilliam Kucharski
58644da779fSWilliam Kucharski /* check for kernel options */
58744da779fSWilliam Kucharski while ((parsestr = get_token(&token, parsestr, " ")) != NULL) {
58844da779fSWilliam Kucharski (void) cvt_hyper_option(token);
58944da779fSWilliam Kucharski free(token);
59044da779fSWilliam Kucharski }
59144da779fSWilliam Kucharski
59244da779fSWilliam Kucharski if (token != NULL) {
59344da779fSWilliam Kucharski (void) cvt_hyper_option(token);
59444da779fSWilliam Kucharski free(token);
59544da779fSWilliam Kucharski }
59644da779fSWilliam Kucharski
59744da779fSWilliam Kucharski return (0);
59844da779fSWilliam Kucharski }
59944da779fSWilliam Kucharski
60044da779fSWilliam Kucharski /*
60144da779fSWilliam Kucharski * Parse a hypervisor's "module$" line into parameters that can be used to
60244da779fSWilliam Kucharski * help build an appropriate "kernel$" line for booting a bare metal kernel.
60344da779fSWilliam Kucharski */
60444da779fSWilliam Kucharski static void
cvt_hyper_module(char * modstr,char ** path)60544da779fSWilliam Kucharski cvt_hyper_module(char *modstr, char **path)
60644da779fSWilliam Kucharski {
60766b6aef6SWilliam Kucharski char *token = NULL;
60844da779fSWilliam Kucharski char *parsestr = modstr;
60944da779fSWilliam Kucharski
61044da779fSWilliam Kucharski /*
61144da779fSWilliam Kucharski * If multiple pathnames exist on the module$ line, we just want
61244da779fSWilliam Kucharski * the last one.
61344da779fSWilliam Kucharski */
61444da779fSWilliam Kucharski while ((parsestr = get_token(path, parsestr, " \t,")) != NULL) {
61544da779fSWilliam Kucharski if (*parsestr != '/')
61644da779fSWilliam Kucharski break;
61766b6aef6SWilliam Kucharski else
61844da779fSWilliam Kucharski free(*path);
61944da779fSWilliam Kucharski }
62044da779fSWilliam Kucharski
62144da779fSWilliam Kucharski /* if the path was the last item on the line, that's OK. */
62244da779fSWilliam Kucharski if ((parsestr == NULL) ||
62344da779fSWilliam Kucharski ((parsestr = get_token(&token, parsestr, " \t,")) == NULL)) {
62444da779fSWilliam Kucharski if (token != NULL)
62544da779fSWilliam Kucharski free(token);
62644da779fSWilliam Kucharski return;
62744da779fSWilliam Kucharski }
62844da779fSWilliam Kucharski
62966b6aef6SWilliam Kucharski if (token == NULL)
63066b6aef6SWilliam Kucharski return;
63166b6aef6SWilliam Kucharski
63244da779fSWilliam Kucharski /* check for "-B" option */
63344da779fSWilliam Kucharski if (strncmp(token, BFLAG, strlen(BFLAG)) != 0) {
63444da779fSWilliam Kucharski free(token);
63544da779fSWilliam Kucharski return;
63644da779fSWilliam Kucharski }
63744da779fSWilliam Kucharski
63866b6aef6SWilliam Kucharski free(token);
63966b6aef6SWilliam Kucharski
64044da779fSWilliam Kucharski /* check for kernel options */
64144da779fSWilliam Kucharski while ((parsestr = get_token(&token, parsestr, ",")) != NULL) {
64244da779fSWilliam Kucharski (void) cvt_hyper_option(token);
64344da779fSWilliam Kucharski free(token);
64444da779fSWilliam Kucharski }
64544da779fSWilliam Kucharski
64644da779fSWilliam Kucharski if (token != NULL) {
64744da779fSWilliam Kucharski (void) cvt_hyper_option(token);
64844da779fSWilliam Kucharski free(token);
64944da779fSWilliam Kucharski }
65044da779fSWilliam Kucharski }
65144da779fSWilliam Kucharski
65244da779fSWilliam Kucharski static void
parse_bootenvrc(char * osroot)65344da779fSWilliam Kucharski parse_bootenvrc(char *osroot)
65444da779fSWilliam Kucharski {
65544da779fSWilliam Kucharski #define LINEBUF_SZ 1024
65644da779fSWilliam Kucharski
65744da779fSWilliam Kucharski FILE *fp;
65844da779fSWilliam Kucharski char *rcpath;
65944da779fSWilliam Kucharski char line[LINEBUF_SZ]; /* make line buffer large but not ridiculous */
66044da779fSWilliam Kucharski int len;
66144da779fSWilliam Kucharski
66244da779fSWilliam Kucharski assert(osroot);
66344da779fSWilliam Kucharski
66444da779fSWilliam Kucharski len = strlen(osroot) + strlen(BOOTRC_FILE) + 1;
66544da779fSWilliam Kucharski rcpath = alloca(len);
66666b6aef6SWilliam Kucharski
66744da779fSWilliam Kucharski (void) snprintf(rcpath, len, "%s%s", osroot, BOOTRC_FILE);
66844da779fSWilliam Kucharski
66944da779fSWilliam Kucharski /* if we couldn't open the bootenv.rc file, ignore the issue. */
67044da779fSWilliam Kucharski if ((fp = fopen(rcpath, "r")) == NULL) {
67144da779fSWilliam Kucharski BAM_DPRINTF((D_NO_BOOTENVRC, rcpath, strerror(errno)));
67244da779fSWilliam Kucharski return;
67344da779fSWilliam Kucharski }
67444da779fSWilliam Kucharski
67544da779fSWilliam Kucharski while (s_fgets(line, LINEBUF_SZ, fp) != NULL) {
676772d6a58SWilliam Kucharski char *parsestr, *token;
677772d6a58SWilliam Kucharski int port = 0;
678772d6a58SWilliam Kucharski
67944da779fSWilliam Kucharski /* we're only interested in parsing "setprop" directives. */
68044da779fSWilliam Kucharski if (strncmp(line, "setprop", 7) != NULL)
68144da779fSWilliam Kucharski continue;
68244da779fSWilliam Kucharski
683772d6a58SWilliam Kucharski /* eat initial "setprop" */
684772d6a58SWilliam Kucharski if ((parsestr = get_token(&token, line, " \t")) == NULL) {
685772d6a58SWilliam Kucharski if (token != NULL)
686772d6a58SWilliam Kucharski free(token);
687772d6a58SWilliam Kucharski
688772d6a58SWilliam Kucharski continue;
689772d6a58SWilliam Kucharski }
690772d6a58SWilliam Kucharski
691772d6a58SWilliam Kucharski if (strcmp(token, "setprop") != 0) {
692772d6a58SWilliam Kucharski free(token);
693772d6a58SWilliam Kucharski continue;
694772d6a58SWilliam Kucharski }
695772d6a58SWilliam Kucharski
696772d6a58SWilliam Kucharski free(token);
697772d6a58SWilliam Kucharski
698772d6a58SWilliam Kucharski /* get property name */
699772d6a58SWilliam Kucharski if ((parsestr = get_token(&token, parsestr, " \t")) == NULL) {
700772d6a58SWilliam Kucharski if (token != NULL)
701772d6a58SWilliam Kucharski free(token);
702772d6a58SWilliam Kucharski
703772d6a58SWilliam Kucharski continue;
704772d6a58SWilliam Kucharski }
705772d6a58SWilliam Kucharski
706772d6a58SWilliam Kucharski if (strcmp(token, "console") == 0) {
707772d6a58SWilliam Kucharski free(token);
708772d6a58SWilliam Kucharski
709772d6a58SWilliam Kucharski /* get console property value */
710772d6a58SWilliam Kucharski parsestr = get_token(&token, parsestr, " \t");
711772d6a58SWilliam Kucharski if (token == NULL)
712772d6a58SWilliam Kucharski continue;
713772d6a58SWilliam Kucharski
714772d6a58SWilliam Kucharski if (bootenv_rc_console != NULL)
715772d6a58SWilliam Kucharski free(bootenv_rc_console);
716772d6a58SWilliam Kucharski
717772d6a58SWilliam Kucharski bootenv_rc_console = s_strdup(token);
718772d6a58SWilliam Kucharski continue;
719772d6a58SWilliam Kucharski }
720772d6a58SWilliam Kucharski
721772d6a58SWilliam Kucharski /* check if it's a serial port setting */
722772d6a58SWilliam Kucharski if (strcmp(token, "ttya-mode") == 0) {
723772d6a58SWilliam Kucharski free(token);
724772d6a58SWilliam Kucharski port = 0;
725772d6a58SWilliam Kucharski } else if (strcmp(token, "ttyb-mode") == 0) {
726772d6a58SWilliam Kucharski free(token);
727772d6a58SWilliam Kucharski port = 1;
728772d6a58SWilliam Kucharski } else {
729772d6a58SWilliam Kucharski /* nope, so check the next line */
730772d6a58SWilliam Kucharski free(token);
731772d6a58SWilliam Kucharski continue;
732772d6a58SWilliam Kucharski }
733772d6a58SWilliam Kucharski
734772d6a58SWilliam Kucharski /* get serial port setting */
735772d6a58SWilliam Kucharski parsestr = get_token(&token, parsestr, " \t");
736772d6a58SWilliam Kucharski
737772d6a58SWilliam Kucharski if (token == NULL)
738772d6a58SWilliam Kucharski continue;
739772d6a58SWilliam Kucharski
740772d6a58SWilliam Kucharski if (bootenv_rc_serial[port] != NULL)
741772d6a58SWilliam Kucharski free(bootenv_rc_serial[port]);
742772d6a58SWilliam Kucharski
743772d6a58SWilliam Kucharski bootenv_rc_serial[port] = s_strdup(token);
744772d6a58SWilliam Kucharski free(token);
74544da779fSWilliam Kucharski }
74644da779fSWilliam Kucharski
74744da779fSWilliam Kucharski (void) fclose(fp);
74844da779fSWilliam Kucharski }
74944da779fSWilliam Kucharski
75044da779fSWilliam Kucharski error_t
cvt_to_hyper(menu_t * mp,char * osroot,char * extra_args)75144da779fSWilliam Kucharski cvt_to_hyper(menu_t *mp, char *osroot, char *extra_args)
75244da779fSWilliam Kucharski {
75344da779fSWilliam Kucharski const char *fcn = "cvt_to_hyper()";
75444da779fSWilliam Kucharski
75544da779fSWilliam Kucharski line_t *lp;
75644da779fSWilliam Kucharski entry_t *ent;
75744da779fSWilliam Kucharski size_t len, zfslen;
75844da779fSWilliam Kucharski
75966b6aef6SWilliam Kucharski char *newstr;
76044da779fSWilliam Kucharski char *osdev;
76144da779fSWilliam Kucharski
76244da779fSWilliam Kucharski char *title = NULL;
76344da779fSWilliam Kucharski char *findroot = NULL;
76444da779fSWilliam Kucharski char *bootfs = NULL;
76544da779fSWilliam Kucharski char *kernel = NULL;
76644da779fSWilliam Kucharski char *mod_kernel = NULL;
76744da779fSWilliam Kucharski char *module = NULL;
76844da779fSWilliam Kucharski
76944da779fSWilliam Kucharski char *kern_path = NULL;
77044da779fSWilliam Kucharski char *kern_bargs = NULL;
77144da779fSWilliam Kucharski
772772d6a58SWilliam Kucharski int curdef, newdef;
77366b6aef6SWilliam Kucharski int kp_allocated = 0;
77444da779fSWilliam Kucharski int ret = BAM_ERROR;
77544da779fSWilliam Kucharski
77644da779fSWilliam Kucharski assert(osroot);
77744da779fSWilliam Kucharski
77844da779fSWilliam Kucharski BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, extra_args));
77944da779fSWilliam Kucharski
78044da779fSWilliam Kucharski /*
78144da779fSWilliam Kucharski * First just check to verify osroot is a sane directory.
78244da779fSWilliam Kucharski */
78344da779fSWilliam Kucharski if ((osdev = get_special(osroot)) == NULL) {
78444da779fSWilliam Kucharski bam_error(CANT_FIND_SPECIAL, osroot);
78544da779fSWilliam Kucharski return (BAM_ERROR);
78644da779fSWilliam Kucharski }
78744da779fSWilliam Kucharski
78844da779fSWilliam Kucharski free(osdev);
78944da779fSWilliam Kucharski
79044da779fSWilliam Kucharski /*
79144da779fSWilliam Kucharski * While the effect is purely cosmetic, if osroot is "/" don't
79244da779fSWilliam Kucharski * bother prepending it to any paths as they are constructed to
79344da779fSWilliam Kucharski * begin with "/" anyway.
79444da779fSWilliam Kucharski */
79544da779fSWilliam Kucharski if (strcmp(osroot, "/") == 0)
79644da779fSWilliam Kucharski osroot = "";
79744da779fSWilliam Kucharski
79844da779fSWilliam Kucharski /*
79944da779fSWilliam Kucharski * Found the GRUB signature on the target partitions, so now get the
80044da779fSWilliam Kucharski * default GRUB boot entry number from the menu.lst file
80144da779fSWilliam Kucharski */
80244da779fSWilliam Kucharski curdef = atoi(mp->curdefault->arg);
80344da779fSWilliam Kucharski
80444da779fSWilliam Kucharski /* look for the first line of the matching boot entry */
80544da779fSWilliam Kucharski for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != curdef));
80644da779fSWilliam Kucharski ent = ent->next)
80744da779fSWilliam Kucharski ;
80844da779fSWilliam Kucharski
80944da779fSWilliam Kucharski /* couldn't find it, so error out */
81044da779fSWilliam Kucharski if (ent == NULL) {
81144da779fSWilliam Kucharski bam_error(CANT_FIND_DEFAULT, curdef);
81244da779fSWilliam Kucharski goto abort;
81344da779fSWilliam Kucharski }
81444da779fSWilliam Kucharski
81544da779fSWilliam Kucharski /*
81644da779fSWilliam Kucharski * We found the proper menu entry, so first we need to process the
81744da779fSWilliam Kucharski * bootenv.rc file to look for boot options the hypervisor might need
81844da779fSWilliam Kucharski * passed as kernel start options such as the console device and serial
81944da779fSWilliam Kucharski * port parameters.
82044da779fSWilliam Kucharski *
82144da779fSWilliam Kucharski * If there's no bootenv.rc, it's not an issue.
82244da779fSWilliam Kucharski */
82344da779fSWilliam Kucharski parse_bootenvrc(osroot);
82444da779fSWilliam Kucharski
825772d6a58SWilliam Kucharski if (bootenv_rc_console != NULL)
826772d6a58SWilliam Kucharski console_metal_to_hyper(bootenv_rc_console);
827772d6a58SWilliam Kucharski
828772d6a58SWilliam Kucharski if (bootenv_rc_serial[0] != NULL)
829772d6a58SWilliam Kucharski (void) serial_metal_to_hyper("ttya-mode", bootenv_rc_serial[0]);
830772d6a58SWilliam Kucharski
831772d6a58SWilliam Kucharski if (bootenv_rc_serial[1] != NULL)
832772d6a58SWilliam Kucharski (void) serial_metal_to_hyper("ttyb-mode", bootenv_rc_serial[1]);
833772d6a58SWilliam Kucharski
83444da779fSWilliam Kucharski /*
83544da779fSWilliam Kucharski * Now process the entry itself.
83644da779fSWilliam Kucharski */
83744da779fSWilliam Kucharski for (lp = ent->start; lp != NULL; lp = lp->next) {
83844da779fSWilliam Kucharski /*
83944da779fSWilliam Kucharski * Process important lines from menu.lst boot entry.
84044da779fSWilliam Kucharski */
84144da779fSWilliam Kucharski if (lp->flags == BAM_TITLE) {
842*23a1cceaSRoger A. Faulkner title = strdupa(lp->arg);
843eac223ccSWilliam Kucharski } else if (lp->cmd != NULL) {
844eac223ccSWilliam Kucharski if (strcmp(lp->cmd, "findroot") == 0) {
845*23a1cceaSRoger A. Faulkner findroot = strdupa(lp->arg);
84644da779fSWilliam Kucharski } else if (strcmp(lp->cmd, "bootfs") == 0) {
847*23a1cceaSRoger A. Faulkner bootfs = strdupa(lp->arg);
848eac223ccSWilliam Kucharski } else if (strcmp(lp->cmd,
849eac223ccSWilliam Kucharski menu_cmds[MODULE_DOLLAR_CMD]) == 0) {
850*23a1cceaSRoger A. Faulkner module = strdupa(lp->arg);
85144da779fSWilliam Kucharski } else if ((strcmp(lp->cmd,
85244da779fSWilliam Kucharski menu_cmds[KERNEL_DOLLAR_CMD]) == 0) &&
853eac223ccSWilliam Kucharski (ret = cvt_metal_kernel(lp->arg,
854eac223ccSWilliam Kucharski &kern_path)) != 0) {
85566b6aef6SWilliam Kucharski if (ret < 0) {
85666b6aef6SWilliam Kucharski ret = BAM_ERROR;
85766b6aef6SWilliam Kucharski bam_error(KERNEL_NOT_PARSEABLE, curdef);
85866b6aef6SWilliam Kucharski } else
85944da779fSWilliam Kucharski ret = BAM_NOCHANGE;
86066b6aef6SWilliam Kucharski
86144da779fSWilliam Kucharski goto abort;
86244da779fSWilliam Kucharski }
863eac223ccSWilliam Kucharski }
86444da779fSWilliam Kucharski
86544da779fSWilliam Kucharski if (lp == ent->end)
86644da779fSWilliam Kucharski break;
86744da779fSWilliam Kucharski }
86844da779fSWilliam Kucharski
86944da779fSWilliam Kucharski /*
870772d6a58SWilliam Kucharski * If findroot, module or kern_path are NULL, the boot entry is
871772d6a58SWilliam Kucharski * malformed.
87244da779fSWilliam Kucharski */
87344da779fSWilliam Kucharski if (findroot == NULL) {
87444da779fSWilliam Kucharski bam_error(FINDROOT_NOT_FOUND, curdef);
87544da779fSWilliam Kucharski goto abort;
87644da779fSWilliam Kucharski }
87744da779fSWilliam Kucharski
87844da779fSWilliam Kucharski if (module == NULL) {
87944da779fSWilliam Kucharski bam_error(MODULE_NOT_PARSEABLE, curdef);
88044da779fSWilliam Kucharski goto abort;
88144da779fSWilliam Kucharski }
88244da779fSWilliam Kucharski
88344da779fSWilliam Kucharski if (kern_path == NULL) {
88444da779fSWilliam Kucharski bam_error(KERNEL_NOT_FOUND, curdef);
88544da779fSWilliam Kucharski goto abort;
88644da779fSWilliam Kucharski }
88744da779fSWilliam Kucharski
88844da779fSWilliam Kucharski /* assemble new kernel and module arguments from parsed values */
88944da779fSWilliam Kucharski if (console_dev != NULL) {
89044da779fSWilliam Kucharski kern_bargs = s_strdup(console_dev);
89144da779fSWilliam Kucharski
89266b6aef6SWilliam Kucharski if (serial_config[0] != NULL) {
89366b6aef6SWilliam Kucharski newstr = append_str(kern_bargs, serial_config[0], " ");
89466b6aef6SWilliam Kucharski free(kern_bargs);
89566b6aef6SWilliam Kucharski kern_bargs = newstr;
89644da779fSWilliam Kucharski }
89744da779fSWilliam Kucharski
89866b6aef6SWilliam Kucharski if (serial_config[1] != NULL) {
89966b6aef6SWilliam Kucharski newstr = append_str(kern_bargs, serial_config[1], " ");
90066b6aef6SWilliam Kucharski free(kern_bargs);
90166b6aef6SWilliam Kucharski kern_bargs = newstr;
90266b6aef6SWilliam Kucharski }
90366b6aef6SWilliam Kucharski }
90466b6aef6SWilliam Kucharski
90566b6aef6SWilliam Kucharski if ((extra_args != NULL) && (*extra_args != NULL)) {
90666b6aef6SWilliam Kucharski newstr = append_str(kern_bargs, extra_args, " ");
90766b6aef6SWilliam Kucharski free(kern_bargs);
90866b6aef6SWilliam Kucharski kern_bargs = newstr;
90966b6aef6SWilliam Kucharski }
91044da779fSWilliam Kucharski
91144da779fSWilliam Kucharski len = strlen(osroot) + strlen(XEN_MENU) + strlen(kern_bargs) +
91244da779fSWilliam Kucharski WHITESPC(1) + 1;
91344da779fSWilliam Kucharski
91444da779fSWilliam Kucharski kernel = alloca(len);
91544da779fSWilliam Kucharski
91666b6aef6SWilliam Kucharski if (kern_bargs != NULL) {
91766b6aef6SWilliam Kucharski if (*kern_bargs != NULL)
91866b6aef6SWilliam Kucharski (void) snprintf(kernel, len, "%s%s %s", osroot,
91966b6aef6SWilliam Kucharski XEN_MENU, kern_bargs);
92066b6aef6SWilliam Kucharski
92144da779fSWilliam Kucharski free(kern_bargs);
92244da779fSWilliam Kucharski } else {
92344da779fSWilliam Kucharski (void) snprintf(kernel, len, "%s%s", osroot, XEN_MENU);
92444da779fSWilliam Kucharski }
92544da779fSWilliam Kucharski
92644da779fSWilliam Kucharski /*
92744da779fSWilliam Kucharski * Change the kernel directory from the metal version to that needed for
92844da779fSWilliam Kucharski * the hypervisor. Convert either "direct boot" path to the default
92944da779fSWilliam Kucharski * path.
93044da779fSWilliam Kucharski */
93144da779fSWilliam Kucharski if ((strcmp(kern_path, DIRECT_BOOT_32) == 0) ||
93244da779fSWilliam Kucharski (strcmp(kern_path, DIRECT_BOOT_64) == 0)) {
93344da779fSWilliam Kucharski kern_path = HYPERVISOR_KERNEL;
93444da779fSWilliam Kucharski } else {
93566b6aef6SWilliam Kucharski newstr = modify_path(kern_path, METAL_KERNEL_DIR,
93644da779fSWilliam Kucharski HYPER_KERNEL_DIR);
93766b6aef6SWilliam Kucharski free(kern_path);
93866b6aef6SWilliam Kucharski kern_path = newstr;
93966b6aef6SWilliam Kucharski kp_allocated = 1;
94044da779fSWilliam Kucharski }
94144da779fSWilliam Kucharski
94244da779fSWilliam Kucharski /*
94344da779fSWilliam Kucharski * We need to allocate space for the kernel path (twice) plus an
94444da779fSWilliam Kucharski * intervening space, possibly the ZFS boot string, and NULL,
94544da779fSWilliam Kucharski * of course.
94644da779fSWilliam Kucharski */
94744da779fSWilliam Kucharski len = (strlen(kern_path) * 2) + WHITESPC(1) + 1;
94844da779fSWilliam Kucharski zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0);
94944da779fSWilliam Kucharski
95044da779fSWilliam Kucharski mod_kernel = alloca(len + zfslen);
95144da779fSWilliam Kucharski (void) snprintf(mod_kernel, len, "%s %s", kern_path, kern_path);
95244da779fSWilliam Kucharski
95344da779fSWilliam Kucharski if (kp_allocated)
95444da779fSWilliam Kucharski free(kern_path);
95544da779fSWilliam Kucharski
95644da779fSWilliam Kucharski if (zfs_boot) {
95744da779fSWilliam Kucharski char *zfsstr = alloca(zfslen + 1);
95844da779fSWilliam Kucharski
95944da779fSWilliam Kucharski (void) snprintf(zfsstr, zfslen + 1, " %s", ZFS_BOOT);
96044da779fSWilliam Kucharski (void) strcat(mod_kernel, zfsstr);
96144da779fSWilliam Kucharski }
96244da779fSWilliam Kucharski
96344da779fSWilliam Kucharski /* shut off warning messages from the entry line parser */
96444da779fSWilliam Kucharski if (ent->flags & BAM_ENTRY_BOOTADM)
96544da779fSWilliam Kucharski ent->flags &= ~BAM_ENTRY_BOOTADM;
96644da779fSWilliam Kucharski
96744da779fSWilliam Kucharski BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, kernel));
96844da779fSWilliam Kucharski BAM_DPRINTF((D_CVT_CMD_MOD_DOLLAR, fcn, mod_kernel));
96944da779fSWilliam Kucharski
970772d6a58SWilliam Kucharski if ((newdef = add_boot_entry(mp, title, findroot, kernel, mod_kernel,
971772d6a58SWilliam Kucharski module, bootfs)) == BAM_ERROR)
972772d6a58SWilliam Kucharski return (newdef);
973772d6a58SWilliam Kucharski
97444da779fSWilliam Kucharski /*
97544da779fSWilliam Kucharski * Now try to delete the current default entry from the menu and add
97644da779fSWilliam Kucharski * the new hypervisor entry with the parameters we've setup.
97744da779fSWilliam Kucharski */
978772d6a58SWilliam Kucharski if (delete_boot_entry(mp, curdef, DBE_QUIET) == BAM_SUCCESS)
979772d6a58SWilliam Kucharski newdef--;
980772d6a58SWilliam Kucharski else
98144da779fSWilliam Kucharski bam_print(NEW_BOOT_ENTRY, title);
98244da779fSWilliam Kucharski
98344da779fSWilliam Kucharski /*
98444da779fSWilliam Kucharski * If we successfully created the new entry, set the default boot
98544da779fSWilliam Kucharski * entry to that entry and let the caller know the new menu should
98644da779fSWilliam Kucharski * be written out.
98744da779fSWilliam Kucharski */
988772d6a58SWilliam Kucharski return (set_global(mp, menu_cmds[DEFAULT_CMD], newdef));
98944da779fSWilliam Kucharski
99044da779fSWilliam Kucharski abort:
99144da779fSWilliam Kucharski if (ret != BAM_NOCHANGE)
99244da779fSWilliam Kucharski bam_error(HYPER_ABORT, ((*osroot == NULL) ? "/" : osroot));
99344da779fSWilliam Kucharski
99444da779fSWilliam Kucharski return (ret);
99544da779fSWilliam Kucharski }
99644da779fSWilliam Kucharski
99744da779fSWilliam Kucharski /*ARGSUSED*/
99844da779fSWilliam Kucharski error_t
cvt_to_metal(menu_t * mp,char * osroot,char * menu_root)99944da779fSWilliam Kucharski cvt_to_metal(menu_t *mp, char *osroot, char *menu_root)
100044da779fSWilliam Kucharski {
100144da779fSWilliam Kucharski const char *fcn = "cvt_to_metal()";
100244da779fSWilliam Kucharski
100344da779fSWilliam Kucharski line_t *lp;
100444da779fSWilliam Kucharski entry_t *ent;
100544da779fSWilliam Kucharski size_t len, zfslen;
100644da779fSWilliam Kucharski
100744da779fSWilliam Kucharski char *delim = ",";
100866b6aef6SWilliam Kucharski char *newstr;
100944da779fSWilliam Kucharski char *osdev;
101044da779fSWilliam Kucharski
101144da779fSWilliam Kucharski char *title = NULL;
101244da779fSWilliam Kucharski char *findroot = NULL;
101344da779fSWilliam Kucharski char *bootfs = NULL;
101444da779fSWilliam Kucharski char *kernel = NULL;
101544da779fSWilliam Kucharski char *module = NULL;
101644da779fSWilliam Kucharski
101744da779fSWilliam Kucharski char *barchive_path = DIRECT_BOOT_ARCHIVE;
101844da779fSWilliam Kucharski char *kern_path = NULL;
101944da779fSWilliam Kucharski
1020772d6a58SWilliam Kucharski int curdef, newdef;
102144da779fSWilliam Kucharski int emit_bflag = 1;
102244da779fSWilliam Kucharski int ret = BAM_ERROR;
102344da779fSWilliam Kucharski
102444da779fSWilliam Kucharski assert(osroot);
102544da779fSWilliam Kucharski
102644da779fSWilliam Kucharski BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, ""));
102744da779fSWilliam Kucharski
102844da779fSWilliam Kucharski /*
102944da779fSWilliam Kucharski * First just check to verify osroot is a sane directory.
103044da779fSWilliam Kucharski */
103144da779fSWilliam Kucharski if ((osdev = get_special(osroot)) == NULL) {
103244da779fSWilliam Kucharski bam_error(CANT_FIND_SPECIAL, osroot);
103344da779fSWilliam Kucharski return (BAM_ERROR);
103444da779fSWilliam Kucharski }
103544da779fSWilliam Kucharski
103644da779fSWilliam Kucharski free(osdev);
103744da779fSWilliam Kucharski
103844da779fSWilliam Kucharski /*
103944da779fSWilliam Kucharski * Found the GRUB signature on the target partitions, so now get the
104044da779fSWilliam Kucharski * default GRUB boot entry number from the menu.lst file
104144da779fSWilliam Kucharski */
104244da779fSWilliam Kucharski curdef = atoi(mp->curdefault->arg);
104344da779fSWilliam Kucharski
104444da779fSWilliam Kucharski /* look for the first line of the matching boot entry */
104544da779fSWilliam Kucharski for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != curdef));
104644da779fSWilliam Kucharski ent = ent->next)
104744da779fSWilliam Kucharski ;
104844da779fSWilliam Kucharski
104944da779fSWilliam Kucharski /* couldn't find it, so error out */
105044da779fSWilliam Kucharski if (ent == NULL) {
105144da779fSWilliam Kucharski bam_error(CANT_FIND_DEFAULT, curdef);
105244da779fSWilliam Kucharski goto abort;
105344da779fSWilliam Kucharski }
105444da779fSWilliam Kucharski
105544da779fSWilliam Kucharski /*
105644da779fSWilliam Kucharski * Now process the entry itself.
105744da779fSWilliam Kucharski */
105844da779fSWilliam Kucharski for (lp = ent->start; lp != NULL; lp = lp->next) {
105944da779fSWilliam Kucharski /*
106044da779fSWilliam Kucharski * Process important lines from menu.lst boot entry.
106144da779fSWilliam Kucharski */
106244da779fSWilliam Kucharski if (lp->flags == BAM_TITLE) {
1063*23a1cceaSRoger A. Faulkner title = strdupa(lp->arg);
1064eac223ccSWilliam Kucharski } else if (lp->cmd != NULL) {
1065eac223ccSWilliam Kucharski if (strcmp(lp->cmd, "findroot") == 0) {
1066*23a1cceaSRoger A. Faulkner findroot = strdupa(lp->arg);
106744da779fSWilliam Kucharski } else if (strcmp(lp->cmd, "bootfs") == 0) {
1068*23a1cceaSRoger A. Faulkner bootfs = strdupa(lp->arg);
1069eac223ccSWilliam Kucharski } else if (strcmp(lp->cmd,
1070eac223ccSWilliam Kucharski menu_cmds[MODULE_DOLLAR_CMD]) == 0) {
107144da779fSWilliam Kucharski if (strstr(lp->arg, "boot_archive") == NULL) {
1072*23a1cceaSRoger A. Faulkner module = strdupa(lp->arg);
107344da779fSWilliam Kucharski cvt_hyper_module(module, &kern_path);
107444da779fSWilliam Kucharski } else {
1075*23a1cceaSRoger A. Faulkner barchive_path = strdupa(lp->arg);
107644da779fSWilliam Kucharski }
107744da779fSWilliam Kucharski } else if ((strcmp(lp->cmd,
107844da779fSWilliam Kucharski menu_cmds[KERNEL_DOLLAR_CMD]) == 0) &&
107944da779fSWilliam Kucharski (cvt_hyper_kernel(lp->arg) < 0)) {
108044da779fSWilliam Kucharski ret = BAM_NOCHANGE;
108144da779fSWilliam Kucharski goto abort;
108244da779fSWilliam Kucharski }
1083eac223ccSWilliam Kucharski }
108444da779fSWilliam Kucharski
108544da779fSWilliam Kucharski if (lp == ent->end)
108644da779fSWilliam Kucharski break;
108744da779fSWilliam Kucharski }
108844da779fSWilliam Kucharski
108944da779fSWilliam Kucharski /*
1090772d6a58SWilliam Kucharski * If findroot, module or kern_path are NULL, the boot entry is
1091772d6a58SWilliam Kucharski * malformed.
109244da779fSWilliam Kucharski */
109344da779fSWilliam Kucharski if (findroot == NULL) {
109444da779fSWilliam Kucharski bam_error(FINDROOT_NOT_FOUND, curdef);
109544da779fSWilliam Kucharski goto abort;
109644da779fSWilliam Kucharski }
109744da779fSWilliam Kucharski
109844da779fSWilliam Kucharski if (module == NULL) {
109944da779fSWilliam Kucharski bam_error(MODULE_NOT_PARSEABLE, curdef);
110044da779fSWilliam Kucharski goto abort;
110144da779fSWilliam Kucharski }
110244da779fSWilliam Kucharski
110344da779fSWilliam Kucharski if (kern_path == NULL) {
110444da779fSWilliam Kucharski bam_error(KERNEL_NOT_FOUND, curdef);
110544da779fSWilliam Kucharski goto abort;
110644da779fSWilliam Kucharski }
110744da779fSWilliam Kucharski
110844da779fSWilliam Kucharski /*
110944da779fSWilliam Kucharski * Assemble new kernel and module arguments from parsed values.
111044da779fSWilliam Kucharski *
111144da779fSWilliam Kucharski * First, change the kernel directory from the hypervisor version to
111244da779fSWilliam Kucharski * that needed for a metal kernel.
111344da779fSWilliam Kucharski */
111466b6aef6SWilliam Kucharski newstr = modify_path(kern_path, HYPER_KERNEL_DIR, METAL_KERNEL_DIR);
111566b6aef6SWilliam Kucharski free(kern_path);
111666b6aef6SWilliam Kucharski kern_path = newstr;
111744da779fSWilliam Kucharski
111844da779fSWilliam Kucharski /* allocate initial space for the kernel path */
111944da779fSWilliam Kucharski len = strlen(kern_path) + 1;
112044da779fSWilliam Kucharski zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0);
112144da779fSWilliam Kucharski
112244da779fSWilliam Kucharski if ((kernel = malloc(len + zfslen)) == NULL) {
112344da779fSWilliam Kucharski free(kern_path);
112466b6aef6SWilliam Kucharski bam_error(NO_MEM, len + zfslen);
112566b6aef6SWilliam Kucharski bam_exit(1);
112644da779fSWilliam Kucharski }
112744da779fSWilliam Kucharski
112844da779fSWilliam Kucharski (void) snprintf(kernel, len, "%s", kern_path);
112944da779fSWilliam Kucharski free(kern_path);
113044da779fSWilliam Kucharski
113144da779fSWilliam Kucharski if (zfs_boot) {
113244da779fSWilliam Kucharski char *zfsstr = alloca(zfslen + 1);
113344da779fSWilliam Kucharski
113444da779fSWilliam Kucharski (void) snprintf(zfsstr, zfslen + 1, " %s", ZFS_BOOT);
113544da779fSWilliam Kucharski (void) strcat(kernel, zfsstr);
113644da779fSWilliam Kucharski emit_bflag = 0;
113744da779fSWilliam Kucharski }
113844da779fSWilliam Kucharski
1139772d6a58SWilliam Kucharski /*
1140772d6a58SWilliam Kucharski * Process the bootenv.rc file to look for boot options that would be
1141772d6a58SWilliam Kucharski * the same as what the hypervisor had manually set, as we need not set
1142772d6a58SWilliam Kucharski * those explicitly.
1143772d6a58SWilliam Kucharski *
1144772d6a58SWilliam Kucharski * If there's no bootenv.rc, it's not an issue.
1145772d6a58SWilliam Kucharski */
1146772d6a58SWilliam Kucharski parse_bootenvrc(osroot);
1147772d6a58SWilliam Kucharski
1148772d6a58SWilliam Kucharski /*
1149772d6a58SWilliam Kucharski * Don't emit a console setting if it's the same as what would be
1150772d6a58SWilliam Kucharski * set by bootenv.rc.
1151772d6a58SWilliam Kucharski */
1152772d6a58SWilliam Kucharski if ((console_dev != NULL) && (bootenv_rc_console == NULL ||
1153772d6a58SWilliam Kucharski (strcmp(console_dev, bootenv_rc_console) != 0))) {
115444da779fSWilliam Kucharski if (emit_bflag) {
115566b6aef6SWilliam Kucharski newstr = append_str(kernel, BFLAG, " ");
115666b6aef6SWilliam Kucharski free(kernel);
1157772d6a58SWilliam Kucharski kernel = append_str(newstr, "console=", " ");
115866b6aef6SWilliam Kucharski free(newstr);
1159772d6a58SWilliam Kucharski newstr = append_str(kernel, console_dev, "");
116066b6aef6SWilliam Kucharski free(kernel);
116166b6aef6SWilliam Kucharski kernel = newstr;
1162772d6a58SWilliam Kucharski emit_bflag = 0;
1163772d6a58SWilliam Kucharski } else {
1164772d6a58SWilliam Kucharski newstr = append_str(kernel, "console=", ",");
1165772d6a58SWilliam Kucharski free(kernel);
1166772d6a58SWilliam Kucharski kernel = append_str(newstr, console_dev, "");
1167772d6a58SWilliam Kucharski free(newstr);
116844da779fSWilliam Kucharski }
116944da779fSWilliam Kucharski }
117044da779fSWilliam Kucharski
117144da779fSWilliam Kucharski /*
1172772d6a58SWilliam Kucharski * We have to do some strange processing here because the hypervisor's
1173772d6a58SWilliam Kucharski * serial ports default to "9600,8,n,1,-" if "comX=auto" is specified,
1174772d6a58SWilliam Kucharski * or to "auto" if nothing is specified.
117544da779fSWilliam Kucharski *
1176772d6a58SWilliam Kucharski * This could result in a serial mode setting string being added when
1177772d6a58SWilliam Kucharski * it would otherwise not be needed, but it's better to play it safe.
117844da779fSWilliam Kucharski */
117944da779fSWilliam Kucharski if (emit_bflag) {
118066b6aef6SWilliam Kucharski newstr = append_str(kernel, BFLAG, " ");
118166b6aef6SWilliam Kucharski free(kernel);
118266b6aef6SWilliam Kucharski kernel = newstr;
118344da779fSWilliam Kucharski delim = " ";
118444da779fSWilliam Kucharski emit_bflag = 0;
118544da779fSWilliam Kucharski }
118644da779fSWilliam Kucharski
1187772d6a58SWilliam Kucharski if ((serial_config[0] != NULL) && (bootenv_rc_serial[0] == NULL ||
1188772d6a58SWilliam Kucharski (strcmp(serial_config[0], bootenv_rc_serial[0]) != 0))) {
1189772d6a58SWilliam Kucharski newstr = append_str(kernel, "ttya-mode='", delim);
119066b6aef6SWilliam Kucharski free(kernel);
119144da779fSWilliam Kucharski
1192772d6a58SWilliam Kucharski /*
1193772d6a58SWilliam Kucharski * Pass the serial configuration as the delimiter to
1194772d6a58SWilliam Kucharski * append_str() as it will be inserted between the current
1195772d6a58SWilliam Kucharski * string and the string we're appending, in this case the
1196772d6a58SWilliam Kucharski * closing single quote.
1197772d6a58SWilliam Kucharski */
1198772d6a58SWilliam Kucharski kernel = append_str(newstr, "'", serial_config[0]);
119966b6aef6SWilliam Kucharski free(newstr);
1200772d6a58SWilliam Kucharski delim = ",";
1201772d6a58SWilliam Kucharski }
1202772d6a58SWilliam Kucharski
1203772d6a58SWilliam Kucharski if ((serial_config[1] != NULL) && (bootenv_rc_serial[1] == NULL ||
1204772d6a58SWilliam Kucharski (strcmp(serial_config[1], bootenv_rc_serial[1]) != 0))) {
1205772d6a58SWilliam Kucharski newstr = append_str(kernel, "ttyb-mode='", delim);
1206772d6a58SWilliam Kucharski free(kernel);
1207772d6a58SWilliam Kucharski
1208772d6a58SWilliam Kucharski /*
1209772d6a58SWilliam Kucharski * Pass the serial configuration as the delimiter to
1210772d6a58SWilliam Kucharski * append_str() as it will be inserted between the current
1211772d6a58SWilliam Kucharski * string and the string we're appending, in this case the
1212772d6a58SWilliam Kucharski * closing single quote.
1213772d6a58SWilliam Kucharski */
1214772d6a58SWilliam Kucharski kernel = append_str(newstr, "'", serial_config[1]);
1215772d6a58SWilliam Kucharski free(newstr);
1216772d6a58SWilliam Kucharski delim = ",";
1217772d6a58SWilliam Kucharski }
121844da779fSWilliam Kucharski
121944da779fSWilliam Kucharski /* shut off warning messages from the entry line parser */
122044da779fSWilliam Kucharski if (ent->flags & BAM_ENTRY_BOOTADM)
122144da779fSWilliam Kucharski ent->flags &= ~BAM_ENTRY_BOOTADM;
122244da779fSWilliam Kucharski
122344da779fSWilliam Kucharski BAM_DPRINTF((D_CVT_CMD_KERN_DOLLAR, fcn, kernel));
122444da779fSWilliam Kucharski BAM_DPRINTF((D_CVT_CMD_MOD_DOLLAR, fcn, module));
122544da779fSWilliam Kucharski
1226772d6a58SWilliam Kucharski if ((newdef = add_boot_entry(mp, title, findroot, kernel, NULL,
1227772d6a58SWilliam Kucharski barchive_path, bootfs)) == BAM_ERROR) {
1228772d6a58SWilliam Kucharski free(kernel);
1229772d6a58SWilliam Kucharski return (newdef);
1230772d6a58SWilliam Kucharski }
1231772d6a58SWilliam Kucharski
123244da779fSWilliam Kucharski /*
123344da779fSWilliam Kucharski * Now try to delete the current default entry from the menu and add
123444da779fSWilliam Kucharski * the new hypervisor entry with the parameters we've setup.
123544da779fSWilliam Kucharski */
1236772d6a58SWilliam Kucharski if (delete_boot_entry(mp, curdef, DBE_QUIET) == BAM_SUCCESS)
1237772d6a58SWilliam Kucharski newdef--;
1238772d6a58SWilliam Kucharski else
123944da779fSWilliam Kucharski bam_print(NEW_BOOT_ENTRY, title);
124044da779fSWilliam Kucharski
1241772d6a58SWilliam Kucharski free(kernel);
124244da779fSWilliam Kucharski
124344da779fSWilliam Kucharski /*
124444da779fSWilliam Kucharski * If we successfully created the new entry, set the default boot
124544da779fSWilliam Kucharski * entry to that entry and let the caller know the new menu should
124644da779fSWilliam Kucharski * be written out.
124744da779fSWilliam Kucharski */
1248772d6a58SWilliam Kucharski return (set_global(mp, menu_cmds[DEFAULT_CMD], newdef));
124944da779fSWilliam Kucharski
125044da779fSWilliam Kucharski abort:
125144da779fSWilliam Kucharski if (ret != BAM_NOCHANGE)
125244da779fSWilliam Kucharski bam_error(METAL_ABORT, osroot);
125344da779fSWilliam Kucharski
125444da779fSWilliam Kucharski return (ret);
125544da779fSWilliam Kucharski }
1256