summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc/port/sys/zone.c
blob: 8cf28c3ccfee1660b8cf3235a126aed899bea91f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 * Copyright 2011 Joyent Inc.  All rights reserved.
 */

#include "lint.h"
#include "thr_uberdata.h"
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/zone.h>
#include <sys/priv.h>
#include <priv_private.h>
#include <zone.h>
#include <sys/tsol/label.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <errno.h>

zoneid_t
zone_create(const char *name, const char *root, const struct priv_set *privs,
    const char *rctls, size_t rctlsz, const char *zfs, size_t zfssz,
    int *extended_error, int match, int doi, const bslabel_t *label, int flags,
    zoneid_t req_zoneid)
{
	zone_def  zd;
	priv_data_t *d;

	LOADPRIVDATA(d);

	zd.zone_name = name;
	zd.zone_root = root;
	zd.zone_privs = privs;
	zd.zone_privssz = d->pd_setsize;
	zd.rctlbuf = rctls;
	zd.rctlbufsz = rctlsz;
	zd.zfsbuf = zfs;
	zd.zfsbufsz = zfssz;
	zd.extended_error = extended_error;
	zd.match = match;
	zd.doi = doi;
	zd.label = label;
	zd.flags = flags;
	zd.zoneid = req_zoneid;

	return ((zoneid_t)syscall(SYS_zone, ZONE_CREATE, &zd));
}

int
zone_boot(zoneid_t zoneid)
{
	return (syscall(SYS_zone, ZONE_BOOT, zoneid));
}

int
zone_shutdown(zoneid_t zoneid)
{
	return (syscall(SYS_zone, ZONE_SHUTDOWN, zoneid));
}

int
zone_destroy(zoneid_t zoneid)
{
	return (syscall(SYS_zone, ZONE_DESTROY, zoneid));
}

ssize_t
zone_getattr(zoneid_t zoneid, int attr, void *valp, size_t size)
{
	sysret_t rval;
	int error;

	error = __systemcall(&rval, SYS_zone, ZONE_GETATTR, zoneid,
	    attr, valp, size);
	if (error)
		(void) __set_errno(error);
	return ((ssize_t)rval.sys_rval1);
}

int
zone_setattr(zoneid_t zoneid, int attr, void *valp, size_t size)
{
	return (syscall(SYS_zone, ZONE_SETATTR, zoneid, attr, valp, size));
}

int
zone_enter(zoneid_t zoneid)
{
	return (syscall(SYS_zone, ZONE_ENTER, zoneid));
}

/*
 * Get id (if any) for specified zone.
 *
 * Call the real zone_get_id() in libzonecfg.so.1 if it can be found.
 * Otherwise, perform a stripped-down version of the function.
 * Any changes in one version should probably be reflected in the other.
 *
 * This stripped-down version of the function only checks for active
 * (booted) zones, by numeric id or name.
 */

typedef	int (*zone_get_id_t)(const char *, zoneid_t *);
static zone_get_id_t real_zone_get_id = NULL;

int
zone_get_id(const char *str, zoneid_t *zip)
{
	zoneid_t zoneid;
	char *cp;

	/*
	 * The first time we are called, attempt to dlopen() libzonecfg.so.1
	 * and get a pointer to the real zone_get_id().
	 * If we fail, set our pointer to -1 so we won't try again.
	 */
	if (real_zone_get_id == NULL) {
		/*
		 * There's no harm in doing this more than once, even
		 * concurrently.  We will get the same result each time,
		 * and the dynamic linker will single-thread the dlopen()
		 * with its own internal lock.  The worst that can happen
		 * is that the handle gets a reference count greater than
		 * one, which doesn't matter since we never dlclose()
		 * the handle if we successfully find the symbol; the
		 * library just stays in the address space until exit().
		 */
		void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY);
		void *sym = (void *)(-1);

		if (dlhandle != NULL &&
		    (sym = dlsym(dlhandle, "zone_get_id")) == NULL) {
			sym = (void *)(-1);
			(void) dlclose(dlhandle);
		}
		real_zone_get_id = (zone_get_id_t)sym;
	}

	/*
	 * If we've successfully loaded it, call the real zone_get_id().
	 * Otherwise, perform our stripped-down version of the code.
	 */
	if (real_zone_get_id != (zone_get_id_t)(-1))
		return (real_zone_get_id(str, zip));

	/* first try looking for active zone by id */
	errno = 0;
	zoneid = (zoneid_t)strtol(str, &cp, 0);
	if (errno == 0 && cp != str && *cp == '\0' &&
	    getzonenamebyid(zoneid, NULL, 0) != -1) {
		*zip = zoneid;
		return (0);
	}

	/* then look for active zone by name */
	if ((zoneid = getzoneidbyname(str)) != -1) {
		*zip = zoneid;
		return (0);
	}

	/* not an active zone, return error */
	return (-1);
}

int
zone_list(zoneid_t *zonelist, uint_t *numzones)
{
	return (syscall(SYS_zone, ZONE_LIST, zonelist, numzones));
}

/*
 * Underlying implementation for getzoneid and getzoneidbyname.
 */
static zoneid_t
zone_lookup(const char *name)
{
	return ((zoneid_t)syscall(SYS_zone, ZONE_LOOKUP, name));
}

zoneid_t
getzoneid(void)
{
	return (zone_lookup(NULL));
}

zoneid_t
getzoneidbyname(const char *zonename)
{
	return (zone_lookup(zonename));
}

ssize_t
getzonenamebyid(zoneid_t zoneid, char *buf, size_t buflen)
{
	return (zone_getattr(zoneid, ZONE_ATTR_NAME, buf, buflen));
}

int
zone_version(int *version)
{
	return (syscall(SYS_zone, ZONE_VERSION, version));
}

int
zone_add_datalink(zoneid_t zoneid, datalink_id_t linkid)
{
	return (syscall(SYS_zone, ZONE_ADD_DATALINK, zoneid, linkid));
}

int
zone_remove_datalink(zoneid_t zoneid, datalink_id_t linkid)
{
	return (syscall(SYS_zone, ZONE_DEL_DATALINK, zoneid, linkid));
}

int
zone_check_datalink(zoneid_t *zoneidp, datalink_id_t linkid)
{
	return (syscall(SYS_zone, ZONE_CHECK_DATALINK, zoneidp, linkid));
}

int
zone_list_datalink(zoneid_t zoneid, int *dlnump, datalink_id_t *linkids)
{
	return (syscall(SYS_zone, ZONE_LIST_DATALINK, zoneid, dlnump, linkids));
}

const char *
zone_get_nroot()
{
	uberdata_t *udp = curthread->ul_uberdata;
	return (udp->ub_broot);
}