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