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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Creates and maintains a short-term cache of live upgrade slices.
29 */
30
31 #include <dirent.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <synch.h>
36 #include <sys/errno.h>
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/wait.h>
43
44 #include "libdiskmgt.h"
45 #include "disks_private.h"
46
47 #define TMPNM_SIZE 25
48
49 /*
50 * The list of live upgrade slices in use.
51 */
52
53 struct lu_list {
54 struct lu_list *next;
55 char *slice;
56 char *name;
57 };
58
59 static struct lu_list *lu_listp = NULL;
60 static time_t timestamp = 0;
61 static mutex_t lu_lock = DEFAULTMUTEX;
62
63 static int add_use_record(char *devname, char *name);
64 static void free_lu(struct lu_list *listp);
65 static int load_lu();
66 static int lustatus(int fd);
67 static int lufslist(int fd);
68 static int run_cmd(char *path, char *cmd, char *arg, int fd);
69
70 /*
71 * Search the list of devices under live upgrade for the specified device.
72 */
73 int
inuse_lu(char * slice,nvlist_t * attrs,int * errp)74 inuse_lu(char *slice, nvlist_t *attrs, int *errp)
75 {
76 int found = 0;
77 time_t curr_time;
78
79 *errp = 0;
80
81 if (slice == NULL) {
82 return (found);
83 }
84
85 /*
86 * We don't want to have to re-read the live upgrade config for
87 * every slice, but we can't just cache it since there is no event
88 * when this changes. So, we'll keep the config in memory for
89 * a short time (1 minute) before reloading it.
90 */
91 (void) mutex_lock(&lu_lock);
92
93 curr_time = time(NULL);
94 if (timestamp < curr_time && (curr_time - timestamp) > 60) {
95 free_lu(lu_listp); /* free old entries */
96 lu_listp = NULL;
97 *errp = load_lu(); /* load the cache */
98 timestamp = curr_time;
99 }
100
101 if (*errp == 0) {
102 struct lu_list *listp;
103
104 listp = lu_listp;
105 while (listp != NULL) {
106 if (strcmp(slice, listp->slice) == 0) {
107 libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_LU, errp);
108 libdiskmgt_add_str(attrs, DM_USED_NAME, listp->name, errp);
109 found = 1;
110 break;
111 }
112 listp = listp->next;
113 }
114 }
115
116 (void) mutex_unlock(&lu_lock);
117
118 return (found);
119 }
120
121 static int
add_use_record(char * devname,char * name)122 add_use_record(char *devname, char *name)
123 {
124 struct lu_list *sp;
125
126 sp = (struct lu_list *)malloc(sizeof (struct lu_list));
127 if (sp == NULL) {
128 return (ENOMEM);
129 }
130
131 if ((sp->slice = strdup(devname)) == NULL) {
132 free(sp);
133 return (ENOMEM);
134 }
135
136 if ((sp->name = strdup(name)) == NULL) {
137 free(sp->slice);
138 free(sp);
139 return (ENOMEM);
140 }
141
142 sp->next = lu_listp;
143 lu_listp = sp;
144
145 return (0);
146 }
147
148 /*
149 * Free the list of liveupgrade entries.
150 */
151 static void
free_lu(struct lu_list * listp)152 free_lu(struct lu_list *listp) {
153
154 struct lu_list *nextp;
155
156 while (listp != NULL) {
157 nextp = listp->next;
158 free((void *)listp->slice);
159 free((void *)listp->name);
160 free((void *)listp);
161 listp = nextp;
162 }
163 }
164
165 /*
166 * Create a list of live upgrade devices.
167 */
168 static int
load_lu()169 load_lu()
170 {
171 char tmpname[TMPNM_SIZE];
172 int fd;
173 int status = 0;
174
175 (void) strlcpy(tmpname, "/var/run/dm_lu_XXXXXX", TMPNM_SIZE);
176 if ((fd = mkstemp(tmpname)) != -1) {
177 (void) unlink(tmpname);
178 if (run_cmd("/usr/sbin/lustatus", "lustatus", NULL, fd)) {
179 status = lustatus(fd);
180 } else {
181 (void) close(fd);
182 }
183 }
184
185 return (status);
186 }
187
188 /*
189 * The XML generated by the live upgrade commands is not parseable by the
190 * standard Solaris XML parser, so we have to do it ourselves.
191 */
192 static int
lufslist(int fd)193 lufslist(int fd)
194 {
195 FILE *fp;
196 char line[MAXPATHLEN];
197 int status;
198
199 if ((fp = fdopen(fd, "r")) == NULL) {
200 (void) close(fd);
201 return (0);
202 }
203
204 (void) fseek(fp, 0L, SEEK_SET);
205 while (fgets(line, sizeof (line), fp) == line) {
206 char *devp;
207 char *nmp;
208 char *ep;
209
210 if (strncmp(line, "<beFsComponent ", 15) != 0) {
211 continue;
212 }
213
214 if ((devp = strstr(line, "fsDevice=\"")) == NULL) {
215 continue;
216 }
217
218 devp = devp + 10;
219
220 if ((ep = strchr(devp, '"')) == NULL) {
221 continue;
222 }
223
224 *ep = 0;
225
226 /* try to get the mountpoint name */
227 if ((nmp = strstr(ep + 1, "mountPoint=\"")) != NULL) {
228 nmp = nmp + 12;
229
230 if ((ep = strchr(nmp, '"')) != NULL) {
231 *ep = 0;
232 } else {
233 nmp = "";
234 }
235
236 } else {
237 nmp = "";
238 }
239
240 if ((status = add_use_record(devp, nmp)) != 0) {
241 break;
242 }
243 }
244
245 (void) fclose(fp);
246
247 return (status);
248 }
249
250 static int
lustatus(int fd)251 lustatus(int fd)
252 {
253 FILE *fp;
254 char line[MAXPATHLEN];
255 int status = 0;
256
257 if ((fp = fdopen(fd, "r")) == NULL) {
258 (void) close(fd);
259 return (0);
260 }
261
262 (void) fseek(fp, 0L, SEEK_SET);
263 while (fgets(line, sizeof (line), fp) == line) {
264 char *sp;
265 char *ep;
266 char tmpname[TMPNM_SIZE];
267 int ffd;
268
269 if (strncmp(line, "<beStatus ", 10) != 0) {
270 continue;
271 }
272
273 if ((sp = strstr(line, "name=\"")) == NULL) {
274 continue;
275 }
276
277 sp = sp + 6;
278
279 if ((ep = strchr(sp, '"')) == NULL) {
280 continue;
281 }
282
283 *ep = 0;
284
285 (void) strlcpy(tmpname, "/var/run/dm_lu_XXXXXX", TMPNM_SIZE);
286 if ((ffd = mkstemp(tmpname)) != -1) {
287 (void) unlink(tmpname);
288
289 if (run_cmd("/usr/sbin/lufslist", "lufslist", sp, ffd) == 0) {
290 (void) close(ffd);
291 break;
292 }
293
294 if ((status = lufslist(ffd)) != 0) {
295 break;
296 }
297 }
298 }
299
300 (void) fclose(fp);
301
302 return (status);
303 }
304
305 static int
run_cmd(char * path,char * cmd,char * arg,int fd)306 run_cmd(char *path, char *cmd, char *arg, int fd)
307 {
308 pid_t pid;
309 int loc;
310
311 /* create the server process */
312 switch ((pid = fork1())) {
313 case 0:
314 /* child process */
315 (void) close(1);
316 (void) dup(fd);
317 (void) close(2);
318 (void) dup(fd);
319 closefrom(3);
320 (void) execl(path, cmd, "-X", arg, NULL);
321 _exit(1);
322 break;
323
324 case -1:
325 return (0);
326
327 default:
328 /* parent process */
329 break;
330 }
331
332 (void) waitpid(pid, &loc, 0);
333
334 /* printf("got 0x%x %d %d\n", loc, WIFEXITED(loc), WEXITSTATUS(loc)); */
335
336 if (WIFEXITED(loc) && WEXITSTATUS(loc) == 0) {
337 return (1);
338 }
339
340 return (0);
341 }
342