1*108322fbScarlsonj /* 2*108322fbScarlsonj * CDDL HEADER START 3*108322fbScarlsonj * 4*108322fbScarlsonj * The contents of this file are subject to the terms of the 5*108322fbScarlsonj * Common Development and Distribution License (the "License"). 6*108322fbScarlsonj * You may not use this file except in compliance with the License. 7*108322fbScarlsonj * 8*108322fbScarlsonj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*108322fbScarlsonj * or http://www.opensolaris.org/os/licensing. 10*108322fbScarlsonj * See the License for the specific language governing permissions 11*108322fbScarlsonj * and limitations under the License. 12*108322fbScarlsonj * 13*108322fbScarlsonj * When distributing Covered Code, include this CDDL HEADER in each 14*108322fbScarlsonj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*108322fbScarlsonj * If applicable, add the following below this CDDL HEADER, with the 16*108322fbScarlsonj * fields enclosed by brackets "[]" replaced with your own identifying 17*108322fbScarlsonj * information: Portions Copyright [yyyy] [name of copyright owner] 18*108322fbScarlsonj * 19*108322fbScarlsonj * CDDL HEADER END 20*108322fbScarlsonj */ 21*108322fbScarlsonj 22*108322fbScarlsonj /* 23*108322fbScarlsonj * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*108322fbScarlsonj * Use is subject to license terms. 25*108322fbScarlsonj */ 26*108322fbScarlsonj 27*108322fbScarlsonj #pragma ident "%Z%%M% %I% %E% SMI" 28*108322fbScarlsonj 29*108322fbScarlsonj /* 30*108322fbScarlsonj * This module contains functions used for reading and writing the scratch zone 31*108322fbScarlsonj * translation files. These files are used by Live Upgrade to keep track of 32*108322fbScarlsonj * mappings between actual kernel zone names and the zones in an alternate boot 33*108322fbScarlsonj * environment. 34*108322fbScarlsonj * 35*108322fbScarlsonj * The functions are MT-safe. 36*108322fbScarlsonj * 37*108322fbScarlsonj * The file format looks like this: 38*108322fbScarlsonj * 39*108322fbScarlsonj * <zonename> <kernel-zonename> <alt-root> 40*108322fbScarlsonj * 41*108322fbScarlsonj * The expected usage model is: 42*108322fbScarlsonj * 43*108322fbScarlsonj * fp = zonecfg_open_scratch("", B_TRUE); 44*108322fbScarlsonj * zonecfg_lock_scratch(fp); 45*108322fbScarlsonj * if (zonecfg_find_scratch(fp, zonename, altroot, NULL, 0) == 0) { 46*108322fbScarlsonj * handle error; zone already mounted 47*108322fbScarlsonj * } 48*108322fbScarlsonj * mount zone here 49*108322fbScarlsonj * zonecfg_add_scratch(fp, zonename, kernname, altroot); 50*108322fbScarlsonj * zonecfg_close_scratch(fp); 51*108322fbScarlsonj * fp = zonecfg_open_scratch(zoneroot, B_TRUE); 52*108322fbScarlsonj * ftruncate(fileno(fp), 0); 53*108322fbScarlsonj * zonecfg_add_scratch(fp, zonename, kernname, "/"); 54*108322fbScarlsonj * zonecfg_close_scratch(fp); 55*108322fbScarlsonj */ 56*108322fbScarlsonj 57*108322fbScarlsonj #include <stdio.h> 58*108322fbScarlsonj #include <unistd.h> 59*108322fbScarlsonj #include <fcntl.h> 60*108322fbScarlsonj #include <errno.h> 61*108322fbScarlsonj #include <string.h> 62*108322fbScarlsonj #include <sys/types.h> 63*108322fbScarlsonj #include <sys/stat.h> 64*108322fbScarlsonj #include <sys/param.h> 65*108322fbScarlsonj #include <libzonecfg.h> 66*108322fbScarlsonj 67*108322fbScarlsonj #define PATH_MAPFILE "tmp/.alt.lu-zone-map" 68*108322fbScarlsonj 69*108322fbScarlsonj static int 70*108322fbScarlsonj lock_op(int fd, int type) 71*108322fbScarlsonj { 72*108322fbScarlsonj struct flock lock; 73*108322fbScarlsonj 74*108322fbScarlsonj lock.l_type = type; 75*108322fbScarlsonj lock.l_whence = SEEK_SET; 76*108322fbScarlsonj lock.l_start = 0; 77*108322fbScarlsonj lock.l_len = 0; 78*108322fbScarlsonj 79*108322fbScarlsonj return (fcntl(fd, F_SETLKW, &lock)); 80*108322fbScarlsonj } 81*108322fbScarlsonj 82*108322fbScarlsonj FILE * 83*108322fbScarlsonj zonecfg_open_scratch(const char *rootpath, boolean_t createfile) 84*108322fbScarlsonj { 85*108322fbScarlsonj mode_t oldmask = umask(0); 86*108322fbScarlsonj struct stat lbuf, fbuf; 87*108322fbScarlsonj int fd, flags; 88*108322fbScarlsonj FILE *fp; 89*108322fbScarlsonj char mapfile[MAXPATHLEN]; 90*108322fbScarlsonj 91*108322fbScarlsonj (void) snprintf(mapfile, sizeof (mapfile), "%s/" PATH_MAPFILE, 92*108322fbScarlsonj rootpath); 93*108322fbScarlsonj 94*108322fbScarlsonj flags = O_RDWR | O_NOFOLLOW | O_NOLINKS; 95*108322fbScarlsonj if (createfile) 96*108322fbScarlsonj flags |= O_EXCL | O_CREAT; 97*108322fbScarlsonj if ((fd = open(mapfile, flags, 0644)) == -1) { 98*108322fbScarlsonj if (!createfile) { 99*108322fbScarlsonj errno = ENOENT; 100*108322fbScarlsonj goto failure; 101*108322fbScarlsonj } 102*108322fbScarlsonj if (lstat(mapfile, &lbuf) == -1) 103*108322fbScarlsonj goto failure; 104*108322fbScarlsonj if (!S_ISREG(lbuf.st_mode) || lbuf.st_nlink != 1 || 105*108322fbScarlsonj lbuf.st_uid != 0) { 106*108322fbScarlsonj errno = EINVAL; 107*108322fbScarlsonj goto failure; 108*108322fbScarlsonj } 109*108322fbScarlsonj fd = open(mapfile, O_RDWR); 110*108322fbScarlsonj if (fd == -1) 111*108322fbScarlsonj goto failure; 112*108322fbScarlsonj if (fstat(fd, &fbuf) == -1) 113*108322fbScarlsonj goto failure; 114*108322fbScarlsonj if (lbuf.st_ino != fbuf.st_ino || lbuf.st_dev != fbuf.st_dev) { 115*108322fbScarlsonj errno = EINVAL; 116*108322fbScarlsonj goto failure; 117*108322fbScarlsonj } 118*108322fbScarlsonj } 119*108322fbScarlsonj if (lock_op(fd, F_RDLCK) == -1) 120*108322fbScarlsonj goto failure; 121*108322fbScarlsonj (void) umask(oldmask); 122*108322fbScarlsonj if ((fp = fdopen(fd, "r+")) == NULL) 123*108322fbScarlsonj (void) close(fd); 124*108322fbScarlsonj return (fp); 125*108322fbScarlsonj 126*108322fbScarlsonj failure: 127*108322fbScarlsonj if (fd != -1) 128*108322fbScarlsonj (void) close(fd); 129*108322fbScarlsonj (void) umask(oldmask); 130*108322fbScarlsonj return (NULL); 131*108322fbScarlsonj } 132*108322fbScarlsonj 133*108322fbScarlsonj int 134*108322fbScarlsonj zonecfg_lock_scratch(FILE *fp) 135*108322fbScarlsonj { 136*108322fbScarlsonj if (fflush(fp) != 0) 137*108322fbScarlsonj return (-1); 138*108322fbScarlsonj return (lock_op(fileno(fp), F_WRLCK)); 139*108322fbScarlsonj } 140*108322fbScarlsonj 141*108322fbScarlsonj void 142*108322fbScarlsonj zonecfg_close_scratch(FILE *fp) 143*108322fbScarlsonj { 144*108322fbScarlsonj (void) fclose(fp); 145*108322fbScarlsonj } 146*108322fbScarlsonj 147*108322fbScarlsonj int 148*108322fbScarlsonj zonecfg_get_scratch(FILE *fp, char *zonename, size_t namelen, char *kernname, 149*108322fbScarlsonj size_t kernlen, char *altroot, size_t altlen) 150*108322fbScarlsonj { 151*108322fbScarlsonj char line[2 * ZONENAME_MAX + MAXPATHLEN + 2]; 152*108322fbScarlsonj char *cp, *cp2; 153*108322fbScarlsonj 154*108322fbScarlsonj /* We always hold at least a read lock on the file */ 155*108322fbScarlsonj for (;;) { 156*108322fbScarlsonj if (fgets(line, sizeof (line), fp) == NULL) 157*108322fbScarlsonj return (-1); 158*108322fbScarlsonj if ((cp = strchr(line, '\n')) == NULL) 159*108322fbScarlsonj return (-1); 160*108322fbScarlsonj *cp = '\0'; 161*108322fbScarlsonj if ((cp = strchr(line, ' ')) == NULL) 162*108322fbScarlsonj cp = line + strlen(line); 163*108322fbScarlsonj else 164*108322fbScarlsonj *cp++ = '\0'; 165*108322fbScarlsonj if (zonename != NULL && 166*108322fbScarlsonj strlcpy(zonename, line, namelen) >= namelen) 167*108322fbScarlsonj continue; 168*108322fbScarlsonj if ((cp2 = strchr(cp, ' ')) == NULL) 169*108322fbScarlsonj cp2 = cp + strlen(cp); 170*108322fbScarlsonj else 171*108322fbScarlsonj *cp2++ = '\0'; 172*108322fbScarlsonj if (kernname != NULL && 173*108322fbScarlsonj strlcpy(kernname, cp, kernlen) >= kernlen) 174*108322fbScarlsonj continue; 175*108322fbScarlsonj if (altroot != NULL && strlcpy(altroot, cp2, altlen) >= altlen) 176*108322fbScarlsonj continue; 177*108322fbScarlsonj break; 178*108322fbScarlsonj } 179*108322fbScarlsonj return (0); 180*108322fbScarlsonj } 181*108322fbScarlsonj 182*108322fbScarlsonj int 183*108322fbScarlsonj zonecfg_find_scratch(FILE *fp, const char *zonename, const char *altroot, 184*108322fbScarlsonj char *kernzone, size_t kernlen) 185*108322fbScarlsonj { 186*108322fbScarlsonj char zone[ZONENAME_MAX]; 187*108322fbScarlsonj char aroot[MAXPATHLEN]; 188*108322fbScarlsonj 189*108322fbScarlsonj rewind(fp); 190*108322fbScarlsonj while (zonecfg_get_scratch(fp, zone, sizeof (zone), kernzone, kernlen, 191*108322fbScarlsonj aroot, sizeof (aroot)) == 0) { 192*108322fbScarlsonj if (strcmp(zone, zonename) == 0 && strcmp(altroot, aroot) == 0) 193*108322fbScarlsonj return (0); 194*108322fbScarlsonj } 195*108322fbScarlsonj return (-1); 196*108322fbScarlsonj } 197*108322fbScarlsonj 198*108322fbScarlsonj int 199*108322fbScarlsonj zonecfg_reverse_scratch(FILE *fp, const char *kernzone, char *zonename, 200*108322fbScarlsonj size_t namelen, char *altroot, size_t altlen) 201*108322fbScarlsonj { 202*108322fbScarlsonj char kzone[ZONENAME_MAX]; 203*108322fbScarlsonj 204*108322fbScarlsonj rewind(fp); 205*108322fbScarlsonj while (zonecfg_get_scratch(fp, zonename, namelen, kzone, 206*108322fbScarlsonj sizeof (kzone), altroot, altlen) == 0) { 207*108322fbScarlsonj if (strcmp(kzone, kernzone) == 0) 208*108322fbScarlsonj return (0); 209*108322fbScarlsonj } 210*108322fbScarlsonj return (-1); 211*108322fbScarlsonj } 212*108322fbScarlsonj 213*108322fbScarlsonj int 214*108322fbScarlsonj zonecfg_add_scratch(FILE *fp, const char *zonename, const char *kernzone, 215*108322fbScarlsonj const char *altroot) 216*108322fbScarlsonj { 217*108322fbScarlsonj if (fseek(fp, 0, SEEK_END) == -1) 218*108322fbScarlsonj return (-1); 219*108322fbScarlsonj if (fprintf(fp, "%s %s %s\n", zonename, kernzone, altroot) == EOF) 220*108322fbScarlsonj return (-1); 221*108322fbScarlsonj if (fflush(fp) != 0) 222*108322fbScarlsonj return (-1); 223*108322fbScarlsonj return (0); 224*108322fbScarlsonj } 225*108322fbScarlsonj 226*108322fbScarlsonj int 227*108322fbScarlsonj zonecfg_delete_scratch(FILE *fp, const char *kernzone) 228*108322fbScarlsonj { 229*108322fbScarlsonj char zone[ZONENAME_MAX]; 230*108322fbScarlsonj char kzone[ZONENAME_MAX]; 231*108322fbScarlsonj char aroot[MAXPATHLEN]; 232*108322fbScarlsonj long roffs, woffs; 233*108322fbScarlsonj 234*108322fbScarlsonj /* 235*108322fbScarlsonj * The implementation here is intentionally quite simple. We could 236*108322fbScarlsonj * allocate a buffer that's big enough to hold the data up to 237*108322fbScarlsonj * stat.st_size and then write back out the part we need to, but there 238*108322fbScarlsonj * seems to be little point. 239*108322fbScarlsonj */ 240*108322fbScarlsonj rewind(fp); 241*108322fbScarlsonj roffs = 0; 242*108322fbScarlsonj do { 243*108322fbScarlsonj woffs = roffs; 244*108322fbScarlsonj if (zonecfg_get_scratch(fp, NULL, 0, kzone, sizeof (kzone), 245*108322fbScarlsonj NULL, 0) != 0) 246*108322fbScarlsonj return (-1); 247*108322fbScarlsonj roffs = ftell(fp); 248*108322fbScarlsonj } while (strcmp(kzone, kernzone) != 0); 249*108322fbScarlsonj while (zonecfg_get_scratch(fp, zone, sizeof (zone), kzone, 250*108322fbScarlsonj sizeof (kzone), aroot, sizeof aroot) == 0) { 251*108322fbScarlsonj roffs = ftell(fp); 252*108322fbScarlsonj if (fseek(fp, woffs, SEEK_SET) == -1) 253*108322fbScarlsonj break; 254*108322fbScarlsonj if (fprintf(fp, "%s %s %s\n", zone, kzone, aroot) == EOF) 255*108322fbScarlsonj break; 256*108322fbScarlsonj woffs = ftell(fp); 257*108322fbScarlsonj if (fseek(fp, roffs, SEEK_SET) == -1) 258*108322fbScarlsonj break; 259*108322fbScarlsonj } 260*108322fbScarlsonj (void) ftruncate(fileno(fp), woffs); 261*108322fbScarlsonj return (0); 262*108322fbScarlsonj } 263*108322fbScarlsonj 264*108322fbScarlsonj boolean_t 265*108322fbScarlsonj zonecfg_is_scratch(const char *kernzone) 266*108322fbScarlsonj { 267*108322fbScarlsonj return (strncmp(kernzone, "SUNWlu", 6) == 0); 268*108322fbScarlsonj } 269