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