1 /*
2 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
3 *
4 * File.xs contains XS code for exacct file manipulation.
5 */
6
7 #include <pwd.h>
8 #include "../exacct_common.xh"
9
10 /* Pull in the file generated by extract_defines. */
11 #include "FileDefs.xi"
12
13 /*
14 * The XS code exported to perl is below here. Note that the XS preprocessor
15 * has its own commenting syntax, so all comments from this point on are in
16 * that form.
17 */
18
19 MODULE = Sun::Solaris::Exacct::File PACKAGE = Sun::Solaris::Exacct::File
20 PROTOTYPES: ENABLE
21
22 #
23 # Define the stash pointers if required and create and populate @_Constants.
24 #
25 BOOT:
26 {
27 init_stashes();
28 define_constants(PKGBASE "::File", constants);
29 }
30
31 #
32 # Open an exacct file and return an object with which to manipulate it.
33 # The parameters are the filename, the open mode and a list of optional
34 # (key => value) parameters where the key may be one of creator, aflags or
35 # mode. For a full explanation of the various combinations, see the manpage
36 # for ea_open_file(3EXACCT).
37 #
38 ea_file_t *
39 new(class, name, oflags, ...)
40 char *class;
41 char *name;
42 int oflags;
43 PREINIT:
44 int i;
45 /* Assume usernames are <= 32 chars (pwck(1M) assumes <= 8) */
46 char user[33];
47 char *creator = NULL;
48 int aflags = -1;
49 mode_t mode = 0666;
50 CODE:
51 /*
52 * Account for the mandatory parameters,
53 * and the rest must be an even number.
54 */
55 i = items - 3;
56 if ((i % 2) != 0) {
57 croak("Usage: Sun::Solaris::Exacct::File::new"
58 "(class, name, oflags, ...)");
59 }
60
61 /* Process any optional parameters. */
62 for (i = 3; i < items; i += 2) {
63 if (strEQ(SvPV_nolen(ST(i)), "creator")) {
64 creator = SvPV_nolen(ST(i + 1));
65 } else if (strEQ(SvPV_nolen(ST(i)), "aflags")) {
66 aflags = SvIV(ST(i + 1));
67 } else if (strEQ(SvPV_nolen(ST(i)), "mode")) {
68 mode = SvIV(ST(i + 1));
69 } else {
70 croak("invalid named argument %s", SvPV_nolen(ST(i)));
71 }
72 }
73
74 /* Check and default the creator parameter. */
75 if (oflags & O_CREAT && creator == NULL) {
76 uid_t uid;
77 struct passwd *pwent;
78
79 uid = getuid();
80 if ((pwent = getpwuid(uid)) == NULL) {
81 snprintf(user, sizeof (user), "%d", uid);
82 } else {
83 strlcpy(user, pwent->pw_name, sizeof (user));
84 }
85 creator = user;
86 }
87
88 /* Check and default the aflags parameter. */
89 if (aflags == -1) {
90 if (oflags == O_RDONLY) {
91 aflags = EO_HEAD;
92 } else {
93 aflags = EO_TAIL;
94 }
95 }
96 RETVAL = ea_alloc(sizeof (ea_file_t));
97 PERL_ASSERT(RETVAL != NULL);
98 if (ea_open(RETVAL, name, creator, aflags, oflags, mode) == -1) {
99 ea_free(RETVAL, sizeof (ea_file_t));
100 RETVAL = NULL;
101 }
102 OUTPUT:
103 RETVAL
104
105 void
106 DESTROY(self)
107 ea_file_t *self;
108 CODE:
109 ea_close(self);
110 ea_free(self, sizeof(ea_file_t));
111
112 #
113 # Return the creator of the file.
114 #
115 SV*
116 creator(self)
117 ea_file_t *self;
118 PREINIT:
119 const char *creator;
120 CODE:
121 if ((creator = ea_get_creator(self)) == NULL) {
122 RETVAL = &PL_sv_undef;
123 } else {
124 RETVAL = newSVpv(creator, 0);
125 }
126 OUTPUT:
127 RETVAL
128
129 #
130 # Return the hostname the file was created on.
131 #
132 SV*
133 hostname(self)
134 ea_file_t *self;
135 PREINIT:
136 const char *hostname;
137 CODE:
138 if ((hostname = ea_get_hostname(self)) == NULL) {
139 RETVAL = &PL_sv_undef;
140 } else {
141 RETVAL = newSVpv(hostname, 0);
142 }
143 OUTPUT:
144 RETVAL
145
146 #
147 # Get the next/previous record from the file and return its type.
148 # These two operations are so similar that the XSUB ALIAS functionality is
149 # used to merge them into one function.
150 #
151 void
152 next(self)
153 ea_file_t *self;
154 ALIAS:
155 previous = 1
156 PREINIT:
157 ea_object_type_t type;
158 const char *type_str;
159 ea_object_t object;
160 SV *sv;
161 static const char *const type_map[] =
162 { "EO_NONE", "EO_GROUP", "EO_ITEM" };
163 PPCODE:
164 /* Call the appropriate next/last function. */
165 if (ix == 0) {
166 type = ea_next_object(self, &object);
167 } else {
168 type = ea_previous_object(self, &object);
169 }
170
171 /* Work out the call context. */
172 switch (GIMME_V) {
173 case G_SCALAR:
174 /* In a scalar context, just return the type. */
175 EXTEND(SP, 1);
176 if (type == EO_ERROR) {
177 PUSHs(&PL_sv_undef);
178 } else {
179 sv = newSVuv(type);
180 sv_setpv(sv, type_map[type]);
181 SvIOK_on(sv);
182 PUSHs(sv_2mortal(sv));
183 }
184 break;
185 case G_ARRAY:
186 /* In a list contect, return the type and catalog. */
187 EXTEND(SP, 2);
188 if (type == EO_ERROR) {
189 PUSHs(&PL_sv_undef);
190 PUSHs(&PL_sv_undef);
191 } else {
192 sv = newSVuv(type);
193 sv_setpv(sv, type_map[type]);
194 SvIOK_on(sv);
195 PUSHs(sv_2mortal(sv));
196 PUSHs(sv_2mortal(new_catalog(object.eo_catalog)));
197 }
198 break;
199 case G_VOID:
200 default:
201 /* In a void context, return nothing. */
202 break;
203 }
204
205 #
206 # Get the next object from the file and return as an ::Object.
207 #
208 SV*
209 get(self)
210 ea_file_t *self;
211 PREINIT:
212 ea_object_t *obj;
213 CODE:
214 if ((obj = ea_get_object_tree(self, 1)) != NULL) {
215 RETVAL = new_xs_ea_object(obj);
216 } else {
217 RETVAL = &PL_sv_undef;
218 }
219 OUTPUT:
220 RETVAL
221
222 #
223 # Write the passed list of ::Objects to the file.
224 # Returns true on success and false on failure.
225 #
226 SV*
227 write(self, ...)
228 ea_file_t *self;
229 PREINIT:
230 int i;
231 SV *sv;
232 HV *stash;
233 ea_object_t *obj;
234 CODE:
235 for (i = 1; i < items; i++) {
236 /* Check the value is either an ::Item or a ::Group. */
237 sv = SvRV(ST(i));
238 stash = sv ? SvSTASH(sv) : NULL;
239 if (stash != Sun_Solaris_Exacct_Object_Item_stash &&
240 stash != Sun_Solaris_Exacct_Object_Group_stash) {
241 XSRETURN_NO;
242 }
243
244 /* Deflate and write the object. */
245 obj = deflate_xs_ea_object(ST(i));
246 PERL_ASSERT(obj != NULL);
247 if (ea_write_object(self, obj) == -1) {
248 XSRETURN_NO;
249 }
250 }
251 RETVAL = &PL_sv_yes;
252 OUTPUT:
253 RETVAL