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