1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains all the functions that get/set fields 28 * in a GRUB menu entry. 29 */ 30 #include <stdio.h> 31 #include <errno.h> 32 #include <stdlib.h> 33 #include <strings.h> 34 #include <unistd.h> 35 #include <sys/types.h> 36 #include <assert.h> 37 #include <ctype.h> 38 39 #include "libgrub_cmd.def" 40 #include "libgrub_impl.h" 41 42 typedef int (*barg_parsef_t)(const grub_line_t *, grub_barg_t *); 43 static const barg_parsef_t barg_parse[] = { 44 #define menu_cmd(cmd, num, flag, parsef) parsef, 45 #include "libgrub_cmd.def" 46 }; 47 48 /* 49 * Remove extra '/', stops at first isspace character. 50 * Return new string length. 51 */ 52 size_t 53 clean_path(char *path) 54 { 55 int i, c; 56 size_t k, n; 57 58 n = strlen(path) + 1; 59 60 for (i = 0; (c = path[i]) != 0 && !isspace(c); i++) { 61 if (c == '/' && (k = strspn(path + i, "/") - 1) != 0) { 62 /* bcopy should deal with overlapping buffers */ 63 n -= k; 64 bcopy(path + i + k, path + i, n - i); 65 } 66 } 67 return (n - 1); 68 } 69 70 /* 71 * Construct boot command line from the ge_barg field 72 */ 73 static size_t 74 barg_cmdline(const grub_barg_t *barg, char *cmd, size_t size) 75 { 76 size_t n; 77 const grub_fsdesc_t *fsd; 78 79 if (!IS_BARG_VALID(barg) || 80 (fsd = grub_get_rootfsd(&barg->gb_root)) == NULL) 81 return ((size_t)-1); 82 83 /* if disk/top dataset is mounted, use mount point */ 84 if (fsd->gfs_mountp[0] != 0) { 85 if ((n = snprintf(cmd, size, "%s%s", fsd->gfs_mountp, 86 barg->gb_kernel)) >= size) 87 return (n); 88 return (clean_path(cmd)); 89 } else 90 return (snprintf(cmd, size, "%s %s", fsd->gfs_dev, 91 barg->gb_kernel)); 92 } 93 94 95 /* 96 * Construct ge_barg field based on the other fields of the entry. 97 * Return 0 on success, errno on failure. 98 */ 99 int 100 grub_entry_construct_barg(grub_entry_t *ent) 101 { 102 int ret = 0; 103 grub_barg_t *barg; 104 grub_line_t *lp, *lend; 105 grub_menu_t *mp; 106 107 assert(ent); 108 109 barg = &ent->ge_barg; 110 mp = ent->ge_menu; 111 112 assert(barg); 113 assert(mp); 114 115 (void) memset(barg, 0, sizeof (*barg)); 116 barg->gb_entry = ent; 117 (void) bcopy(&mp->gm_root, &barg->gb_root, sizeof (barg->gb_root)); 118 119 lend = ent->ge_end->gl_next; 120 for (lp = ent->ge_start; lp != lend; lp = lp->gl_next) { 121 if (lp->gl_cmdtp >= GRBM_CMD_NUM) 122 ret = EG_INVALIDCMD; 123 else 124 ret = barg_parse[lp->gl_cmdtp](lp, barg); 125 126 if (ret != 0) 127 break; 128 } 129 130 barg->gb_errline = lp; 131 if (ret == 0) { 132 /* at least kernel and module should be defined */ 133 if (barg->gb_kernel[0] != 0 && barg->gb_module[0] != 0) 134 barg->gb_flags |= GRBM_VALID_FLAG; 135 } 136 137 return (ret); 138 } 139 140 const char * 141 grub_entry_get_fstyp(const grub_entry_t *ent) 142 { 143 if (IS_ENTRY_BARG_VALID(ent)) 144 return (ent->ge_barg.gb_root.gr_fstyp); 145 else 146 return (NULL); 147 } 148 149 const char * 150 grub_entry_get_kernel(const grub_entry_t *ent) 151 { 152 if (IS_ENTRY_BARG_VALID(ent)) 153 return (ent->ge_barg.gb_kernel); 154 else 155 return (NULL); 156 } 157 158 const char * 159 grub_entry_get_module(const grub_entry_t *ent) 160 { 161 if (IS_ENTRY_BARG_VALID(ent)) 162 return (ent->ge_barg.gb_module); 163 else 164 return (NULL); 165 } 166 167 const char * 168 grub_entry_get_error_desc(const grub_entry_t *ent) 169 { 170 assert(ent != NULL); 171 return ("Not implemented"); 172 } 173 174 const grub_fsdesc_t * 175 grub_entry_get_rootfs(const grub_entry_t *ent) 176 { 177 if (IS_ENTRY_BARG_VALID(ent)) 178 return (grub_get_rootfsd(&ent->ge_barg.gb_root)); 179 else 180 return (NULL); 181 } 182 183 size_t 184 grub_entry_get_cmdline(grub_entry_t *ent, char *cmdline, size_t size) 185 { 186 if (IS_ENTRY_VALID(ent) && (grub_entry_construct_barg(ent) == 0)) 187 return (barg_cmdline(&ent->ge_barg, cmdline, size)); 188 else 189 return ((size_t)-1); 190 191 } 192