changeset 10787:9fffdd17fec8

6890353 bootadm hypervisor enabling/disabling commands have issues
author William Kucharski <William.Kucharski@Sun.COM>
date Tue, 13 Oct 2009 16:03:16 -0600
parents 85c502c72ce8
children 9742ae62f8f2
files usr/src/cmd/boot/bootadm/bootadm.c usr/src/cmd/boot/bootadm/bootadm.h usr/src/cmd/boot/bootadm/bootadm_hyper.c usr/src/cmd/boot/bootadm/message.h
diffstat 4 files changed, 123 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/boot/bootadm/bootadm.c	Tue Oct 13 17:32:06 2009 -0400
+++ b/usr/src/cmd/boot/bootadm/bootadm.c	Tue Oct 13 16:03:16 2009 -0600
@@ -253,7 +253,6 @@
 static error_t bam_menu(char *, char *, int, char *[]);
 static error_t bam_archive(char *, char *);
 
-static void bam_exit(int);
 static void bam_lock(void);
 static void bam_unlock(void);
 
@@ -1324,7 +1323,7 @@
 	va_end(ap);
 }
 
-static void
+void
 bam_exit(int excode)
 {
 	restore_env();
--- a/usr/src/cmd/boot/bootadm/bootadm.h	Tue Oct 13 17:32:06 2009 -0400
+++ b/usr/src/cmd/boot/bootadm/bootadm.h	Tue Oct 13 16:03:16 2009 -0600
@@ -167,6 +167,7 @@
 extern void *s_realloc(void *, size_t);
 extern char *s_fgets(char *buf, int n, FILE *fp);
 extern void bam_error(char *format, ...);
+extern void bam_exit(int);
 extern void bam_print(char *, ...);
 extern void bam_print_stderr(char *format, ...);
 extern void bam_derror(char *format, ...);
--- a/usr/src/cmd/boot/bootadm/bootadm_hyper.c	Tue Oct 13 17:32:06 2009 -0400
+++ b/usr/src/cmd/boot/bootadm/bootadm_hyper.c	Tue Oct 13 16:03:16 2009 -0600
@@ -59,8 +59,7 @@
  * Append the string pointed to by "str" to the string pointed to by "orig"
  * adding the delimeter "delim" in between.
  *
- * Return a pointer to the new string or NULL, if we were passed a bad string
- * or we couldn't allocate memory for the new one.
+ * Return a pointer to the new string or NULL, if we were passed a bad string.
  */
 static char *
 append_str(char *orig, char *str, char *delim)
@@ -68,57 +67,63 @@
 	char *newstr;
 	int len;
 
-	if ((orig == NULL) || (str == NULL) || (delim == NULL))
+	if ((str == NULL) || (delim == NULL))
 		return (NULL);
 
-	if (*orig == NULL)
+	if ((orig == NULL) || (*orig == NULL)) {
+		/*
+		 * Return a pointer to a copy of the path so a caller can
+		 * always rely upon being able to free() a returned pointer.
+		 */
 		return (s_strdup(str));
+	}
 
 	len = strlen(orig) + strlen(str) + strlen(delim) + 1;
-	newstr = s_realloc(orig, len);
+	if ((newstr = malloc(len)) == NULL) {
+		bam_error(NO_MEM, len);
+		bam_exit(1);
+	}
 
-	if (newstr != NULL)
-		(void) snprintf(newstr, len, "%s%s%s", orig, delim, str);
-
+	(void) snprintf(newstr, len, "%s%s%s", orig, delim, str);
 	return (newstr);
 }
 
 /*
  * Replace the substring "old_str" in a path with the substring "new_str"
  *
- * Return a pointer to the  modified string or NULL, if we couldn't allocate
- * memory for the new string.
+ * Return a pointer to the modified string.
  */
 static char *
 modify_path(char *path, char *old_str, char *new_str)
 {
 	char *newpath;
-	char *oldpath;
 	char *pc;
-
-	oldpath = s_strdup(path);
+	int len;
 
-	if ((pc = strstr(oldpath, old_str)) == NULL) {
-		free(oldpath);
-		return (path);
-	}
+	/*
+	 * Return a pointer to a copy of the path so a caller can always rely
+	 * upon being able to free() a returned pointer.
+	 */
+	if ((pc = strstr(path, old_str)) == NULL)
+		return (s_strdup(path));
 
 	/*
 	 * Allocate space for duplicate of path with name changes and
 	 * NULL terminating byte
 	 */
-	if ((newpath = s_realloc(path,
-	    strlen(oldpath) - strlen(old_str) + strlen(new_str) + 1)) == NULL) {
-		free(oldpath);
-		return (NULL);
+	len = strlen(path) - strlen(old_str) + strlen(new_str) + 1;
+
+	if ((newpath = malloc(len)) == NULL) {
+		bam_error(NO_MEM, len);
+		bam_exit(1);
 	}
 
-	(void) strlcpy(newpath, oldpath, (pc - oldpath) + 1);
-	free(oldpath);
+	(void) strlcpy(newpath, path, (pc - path) + 1);
+	pc += strlen(old_str);
 
 	(void) strcat(newpath, new_str);
-	pc += strlen(old_str);
-	return (strcat(newpath, pc));
+	(void) strcat(newpath, pc);
+	return (newpath);
 }
 
 /*
@@ -165,7 +170,7 @@
 			/* found a delimiter, so create a token string */
 			if ((*token = malloc(len)) == NULL) {
 				bam_error(NO_MEM, len);
-				return (NULL);
+				bam_exit(1);
 			}
 
 			(void) strlcpy(*token, start, len);
@@ -219,7 +224,7 @@
 		return (0);
 	}
 
