xref: /illumos-gate/usr/src/cmd/luxadm/setboot.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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