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
pushret_project(const struct project * proj)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
pwalk_cb(const projid_t project,void * walk_data)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