Change soft-fail to use the config, rather than env
[rbx.git] / stdlib / ext / etc / etc.c
blobe7b0ad7c79e91bdc94a0412745e57827f27d098c
1 /************************************************
3 etc.c -
5 $Author: shyouhei $
6 $Date: 2007-02-12 15:01:19 -0800 (Mon, 12 Feb 2007) $
7 created at: Tue Mar 22 18:39:19 JST 1994
9 ************************************************/
11 #include "ruby.h"
13 #include <sys/types.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
18 #ifdef HAVE_GETPWENT
19 #include <pwd.h>
20 #endif
22 #ifdef HAVE_GETGRENT
23 #include <grp.h>
24 #endif
26 #ifndef HAVE_TYPE_UID_T
27 #define uid_t int
28 #endif
30 static VALUE sPasswd, sGroup;
32 #ifndef _WIN32
33 char *getenv();
34 #endif
35 char *getlogin();
37 /* Returns the short user name of the currently logged in user.
39 * e.g.
40 * Etc.getlogin -> 'guest'
42 static VALUE
43 etc_getlogin(obj)
44 VALUE obj;
46 char *login;
48 rb_secure(4);
49 #ifdef HAVE_GETLOGIN
50 login = getlogin();
51 if (!login) login = getenv("USER");
52 #else
53 login = getenv("USER");
54 #endif
56 if (login)
57 return rb_tainted_str_new2(login);
58 return Qnil;
61 #if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
62 static VALUE
63 safe_setup_str(str)
64 const char *str;
66 if (str == 0) str = "";
67 return rb_tainted_str_new2(str);
69 #endif
71 #ifdef HAVE_GETPWENT
72 static VALUE
73 setup_passwd(pwd)
74 struct passwd *pwd;
76 if (pwd == 0) rb_sys_fail("/etc/passwd");
77 return rb_struct_new(sPasswd,
78 safe_setup_str(pwd->pw_name),
79 #ifdef HAVE_ST_PW_PASSWD
80 safe_setup_str(pwd->pw_passwd),
81 #endif
82 PW_UID2VAL(pwd->pw_uid),
83 PW_GID2VAL(pwd->pw_gid),
84 #ifdef HAVE_ST_PW_GECOS
85 safe_setup_str(pwd->pw_gecos),
86 #endif
87 safe_setup_str(pwd->pw_dir),
88 safe_setup_str(pwd->pw_shell),
89 #ifdef HAVE_ST_PW_CHANGE
90 INT2NUM(pwd->pw_change),
91 #endif
92 #ifdef HAVE_ST_PW_QUOTA
93 INT2NUM(pwd->pw_quota),
94 #endif
95 #ifdef HAVE_ST_PW_AGE
96 PW_AGE2VAL(pwd->pw_age),
97 #endif
98 #ifdef HAVE_ST_PW_CLASS
99 safe_setup_str(pwd->pw_class),
100 #endif
101 #ifdef HAVE_ST_PW_COMMENT
102 safe_setup_str(pwd->pw_comment),
103 #endif
104 #ifdef HAVE_ST_PW_EXPIRE
105 INT2NUM(pwd->pw_expire),
106 #endif
107 0 /*dummy*/
110 #endif
112 /* Returns the /etc/passwd information for the user with specified integer
113 * user id (uid).
115 * The information is returned as a Struct::Passwd; see getpwent above for
116 * details.
118 * e.g. * Etc.getpwuid(0) -> #<struct Struct::Passwd name="root",
119 * passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
121 static VALUE
122 etc_getpwuid(argc, argv, obj)
123 int argc;
124 VALUE *argv;
125 VALUE obj;
127 #if defined(HAVE_GETPWENT)
128 VALUE id;
129 uid_t uid;
130 struct passwd *pwd;
132 rb_secure(4);
133 if (rb_scan_args(argc, argv, "01", &id) == 1) {
134 uid = PW_VAL2UID(id);
136 else {
137 uid = getuid();
139 pwd = getpwuid(uid);
140 if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", uid);
141 return setup_passwd(pwd);
142 #else
143 return Qnil;
144 #endif
147 /* Returns the /etc/passwd information for the user with specified login name.
149 * The information is returned as a Struct::Passwd; see getpwent above for
150 * details.
152 * e.g. * Etc.getpwnam('root') -> #<struct Struct::Passwd name="root",
153 * passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
155 static VALUE
156 etc_getpwnam(obj, nam)
157 VALUE obj, nam;
159 #ifdef HAVE_GETPWENT
160 struct passwd *pwd;
162 SafeStringValue(nam);
163 pwd = getpwnam(RSTRING(nam)->ptr);
164 if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %s", RSTRING(nam)->ptr);
165 return setup_passwd(pwd);
166 #else
167 return Qnil;
168 #endif
171 #ifdef HAVE_GETPWENT
172 static int passwd_blocking = 0;
173 static VALUE
174 passwd_ensure()
176 passwd_blocking = Qfalse;
177 return Qnil;
180 static VALUE
181 passwd_iterate()
183 struct passwd *pw;
185 setpwent();
186 while (pw = getpwent()) {
187 rb_yield(setup_passwd(pw));
189 endpwent();
190 return Qnil;
192 #endif
194 /* Provides a convenient Ruby iterator which executes a block for each entry
195 * in the /etc/passwd file.
197 * The code block is passed an Etc::Passwd struct; see getpwent above for
198 * details.
200 * Example:
202 * require 'etc'
204 * Etc.passwd {|u|
205 * puts u.name + " = " + u.gecos
209 static VALUE
210 etc_passwd(obj)
211 VALUE obj;
213 #ifdef HAVE_GETPWENT
214 struct passwd *pw;
216 rb_secure(4);
217 if (rb_block_given_p()) {
218 if (passwd_blocking) {
219 rb_raise(rb_eRuntimeError, "parallel passwd iteration");
221 passwd_blocking = Qtrue;
222 rb_ensure(passwd_iterate, 0, passwd_ensure, 0);
224 if (pw = getpwent()) {
225 return setup_passwd(pw);
227 #endif
228 return Qnil;
231 /* Resets the process of reading the /etc/passwd file, so that the next call
232 * to getpwent will return the first entry again.
234 static VALUE
235 etc_setpwent(obj)
236 VALUE obj;
238 #ifdef HAVE_GETPWENT
239 setpwent();
240 #endif
241 return Qnil;
244 /* Ends the process of scanning through the /etc/passwd file begun with
245 * getpwent, and closes the file.
247 static VALUE
248 etc_endpwent(obj)
249 VALUE obj;
251 #ifdef HAVE_GETPWENT
252 endpwent();
253 #endif
254 return Qnil;
257 /* Returns an entry from the /etc/passwd file. The first time it is called it
258 * opens the file and returns the first entry; each successive call returns
259 * the next entry, or nil if the end of the file has been reached.
261 * To close the file when processing is complete, call endpwent.
263 * Each entry is returned as a Struct::Passwd:
265 * - Passwd#name contains the short login name of the user as a String.
267 * - Passwd#passwd contains the encrypted password of the user as a String.
268 * an 'x' is returned if shadow passwords are in use. An '*' is returned
269 * if the user cannot log in using a password.
271 * - Passwd#uid contains the integer user ID (uid) of the user.
273 * - Passwd#gid contains the integer group ID (gid) of the user's primary group.
275 * - Passwd#gecos contains a longer String description of the user, such as
276 * a full name. Some Unix systems provide structured information in the
277 * gecos field, but this is system-dependent.
279 * - Passwd#dir contains the path to the home directory of the user as a String.
281 * - Passwd#shell contains the path to the login shell of the user as a String.
283 static VALUE
284 etc_getpwent(obj)
285 VALUE obj;
287 #ifdef HAVE_GETPWENT
288 struct passwd *pw;
290 if (pw = getpwent()) {
291 return setup_passwd(pw);
293 #endif
294 return Qnil;
297 #ifdef HAVE_GETGRENT
298 static VALUE
299 setup_group(grp)
300 struct group *grp;
302 VALUE mem;
303 char **tbl;
305 mem = rb_ary_new();
306 tbl = grp->gr_mem;
307 while (*tbl) {
308 rb_ary_push(mem, safe_setup_str(*tbl));
309 tbl++;
311 return rb_struct_new(sGroup,
312 safe_setup_str(grp->gr_name),
313 #ifdef HAVE_ST_GR_PASSWD
314 safe_setup_str(grp->gr_passwd),
315 #endif
316 PW_GID2VAL(grp->gr_gid),
317 mem);
319 #endif
321 /* Returns information about the group with specified integer group id (gid),
322 * as found in /etc/group.
324 * The information is returned as a Struct::Group; see getgrent above for
325 * details.
327 * e.g. Etc.getgrgid(100) -> #<struct Struct::Group name="users", passwd="x",
328 * gid=100, mem=["meta", "root"]>
331 static VALUE
332 etc_getgrgid(obj, id)
333 VALUE obj, id;
335 #ifdef HAVE_GETGRENT
336 gid_t gid;
337 struct group *grp;
339 rb_secure(4);
340 gid = getgid();
341 grp = getgrgid(gid);
342 if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", gid);
343 return setup_group(grp);
344 #else
345 return Qnil;
346 #endif
349 /* Returns information about the group with specified String name, as found
350 * in /etc/group.
352 * The information is returned as a Struct::Group; see getgrent above for
353 * details.
355 * e.g. Etc.getgrnam('users') -> #<struct Struct::Group name="users",
356 * passwd="x", gid=100, mem=["meta", "root"]>
359 static VALUE
360 etc_getgrnam(obj, nam)
361 VALUE obj, nam;
363 #ifdef HAVE_GETGRENT
364 struct group *grp;
366 rb_secure(4);
367 SafeStringValue(nam);
368 grp = getgrnam(RSTRING(nam)->ptr);
369 if (grp == 0) rb_raise(rb_eArgError, "can't find group for %s", RSTRING(nam)->ptr);
370 return setup_group(grp);
371 #else
372 return Qnil;
373 #endif
376 #ifdef HAVE_GETGRENT
377 static int group_blocking = 0;
378 static VALUE
379 group_ensure()
381 group_blocking = Qfalse;
382 return Qnil;
385 static VALUE
386 group_iterate()
388 struct group *pw;
390 setgrent();
391 while (pw = getgrent()) {
392 rb_yield(setup_group(pw));
394 endgrent();
395 return Qnil;
397 #endif
399 /* Provides a convenient Ruby iterator which executes a block for each entry
400 * in the /etc/group file.
402 * The code block is passed an Etc::Group struct; see getgrent above for
403 * details.
405 * Example:
407 * require 'etc'
409 * Etc.group {|g|
410 * puts g.name + ": " + g.mem.join(', ')
414 static VALUE
415 etc_group(obj)
416 VALUE obj;
418 #ifdef HAVE_GETGRENT
419 struct group *grp;
421 rb_secure(4);
422 if (rb_block_given_p()) {
423 if (group_blocking) {
424 rb_raise(rb_eRuntimeError, "parallel group iteration");
426 group_blocking = Qtrue;
427 rb_ensure(group_iterate, 0, group_ensure, 0);
429 if (grp = getgrent()) {
430 return setup_group(grp);
432 #endif
433 return Qnil;
436 /* Resets the process of reading the /etc/group file, so that the next call
437 * to getgrent will return the first entry again.
439 static VALUE
440 etc_setgrent(obj)
441 VALUE obj;
443 #ifdef HAVE_GETGRENT
444 setgrent();
445 #endif
446 return Qnil;
449 /* Ends the process of scanning through the /etc/group file begun by
450 * getgrent, and closes the file.
452 static VALUE
453 etc_endgrent(obj)
454 VALUE obj;
456 #ifdef HAVE_GETGRENT
457 endgrent();
458 #endif
459 return Qnil;
462 /* Returns an entry from the /etc/group file. The first time it is called it
463 * opens the file and returns the first entry; each successive call returns
464 * the next entry, or nil if the end of the file has been reached.
466 * To close the file when processing is complete, call endgrent.
468 * Each entry is returned as a Struct::Group:
470 * - Group#name contains the name of the group as a String.
472 * - Group#passwd contains the encrypted password as a String. An 'x' is
473 * returned if password access to the group is not available; an empty
474 * string is returned if no password is needed to obtain membership of
475 * the group.
477 * - Group#gid contains the group's numeric ID as an integer.
479 * - Group#mem is an Array of Strings containing the short login names of the
480 * members of the group.
482 static VALUE
483 etc_getgrent(obj)
484 VALUE obj;
486 #ifdef HAVE_GETGRENT
487 struct group *gr;
489 if (gr = getgrent()) {
490 return setup_group(gr);
492 #endif
493 return Qnil;
496 static VALUE mEtc;
498 /* The etc module provides access to information from the /etc/passwd and
499 * /etc/group files on Linux and Unix systems.
501 * Documented by mathew <meta@pobox.com>.
503 void
504 Init_etc()
506 mEtc = rb_define_module("Etc");
508 rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
510 rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
511 rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1);
512 rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0);
513 rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0);
514 rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0);
515 rb_define_module_function(mEtc, "passwd", etc_passwd, 0);
517 rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, 1);
518 rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1);
519 rb_define_module_function(mEtc, "group", etc_group, 0);
520 rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0);
521 rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
522 rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
524 rb_global_variable(&sPasswd);
525 sPasswd = rb_struct_define("Passwd",
526 "name", "passwd", "uid", "gid",
527 #ifdef HAVE_ST_PW_GECOS
528 "gecos",
529 #endif
530 "dir", "shell",
531 #ifdef HAVE_ST_PW_CHANGE
532 "change",
533 #endif
534 #ifdef HAVE_ST_PW_QUOTA
535 "quota",
536 #endif
537 #ifdef HAVE_ST_PW_AGE
538 "age",
539 #endif
540 #ifdef HAVE_ST_PW_CLASS
541 "uclass",
542 #endif
543 #ifdef HAVE_ST_PW_COMMENT
544 "comment",
545 #endif
546 #ifdef HAVE_ST_PW_EXPIRE
547 "expire",
548 #endif
549 NULL);
551 #ifdef HAVE_GETGRENT
552 rb_global_variable(&sGroup);
553 sGroup = rb_struct_define("Group", "name",
554 #ifdef HAVE_ST_GR_PASSWD
555 "passwd",
556 #endif
557 "gid", "mem", NULL);
558 #endif