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