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