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