-	*rp = s_realloc(*rp, strlen(rate));
+	*rp = s_realloc(*rp, strlen(rate) + 1);
 	(void) strcpy(*rp, rate);
 	return (0);
 }
@@ -421,7 +426,7 @@
 	    (strncmp(optstr, "ttyb-mode", namlen) == 0)) {
 		char *port = alloca(namlen + 1);
 
-		(void) strlcpy(port, optstr, namlen);
+		(void) strlcpy(port, optstr, namlen + 1);
 		return (serial_metal_to_hyper(port, value));
 	}
 
@@ -577,15 +582,20 @@
  * use to construct an appropriate "module$" line that can be used to specify
  * how to boot the hypervisor's dom0.
  *
- * Return 0 on success, non-zero on failure.
+ * Return values:
+ *
+ *	-1: error parsing kernel path
+ *	 0: success
+ *	 1: kernel already a hypervisor kernel
  */
 static int
 cvt_metal_kernel(char *kernstr, char **path)
 {
 	char *token, *parsestr;
 
-	if ((parsestr = get_token(path, kernstr, " \t,")) == NULL)
-		return (*path == NULL);
+	parsestr = get_token(path, kernstr, " \t,");
+	if (*path == NULL)
+		return (-1);
 
 	/*
 	 * If the metal kernel specified contains the name of the hypervisor,
@@ -594,7 +604,9 @@
 	 */
 	if (strstr(*path, XEN_MENU) != NULL) {
 		bam_error(ALREADY_HYPER);
-		return (-1);
+		free(*path);
+		*path = NULL;
+		return (1);
 	}
 
 	/* if the path was the last item on the line, that's OK. */
@@ -610,6 +622,8 @@
 		return (0);
 	}
 
