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 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 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 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 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 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 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 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