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