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
setboot(unsigned int yes,unsigned int verbose,char * fname)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
getbootdevname(char * bootfs,char * bdev)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
setprom(unsigned yes,unsigned verbose,char * bdev)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