+	free(token);
+
 	while ((parsestr = get_token(&token, parsestr, ",")) != NULL) {
 		(void) cvt_metal_option(token);
 		free(token);
@@ -634,9 +648,10 @@
 {
 	char *token, *parsestr;
 
-	/* eat the kernel path, which should be the first token */
-	if ((parsestr = get_token(&token, kernel, " \t,")) == NULL)
-		return (0);
+	parsestr = get_token(&token, kernel, " \t,");
+
+	if (token == NULL)
+		return (-1);
 
 	/*
 	 * If the hypervisor kernel specified lives in the metal kernel
@@ -645,11 +660,10 @@
 	 */
 	if (strncmp(token, METAL_KERNEL_DIR, strlen(METAL_KERNEL_DIR)) == 0) {
 		bam_error(ALREADY_METAL);
-		(void) free(token);
+		free(token);
 		return (-1);
 	}
 
-	/* if the path was the last item on the line, that's OK. */
 	free(token);
 
 	/* check for kernel options */
@@ -673,7 +687,7 @@
 static void
 cvt_hyper_module(char *modstr, char **path)
 {
-	char *token;
+	char *token = NULL;
 	char *parsestr = modstr;
 
 	/*
@@ -683,8 +697,8 @@
 	while ((parsestr = get_token(path, parsestr, " \t,")) != NULL) {
 		if (*parsestr != '/')
 			break;
-
-		free(*path);
+		else
+			free(*path);
 	}
 
 	/* if the path was the last item on the line, that's OK. */
@@ -695,12 +709,17 @@
 		return;
 	}
 
+	if (token == NULL)
+		return;
+
 	/* check for "-B" option */
 	if (strncmp(token, BFLAG, strlen(BFLAG)) != 0) {
 		free(token);
 		return;
 	}
 
+	free(token);
+
 	/* check for kernel options */
 	while ((parsestr = get_token(&token, parsestr, ",")) != NULL) {
 		(void) cvt_hyper_option(token);
@@ -727,6 +746,7 @@
 
 	len = strlen(osroot) + strlen(BOOTRC_FILE) + 1;
 	rcpath = alloca(len);
+
 	(void) snprintf(rcpath, len, "%s%s", osroot, BOOTRC_FILE);
 
 	/* if we couldn't open the bootenv.rc file, ignore the issue. */
@@ -755,6 +775,7 @@
 	entry_t *ent;
 	size_t len, zfslen;
 
+	char *newstr;
 	char *osdev;
 
 	char *title = NULL;
@@ -768,7 +789,7 @@
 	char *kern_bargs = NULL;
 
 	int curdef;
-	int kp_allocated = 1;
+	int kp_allocated = 0;
 	int ret = BAM_ERROR;
 
 	assert(osroot);
@@ -841,8 +862,13 @@
 			(void) strcpy(module, lp->arg);
 		} else if ((strcmp(lp->cmd,
 		    menu_cmds[KERNEL_DOLLAR_CMD]) == 0) &&
-		    (cvt_metal_kernel(lp->arg, &kern_path) < 0)) {
-			ret = BAM_NOCHANGE;
+		    (ret = cvt_metal_kernel(lp->arg, &kern_path)) != 0) {
+			if (ret < 0) {
+				ret = BAM_ERROR;
+				bam_error(KERNEL_NOT_PARSEABLE, curdef);
+			} else
+				ret = BAM_NOCHANGE;
+
 			goto abort;
 		}
 
@@ -872,26 +898,35 @@
 	if (console_dev != NULL) {
 		kern_bargs = s_strdup(console_dev);
 
-		if (serial_config[0] != NULL)
-			kern_bargs = append_str(kern_bargs, serial_config[0],
-			    " ");
+		if (serial_config[0] != NULL) {
+			newstr = append_str(kern_bargs, serial_config[0], " ");
+			free(kern_bargs);
+			kern_bargs = newstr;
+		}
 
-		if (serial_config[1] != NULL)
-			kern_bargs = append_str(kern_bargs, serial_config[1],
-			    " ");
+		if (serial_config[1] != NULL) {
+			newstr = append_str(kern_bargs, serial_config[1], " ");
+			free(kern_bargs);
+			kern_bargs = newstr;
+		}
 	}
 
-	if ((extra_args != NULL) && (*extra_args != NULL))
-		kern_bargs = append_str(kern_bargs, extra_args, " ");
+	if ((extra_args != NULL) && (*extra_args != NULL)) {
+		newstr = append_str(kern_bargs, extra_args, " ");
+		free(kern_bargs);
+		kern_bargs = newstr;
+	}
 
 	len = strlen(osroot) + strlen(XEN_MENU) + strlen(kern_bargs) +
 	    WHITESPC(1) + 1;
 
 	kernel = alloca(len);
 
-	if ((kern_bargs != NULL) && (*kern_bargs != NULL)) {
-		(void) snprintf(kernel, len, "%s%s %s", osroot, XEN_MENU,
-		    kern_bargs);
+	if (kern_bargs != NULL) {
+		if (*kern_bargs != NULL)
+			(void) snprintf(kernel, len, "%s%s %s", osroot,
+			    XEN_MENU, kern_bargs);
+
 		free(kern_bargs);
 	} else {
 		(void) snprintf(kernel, len, "%s%s", osroot, XEN_MENU);
@@ -905,10 +940,12 @@
 	if ((strcmp(kern_path, DIRECT_BOOT_32) == 0) ||
 	    (strcmp(kern_path, DIRECT_BOOT_64) == 0)) {
 		kern_path = HYPERVISOR_KERNEL;
-		kp_allocated = 0;
 	} else {
-		kern_path = modify_path(kern_path, METAL_KERNEL_DIR,
+		newstr = modify_path(kern_path, METAL_KERNEL_DIR,
 		    HYPER_KERNEL_DIR);
+		free(kern_path);
+		kern_path = newstr;
+		kp_allocated = 1;
 	}
 
 	/*
@@ -920,7 +957,6 @@
 	zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0);
 
 	mod_kernel = alloca(len + zfslen);
-
 	(void) snprintf(mod_kernel, len, "%s %s", kern_path, kern_path);
 
 	if (kp_allocated)
@@ -961,9 +997,6 @@
 	return (BAM_ERROR);
 
 abort:
-	if ((kp_allocated) && (kern_path != NULL))
-		free(kern_path);
-
 	if (ret != BAM_NOCHANGE)
 		bam_error(HYPER_ABORT, ((*osroot == NULL) ? "/" : osroot));
 
@@ -980,7 +1013,8 @@
 	entry_t *ent;
 	size_t len, zfslen;
 
-	char *delim = ", ";
+	char *delim = ",";
+	char *newstr;
 	char *osdev;
 
 	char *title = NULL;
@@ -1087,7 +1121,9 @@
 	 * First, change the kernel directory from the hypervisor version to
 	 * that needed for a metal kernel.
 	 */
-	kern_path = modify_path(kern_path, HYPER_KERNEL_DIR, METAL_KERNEL_DIR);
+	newstr = modify_path(kern_path, HYPER_KERNEL_DIR, METAL_KERNEL_DIR);
+	free(kern_path);
+	kern_path = newstr;
 
 	/* allocate initial space for the kernel path */
 	len = strlen(kern_path) + 1;
@@ -1095,8 +1131,8 @@
 
 	if ((kernel = malloc(len + zfslen)) == NULL) {
 		free(kern_path);
-		bam_error(NO_MEM, len);
-		goto abort;
+		bam_error(NO_MEM, len + zfslen);
+		bam_exit(1);
 	}
 
 	(void) snprintf(kernel, len, "%s", kern_path);
@@ -1112,11 +1148,15 @@
 
 	if (console_dev != NULL) {
 		if (emit_bflag) {
-			kernel = append_str(kernel, BFLAG, " ");
-			kernel = append_str(kernel, console_dev, " ");
+			newstr = append_str(kernel, BFLAG, " ");
+			free(kernel);
+			kernel = append_str(newstr, console_dev, " ");
+			free(newstr);
 			emit_bflag = 0;
 		} else {
-			kernel = append_str(kernel, console_dev, ", ");
+			newstr = append_str(kernel, console_dev, ",");
+			free(kernel);
+			kernel = newstr;
 		}
 	}
 
@@ -1133,20 +1173,26 @@
 	 */
 
 	if (emit_bflag) {
-		kernel = append_str(kernel, BFLAG, " ");
+		newstr = append_str(kernel, BFLAG, " ");
+		free(kernel);
+		kernel = newstr;
 		delim = " ";
 		emit_bflag = 0;
 	}
 
 	if (serial_config[0] != NULL)
-		kernel = append_str(kernel, serial_config[0], delim);
+		newstr = append_str(kernel, serial_config[0], delim);
 	else
-		kernel = append_str(kernel, "ttya-mode='9600,8,n,1,-'", delim);
+		newstr = append_str(kernel, "ttya-mode='9600,8,n,1,-'", delim);
+
+	free(kernel);
 
 	if (serial_config[1] != NULL)
-		kernel = append_str(kernel, serial_config[1], ", ");
+		kernel = append_str(newstr, serial_config[1], ",");
 	else
-		kernel = append_str(kernel, "ttyb-mode='9600,8,n,1,-'", ", ");
+		kernel = append_str(newstr, "ttyb-mode='9600,8,n,1,-'", ",");
+
+	free(newstr);
 
 	/* shut off warning messages from the entry line parser */
 	if (ent->flags & BAM_ENTRY_BOOTADM)
--- a/usr/src/cmd/boot/bootadm/message.h	Tue Oct 13 17:32:06 2009 -0400
+++ b/usr/src/cmd/boot/bootadm/message.h	Tue Oct 13 16:03:16 2009 -0600
@@ -304,6 +304,9 @@
 #define	KERNEL_NOT_FOUND	\
 gettext("kernel$ in default boot entry (%d) missing.\n")
 
+#define	KERNEL_NOT_PARSEABLE	\
+gettext("kernel$ in default boot entry (%d) missing or not parseable.\n")
+
 #define	MODULE_NOT_PARSEABLE	\
 gettext("module$ in default boot entry (%d) missing or not parseable.\n")