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