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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * I18N message number ranges 28 * This file: 6000 - 6499 29 * Shared common messages: 1 - 1999 30 */ 31 32 33 34 #include <stdio.h> 35 #include <unistd.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <sys/param.h> 41 #include <sys/mnttab.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <sys/openpromio.h> 45 46 47 /* 48 * For i18n 49 */ 50 #include <stgcom.h> 51 52 53 /* 54 * 128 is the size of the largest (currently) property name 55 * 8192 - MAXPROPSIZE - sizeof (int) is the size of the largest 56 * (currently) property value, viz. nvramrc. 57 * the sizeof(uint_t) is from struct openpromio 58 */ 59 #define MAXPROPSIZE 128 60 #define MAXVALSIZE (8192 - MAXPROPSIZE - sizeof (uint_t)) 61 62 #define BOOTDEV_PROP_NAME "boot-device" 63 64 static int getbootdevname(char *, char *); 65 static int setprom(unsigned, unsigned, char *); 66 extern int devfs_dev_to_prom_name(char *, char *); 67 68 /* 69 * Call getbootdevname() to get the absolute pathname of boot device 70 * and call setprom() to set the boot-device variable. 71 */ 72 int 73 setboot(unsigned int yes, unsigned int verbose, char *fname) 74 { 75 char bdev[MAXPATHLEN]; 76 77 if (!getbootdevname(fname, bdev)) { 78 (void) fprintf(stderr, MSGSTR(6000, 79 "Cannot determine device name for %s\n"), 80 fname); 81 return (errno); 82 } 83 84 return (setprom(yes, verbose, bdev)); 85 } 86 87 /* 88 * Read the mnttab and resolve the special device of the fs we are 89 * interested in, into an absolute pathname 90 */ 91 static int 92 getbootdevname(char *bootfs, char *bdev) 93 { 94 FILE *f; 95 char *fname; 96 char *devname; 97 struct mnttab m; 98 struct stat sbuf; 99 int mountpt = 0; 100 int found = 0; 101 102 devname = bootfs; 103 104 if (stat(bootfs, &sbuf) < 0) { 105 perror(MSGSTR(6001, "stat")); 106 return (0); 107 } 108 109 switch (sbuf.st_mode & S_IFMT) { 110 case S_IFBLK: 111 break; 112 default: 113 mountpt = 1; 114 break; 115 } 116 117 if (mountpt) { 118 fname = MNTTAB; 119 f = fopen(fname, "r"); 120 if (f == NULL) { 121 perror(fname); 122 return (0); 123 } 124 125 while (getmntent(f, &m) == 0) { 126 if (strcmp(m.mnt_mountp, bootfs)) 127 continue; 128 else { 129 found = 1; 130 break; 131 } 132 } 133 134 (void) fclose(f); 135 136 if (!found) { 137 return (0); 138 } 139 devname = m.mnt_special; 140 } 141 142 if (devfs_dev_to_prom_name(devname, bdev) != 0) { 143 perror(devname); 144 return (0); 145 } 146 147 return (1); 148 } 149 150 /* 151 * setprom() - use /dev/openprom to read the "boot_device" variable and set 152 * it to the new value. 153 */ 154 static int 155 setprom(unsigned yes, unsigned verbose, char *bdev) 156 { 157 struct openpromio *pio; 158 int fd; 159 char save_bootdev[MAXVALSIZE]; 160 161 if ((fd = open("/dev/openprom", O_RDWR)) < 0) { 162 perror(MSGSTR(6002, "Could not open openprom dev")); 163 return (errno); 164 } 165 166 pio = (struct openpromio *)malloc(sizeof (struct openpromio) + 167 MAXVALSIZE + MAXPROPSIZE); 168 169 if (pio == (struct openpromio *)NULL) { 170 perror(MSGSTR(6003, " Error: Unable to allocate memory.")); 171 return (errno); 172 } 173 174 pio->oprom_size = MAXVALSIZE; 175 (void) strcpy(pio->oprom_array, BOOTDEV_PROP_NAME); 176 177 if (ioctl(fd, OPROMGETOPT, pio) < 0) { 178 perror(MSGSTR(6004, "openprom getopt ioctl")); 179 return (errno); 180 } 181 182 /* 183 * save the existing boot-device, so we can use it if setting 184 * to new value fails. 185 */ 186 (void) strcpy(save_bootdev, pio->oprom_array); 187 188 if (verbose) { 189 (void) fprintf(stdout, 190 MSGSTR(6005, 191 "Current boot-device = %s\n"), pio->oprom_array); 192 (void) fprintf(stdout, MSGSTR(6006, 193 "New boot-device = %s\n"), bdev); 194 } 195 196 if (!yes) { 197 (void) fprintf(stdout, MSGSTR(6007, 198 "Do you want to change boot-device " 199 "to the new setting? (y/n) ")); 200 switch (getchar()) { 201 case 'Y': 202 case 'y': 203 break; 204 default: 205 return (0); 206 } 207 } 208 209 /* set the new value for boot-device */ 210 211 pio->oprom_size = (int)strlen(BOOTDEV_PROP_NAME) + 1 + 212 (int)strlen(bdev); 213 214 (void) strcpy(pio->oprom_array, BOOTDEV_PROP_NAME); 215 (void) strcpy(pio->oprom_array + (int)strlen(BOOTDEV_PROP_NAME) + 1, 216 bdev); 217 218 if (ioctl(fd, OPROMSETOPT, pio) < 0) { 219 perror(MSGSTR(6008, "openprom setopt ioctl")); 220 return (errno); 221 } 222 223 /* read back the value that was set */ 224 225 pio->oprom_size = MAXVALSIZE; 226 (void) strcpy(pio->oprom_array, BOOTDEV_PROP_NAME); 227 228 if (ioctl(fd, OPROMGETOPT, pio) < 0) { 229 perror(MSGSTR(6009, "openprom getopt ioctl")); 230 return (errno); 231 } 232 233 if (strcmp(bdev, pio->oprom_array)) { 234 235 /* could not set the new device name, set the old one back */ 236 237 perror(MSGSTR(6010, 238 "Could not set boot-device, reverting to old value")); 239 pio->oprom_size = (int)strlen(BOOTDEV_PROP_NAME) + 1 + 240 (int)strlen(save_bootdev); 241 242 (void) strcpy(pio->oprom_array, BOOTDEV_PROP_NAME); 243 (void) strcpy(pio->oprom_array + 244 (int)strlen(BOOTDEV_PROP_NAME) + 1, 245 save_bootdev); 246 247 if (ioctl(fd, OPROMSETOPT, pio) < 0) { 248 perror(MSGSTR(6011, "openprom setopt ioctl")); 249 return (errno); 250 } 251 252 } 253 254 (void) close(fd); 255 256 return (0); 257 } 258