xref: /illumos-gate/usr/src/cmd/perl/contrib/Sun/Solaris/Project/Project.xs (revision 94cad3fef5d199c4897e68d856995cdb44e20dbb)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Project.xs contains XS wrappers for the project database maniplulation
26  * functions as provided by libproject and described in getprojent(3EXACCT).
27  */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 /* Solaris includes. */
32 #include <zone.h>
33 #include <project.h>
34 #include <pool.h>
35 #include <sys/pool_impl.h>
36 #include <rctl.h>
37 #include <stdio.h>
38 
39 /* Perl includes. */
40 #include "EXTERN.h"
41 #include "perl.h"
42 #include "XSUB.h"
43 
44 /*
45  * Convert and save a struct project on the perl XS return stack.
46  * In a void context it returns nothing, in a scalar context it returns just
47  * the name of the project and in a list context it returns a 6-element list
48  * consisting of (name, projid, comment, users, groups, attr), where users and
49  * groups are references to arrays containing the appropriate lists.
50  */
51 static int
52 pushret_project(const struct project *proj)
53 {
54 	char	**cp;
55 	AV	*ary;
56 
57 	dSP;
58 	if (GIMME_V == G_SCALAR) {
59 		EXTEND(SP, 1);
60 		PUSHs(sv_2mortal(newSVpv(proj->pj_name, 0)));
61 		PUTBACK;
62 		return (1);
63 	} else if (GIMME_V == G_ARRAY) {
64 		EXTEND(SP, 6);
65 		PUSHs(sv_2mortal(newSVpv(proj->pj_name, 0)));
66 		PUSHs(sv_2mortal(newSViv(proj->pj_projid)));
67 		PUSHs(sv_2mortal(newSVpv(proj->pj_comment, 0)));
68 		ary = newAV();
69 		for (cp = proj->pj_users; *cp != NULL; cp++) {
70 			av_push(ary, newSVpv(*cp, 0));
71 		}
72 		PUSHs(sv_2mortal(newRV_noinc((SV *)ary)));
73 		ary = newAV();
74 		for (cp = proj->pj_groups; *cp != NULL; cp++) {
75 			av_push(ary, newSVpv(*cp, 0));
76 		}
77 		PUSHs(sv_2mortal(newRV_noinc((SV *)ary)));
78 		PUSHs(sv_2mortal(newSVpv(proj->pj_attr, 0)));
79 		PUTBACK;
80 		return (6);
81 	} else {
82 		return (0);
83 	}
84 }
85 
86 static int
87 pwalk_cb(const projid_t project, void *walk_data)
88 {
89 	int *nitemsp;
90 
91 	dSP;
92 	nitemsp = (int *) walk_data;
93 	EXTEND(SP, 1);
94 	PUSHs(sv_2mortal(newSViv(project)));
95 	(*nitemsp)++;
96 	PUTBACK;
97 	return (0);
98 }
99 
100 /*
101  * The XS code exported to perl is below here.  Note that the XS preprocessor
102  * has its own commenting syntax, so all comments from this point on are in
103  * that form.  Note also that the PUTBACK; lines are necessary to synchronise
104  * the local and global views of the perl stack before calling pushret_project,
105  * as the code generated by the perl XS compiler twiddles with the stack on
106  * entry to an XSUB.
107  */
108 
109 MODULE = Sun::Solaris::Project PACKAGE = Sun::Solaris::Project
110 PROTOTYPES: ENABLE
111 
112  #
113  # Define any constants that need to be exported.  By doing it this way we can
114  # avoid the overhead of using the DynaLoader package, and in addition constants
115  # defined using this mechanism are eligible for inlining by the perl
116  # interpreter at compile time.
117  #
118 BOOT:
119 	{
120 	HV *stash;
121 	char buf[128];
122 	stash = gv_stashpv("Sun::Solaris::Project", TRUE);
123 	newCONSTSUB(stash, "MAXPROJID", newSViv(MAXPROJID));
124 	newCONSTSUB(stash, "PROJNAME_MAX", newSViv(PROJNAME_MAX));
125 	newCONSTSUB(stash, "PROJF_PATH",
126 	    newSVpv(PROJF_PATH, sizeof (PROJF_PATH) - 1));
127 	newCONSTSUB(stash, "PROJECT_BUFSZ", newSViv(PROJECT_BUFSZ));
128 	newCONSTSUB(stash, "SETPROJ_ERR_TASK", newSViv(SETPROJ_ERR_TASK));
129 	newCONSTSUB(stash, "SETPROJ_ERR_POOL", newSViv(SETPROJ_ERR_POOL));
130 	newCONSTSUB(stash, "RCTL_GLOBAL_NOBASIC",
131 		newSViv(RCTL_GLOBAL_NOBASIC));
132 	newCONSTSUB(stash, "RCTL_GLOBAL_LOWERABLE",
133 		newSViv(RCTL_GLOBAL_LOWERABLE));
134 	newCONSTSUB(stash, "RCTL_GLOBAL_DENY_ALWAYS",
135 		newSViv(RCTL_GLOBAL_DENY_ALWAYS));
136 	newCONSTSUB(stash, "RCTL_GLOBAL_DENY_NEVER",
137 		newSViv(RCTL_GLOBAL_DENY_NEVER));
138 	newCONSTSUB(stash, "RCTL_GLOBAL_FILE_SIZE",
139 		newSViv(RCTL_GLOBAL_FILE_SIZE));
140 	newCONSTSUB(stash, "RCTL_GLOBAL_CPU_TIME",
141 		newSViv(RCTL_GLOBAL_CPU_TIME));
142 	newCONSTSUB(stash, "RCTL_GLOBAL_SIGNAL_NEVER",
143 		newSViv(RCTL_GLOBAL_SIGNAL_NEVER));
144 	newCONSTSUB(stash, "RCTL_GLOBAL_INFINITE",
145 		newSViv(RCTL_GLOBAL_INFINITE));
146 	newCONSTSUB(stash, "RCTL_GLOBAL_UNOBSERVABLE",
147 		newSViv(RCTL_GLOBAL_UNOBSERVABLE));
148 	newCONSTSUB(stash, "RCTL_GLOBAL_BYTES",
149 		newSViv(RCTL_GLOBAL_BYTES));
150 	newCONSTSUB(stash, "RCTL_GLOBAL_SECONDS",
151 		newSViv(RCTL_GLOBAL_SECONDS));
152 	newCONSTSUB(stash, "RCTL_GLOBAL_COUNT",
153 		newSViv(RCTL_GLOBAL_COUNT));
154 	sprintf(buf, "%llu", UINT64_MAX);
155 	newCONSTSUB(stash, "RCTL_MAX_VALUE",
156 		newSVpv(buf, strlen(buf)));
157 	}
158 
159 projid_t
160 getprojid()
161 
162 int
163 setproject(name, user_name, flags)
164 	const char	*name;
165 	const char	*user_name
166 	uint_t		flags
167 
168 void
169 activeprojects()
170 PREINIT:
171 	int	nitems;
172 PPCODE:
173 	PUTBACK;
174 	nitems = 0;
175 	project_walk(&pwalk_cb, (void*)&nitems);
176 	XSRETURN(nitems);
177 
178 void
179 getprojent()
180 PREINIT:
181 	struct project	proj, *projp;
182 	char		buf[PROJECT_BUFSZ];
183 PPCODE:
184 	PUTBACK;
185 	if (projp = getprojent(&proj, buf, sizeof (buf))) {
186 		XSRETURN(pushret_project(projp));
187 	} else {
188 		XSRETURN_EMPTY;
189 	}
190 
191 void
192 setprojent()
193 
194 void
195 endprojent()
196 
197 void
198 getprojbyname(name)
199 	char	*name
200 PREINIT:
201 	struct project	proj, *projp;
202 	char		buf[PROJECT_BUFSZ];
203 PPCODE:
204 	PUTBACK;
205 	if (projp = getprojbyname(name, &proj, buf, sizeof (buf))) {
206 		XSRETURN(pushret_project(projp));
207 	} else {
208 		XSRETURN_EMPTY;
209 	}
210 
211 void
212 getprojbyid(id)
213 	projid_t	id
214 PREINIT:
215 	struct project	proj, *projp;
216 	char		buf[PROJECT_BUFSZ];
217 PPCODE:
218 	PUTBACK;
219 	if (projp = getprojbyid(id, &proj, buf, sizeof (buf))) {
220 		XSRETURN(pushret_project(projp));
221 	} else {
222 		XSRETURN_EMPTY;
223 	}
224 
225 void
226 getdefaultproj(user)
227 	char	*user
228 PREINIT:
229 	struct project	proj, *projp;
230 	char		buf[PROJECT_BUFSZ];
231 PPCODE:
232 	PUTBACK;
233 	if (projp = getdefaultproj(user, &proj, buf, sizeof (buf))) {
234 		XSRETURN(pushret_project(projp));
235 	} else {
236 		XSRETURN_EMPTY;
237 	}
238 
239 void
240 fgetprojent(fh)
241 	FILE	*fh
242 PREINIT:
243 	struct project	proj, *projp;
244 	char		buf[PROJECT_BUFSZ];
245 PPCODE:
246 	PUTBACK;
247 	if (projp = fgetprojent(fh, &proj, buf, sizeof (buf))) {
248 		XSRETURN(pushret_project(projp));
249 	} else {
250 		XSRETURN_EMPTY;
251 	}
252 
253 bool
254 inproj(user, proj)
255 	char	*user
256 	char	*proj
257 PREINIT:
258 	char	buf[PROJECT_BUFSZ];
259 CODE:
260 	RETVAL = inproj(user, proj, buf, sizeof (buf));
261 
262 
263 int
264 getprojidbyname(proj)
265 	char	*proj
266 PREINIT:
267 	int	id;
268 PPCODE:
269 	if ((id = getprojidbyname(proj)) == -1) {
270 		XSRETURN_UNDEF;
271 	} else {
272 		XSRETURN_IV(id);
273 	}
274 
275 
276 # rctl_get_info(name)
277 #
278 # For the given rctl name, returns the list
279 # ($max, $flags), where $max is the integer value
280 # of the system rctl, and $flags are the rctl's
281 # global flags, as returned by rctlblk_get_global_flags
282 #
283 # This function is private to Project.pm
284 void
285 rctl_get_info(name)
286 	char	*name
287 PREINIT:
288 	rctlblk_t *blk1 = NULL;
289 	rctlblk_t *blk2 = NULL;
290 	rctlblk_t *tmp = NULL;
291 	rctl_priv_t priv;
292 	rctl_qty_t value;
293 	int flags;
294 	int ret;
295 	int err = 0;
296 	char string[24];	/* 24 will always hold a uint64_t */
297 PPCODE:
298 	Newc(0, blk1, rctlblk_size(), char, rctlblk_t);
299 	if (blk1 == NULL) {
300 		err = 1;
301 		goto out;
302 	}
303 	Newc(1, blk2, rctlblk_size(), char, rctlblk_t);
304 	if (blk2 == NULL) {
305 		err = 1;
306 		goto out;
307 	}
308 	ret = getrctl(name, NULL, blk1, RCTL_FIRST);
309 	if (ret != 0) {
310 		err = 1;
311 		goto out;
312 	}
313 	priv = rctlblk_get_privilege(blk1);
314 	while (priv != RCPRIV_SYSTEM) {
315 		tmp = blk2;
316 		blk2 = blk1;
317 		blk1 = tmp;
318 		ret = getrctl(name, blk2, blk1, RCTL_NEXT);
319 		if (ret != 0) {
320 			err = 1;
321 			goto out;
322 		}
323 		priv = rctlblk_get_privilege(blk1);
324 	}
325 	value = rctlblk_get_value(blk1);
326 	flags = rctlblk_get_global_flags(blk1);
327 	ret = sprintf(string, "%llu", value);
328 	if (ret <= 0) {
329 		err = 1;
330 	}
331 	out:
332 	if (blk1)
333 		Safefree(blk1);
334 	if (blk2)
335 		Safefree(blk2);
336 	if (err)
337 		XSRETURN(0);
338 
339 	XPUSHs(sv_2mortal(newSVpv(string, 0)));
340 	XPUSHs(sv_2mortal(newSViv(flags)));
341 	XSRETURN(2);
342 
343 #
344 # pool_exists(name)
345 #
346 # Returns 0 a pool with the given name exists on the current system.
347 # Returns 1 if pools are disabled or the pool does not exist
348 #
349 # Used internally by project.pm to validate the project.pool attribute
350 #
351 # This function is private to Project.pm
352 void
353 pool_exists(name)
354 	char	*name
355 PREINIT:
356 	pool_conf_t *conf;
357 	pool_t *pool;
358 	pool_status_t status;
359 	int fd;
360 PPCODE:
361 
362 	/*
363 	 * Determine if pools are enabled using /dev/pool directly, as
364 	 * libpool may not be present.
365 	 */
366 	if (getzoneid() != GLOBAL_ZONEID) {
367 		XSRETURN_IV(1);
368 	}
369 	if ((fd = open("/dev/pool", O_RDONLY)) < 0) {
370 		XSRETURN_IV(1);
371 	}
372 	if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
373 		(void) close(fd);
374 		XSRETURN_IV(1);
375 	}
376 	close(fd);
377 	if (status.ps_io_state != 1) {
378 		XSRETURN_IV(1);
379 	}
380 
381 	/*
382 	 * If pools are enabled, assume libpool is present.
383 	 */
384 	conf = pool_conf_alloc();
385 	if (conf == NULL) {
386 		XSRETURN_IV(1);
387 	}
388 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)) {
389 		pool_conf_free(conf);
390 		XSRETURN_IV(1);
391 	}
392 	pool = pool_get_pool(conf, name);
393 	if (pool == NULL) {
394 		pool_conf_close(conf);
395 		pool_conf_free(conf);
396 		XSRETURN_IV(1);
397 	}
398 	pool_conf_close(conf);
399 	pool_conf_free(conf);
400 	XSRETURN_IV(0);
401 
402