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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2011 Joyent Inc. All rights reserved. 26 */ 27 28 #include "lint.h" 29 #include <sys/types.h> 30 #include <sys/syscall.h> 31 #include <sys/zone.h> 32 #include <sys/priv.h> 33 #include <priv_private.h> 34 #include <zone.h> 35 #include <sys/tsol/label.h> 36 #include <dlfcn.h> 37 #include <stdlib.h> 38 #include <errno.h> 39 40 zoneid_t 41 zone_create(const char *name, const char *root, const struct priv_set *privs, 42 const char *rctls, size_t rctlsz, const char *zfs, size_t zfssz, 43 int *extended_error, int match, int doi, const bslabel_t *label, int flags, 44 zoneid_t zone_did) 45 { 46 zone_def zd; 47 priv_data_t *d; 48 49 LOADPRIVDATA(d); 50 51 zd.zone_name = name; 52 zd.zone_root = root; 53 zd.zone_privs = privs; 54 zd.zone_privssz = d->pd_setsize; 55 zd.rctlbuf = rctls; 56 zd.rctlbufsz = rctlsz; 57 zd.zfsbuf = zfs; 58 zd.zfsbufsz = zfssz; 59 zd.extended_error = extended_error; 60 zd.match = match; 61 zd.doi = doi; 62 zd.label = label; 63 zd.flags = flags; 64 zd.zone_did = zone_did; 65 66 return ((zoneid_t)syscall(SYS_zone, ZONE_CREATE, &zd)); 67 } 68 69 int 70 zone_boot(zoneid_t zoneid) 71 { 72 return (syscall(SYS_zone, ZONE_BOOT, zoneid)); 73 } 74 75 int 76 zone_shutdown(zoneid_t zoneid) 77 { 78 return (syscall(SYS_zone, ZONE_SHUTDOWN, zoneid)); 79 } 80 81 int 82 zone_destroy(zoneid_t zoneid) 83 { 84 return (syscall(SYS_zone, ZONE_DESTROY, zoneid)); 85 } 86 87 ssize_t 88 zone_getattr(zoneid_t zoneid, int attr, void *valp, size_t size) 89 { 90 sysret_t rval; 91 int error; 92 93 error = __systemcall(&rval, SYS_zone, ZONE_GETATTR, zoneid, 94 attr, valp, size); 95 if (error) 96 (void) __set_errno(error); 97 return ((ssize_t)rval.sys_rval1); 98 } 99 100 int 101 zone_setattr(zoneid_t zoneid, int attr, void *valp, size_t size) 102 { 103 return (syscall(SYS_zone, ZONE_SETATTR, zoneid, attr, valp, size)); 104 } 105 106 int 107 zone_enter(zoneid_t zoneid) 108 { 109 return (syscall(SYS_zone, ZONE_ENTER, zoneid)); 110 } 111 112 /* 113 * Get id (if any) for specified zone. 114 * 115 * Call the real zone_get_id() in libzonecfg.so.1 if it can be found. 116 * Otherwise, perform a stripped-down version of the function. 117 * Any changes in one version should probably be reflected in the other. 118 * 119 * This stripped-down version of the function only checks for active 120 * (booted) zones, by numeric id or name. 121 */ 122 123 typedef int (*zone_get_id_t)(const char *, zoneid_t *); 124 static zone_get_id_t real_zone_get_id = NULL; 125 126 int 127 zone_get_id(const char *str, zoneid_t *zip) 128 { 129 zoneid_t zoneid; 130 char *cp; 131 132 /* 133 * The first time we are called, attempt to dlopen() libzonecfg.so.1 134 * and get a pointer to the real zone_get_id(). 135 * If we fail, set our pointer to -1 so we won't try again. 136 */ 137 if (real_zone_get_id == NULL) { 138 /* 139 * There's no harm in doing this more than once, even 140 * concurrently. We will get the same result each time, 141 * and the dynamic linker will single-thread the dlopen() 142 * with its own internal lock. The worst that can happen 143 * is that the handle gets a reference count greater than 144 * one, which doesn't matter since we never dlclose() 145 * the handle if we successfully find the symbol; the 146 * library just stays in the address space until exit(). 147 */ 148 void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY); 149 void *sym = (void *)(-1); 150 151 if (dlhandle != NULL && 152 (sym = dlsym(dlhandle, "zone_get_id")) == NULL) { 153 sym = (void *)(-1); 154 (void) dlclose(dlhandle); 155 } 156 real_zone_get_id = (zone_get_id_t)sym; 157 } 158 159 /* 160 * If we've successfully loaded it, call the real zone_get_id(). 161 * Otherwise, perform our stripped-down version of the code. 162 */ 163 if (real_zone_get_id != (zone_get_id_t)(-1)) 164 return (real_zone_get_id(str, zip)); 165 166 /* first try looking for active zone by id */ 167 errno = 0; 168 zoneid = (zoneid_t)strtol(str, &cp, 0); 169 if (errno == 0 && cp != str && *cp == '\0' && 170 getzonenamebyid(zoneid, NULL, 0) != -1) { 171 *zip = zoneid; 172 return (0); 173 } 174 175 /* then look for active zone by name */ 176 if ((zoneid = getzoneidbyname(str)) != -1) { 177 *zip = zoneid; 178 return (0); 179 } 180 181 /* not an active zone, return error */ 182 return (-1); 183 } 184 185 int 186 zone_list(zoneid_t *zonelist, uint_t *numzones) 187 { 188 return (syscall(SYS_zone, ZONE_LIST, zonelist, numzones)); 189 } 190 191 /* 192 * Underlying implementation for getzoneid and getzoneidbyname. 193 */ 194 static zoneid_t 195 zone_lookup(const char *name) 196 { 197 return ((zoneid_t)syscall(SYS_zone, ZONE_LOOKUP, name)); 198 } 199 200 zoneid_t 201 getzoneid(void) 202 { 203 return (zone_lookup(NULL)); 204 } 205 206 zoneid_t 207 getzoneidbyname(const char *zonename) 208 { 209 return (zone_lookup(zonename)); 210 } 211 212 ssize_t 213 getzonenamebyid(zoneid_t zoneid, char *buf, size_t buflen) 214 { 215 return (zone_getattr(zoneid, ZONE_ATTR_NAME, buf, buflen)); 216 } 217 218 int 219 zone_version(int *version) 220 { 221 return (syscall(SYS_zone, ZONE_VERSION, version)); 222 } 223 224 int 225 zone_add_datalink(zoneid_t zoneid, datalink_id_t linkid) 226 { 227 return (syscall(SYS_zone, ZONE_ADD_DATALINK, zoneid, linkid)); 228 } 229 230 int 231 zone_remove_datalink(zoneid_t zoneid, datalink_id_t linkid) 232 { 233 return (syscall(SYS_zone, ZONE_DEL_DATALINK, zoneid, linkid)); 234 } 235 236 int 237 zone_check_datalink(zoneid_t *zoneidp, datalink_id_t linkid) 238 { 239 return (syscall(SYS_zone, ZONE_CHECK_DATALINK, zoneidp, linkid)); 240 } 241 242 int 243 zone_list_datalink(zoneid_t zoneid, int *dlnump, datalink_id_t *linkids) 244 { 245 return (syscall(SYS_zone, ZONE_LIST_DATALINK, zoneid, dlnump, linkids)); 246 }