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