Ruby  1.9.3p547(2014-05-14revision45962)
etc.c
Go to the documentation of this file.
1 /************************************************
2 
3  etc.c -
4 
5  $Author: akr $
6  created at: Tue Mar 22 18:39:19 JST 1994
7 
8 ************************************************/
9 
10 #include "ruby.h"
11 #include "ruby/encoding.h"
12 
13 #include <sys/types.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 
18 #ifdef HAVE_GETPWENT
19 #include <pwd.h>
20 #endif
21 
22 #ifdef HAVE_GETGRENT
23 #include <grp.h>
24 #endif
25 
26 static VALUE sPasswd;
27 #ifdef HAVE_GETGRENT
28 static VALUE sGroup;
29 #endif
30 
31 #ifdef _WIN32
32 #include <shlobj.h>
33 #ifndef CSIDL_COMMON_APPDATA
34 #define CSIDL_COMMON_APPDATA 35
35 #endif
36 #endif
37 
38 #ifndef _WIN32
39 char *getenv();
40 #endif
41 char *getlogin();
42 
43 /* Returns the short user name of the currently logged in user.
44  * Unfortunately, it is often rather easy to fool getlogin().
45  * Avoid getlogin() for security-related purposes.
46  *
47  * e.g.
48  * Etc.getlogin -> 'guest'
49  */
50 static VALUE
52 {
53  char *login;
54 
55  rb_secure(4);
56 #ifdef HAVE_GETLOGIN
57  login = getlogin();
58  if (!login) login = getenv("USER");
59 #else
60  login = getenv("USER");
61 #endif
62 
63  if (login)
64  return rb_tainted_str_new2(login);
65  return Qnil;
66 }
67 
68 #if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
69 static VALUE
70 safe_setup_str(const char *str)
71 {
72  if (str == 0) str = "";
73  return rb_tainted_str_new2(str);
74 }
75 #endif
76 
77 #ifdef HAVE_GETPWENT
78 static VALUE
79 setup_passwd(struct passwd *pwd)
80 {
81  if (pwd == 0) rb_sys_fail("/etc/passwd");
82  return rb_struct_new(sPasswd,
83  safe_setup_str(pwd->pw_name),
84 #ifdef HAVE_ST_PW_PASSWD
85  safe_setup_str(pwd->pw_passwd),
86 #endif
87  UIDT2NUM(pwd->pw_uid),
88  GIDT2NUM(pwd->pw_gid),
89 #ifdef HAVE_ST_PW_GECOS
90  safe_setup_str(pwd->pw_gecos),
91 #endif
92  safe_setup_str(pwd->pw_dir),
93  safe_setup_str(pwd->pw_shell),
94 #ifdef HAVE_ST_PW_CHANGE
95  INT2NUM(pwd->pw_change),
96 #endif
97 #ifdef HAVE_ST_PW_QUOTA
98  INT2NUM(pwd->pw_quota),
99 #endif
100 #ifdef HAVE_ST_PW_AGE
101  PW_AGE2VAL(pwd->pw_age),
102 #endif
103 #ifdef HAVE_ST_PW_CLASS
104  safe_setup_str(pwd->pw_class),
105 #endif
106 #ifdef HAVE_ST_PW_COMMENT
107  safe_setup_str(pwd->pw_comment),
108 #endif
109 #ifdef HAVE_ST_PW_EXPIRE
110  INT2NUM(pwd->pw_expire),
111 #endif
112  0 /*dummy*/
113  );
114 }
115 #endif
116 
117 /* Returns the /etc/passwd information for the user with specified integer
118  * user id (uid).
119  *
120  * The information is returned as a Struct::Passwd; see getpwent above for
121  * details.
122  *
123  * e.g. * Etc.getpwuid(0) -> #<struct Struct::Passwd name="root",
124  * passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
125  */
126 static VALUE
128 {
129 #if defined(HAVE_GETPWENT)
130  VALUE id;
131  rb_uid_t uid;
132  struct passwd *pwd;
133 
134  rb_secure(4);
135  if (rb_scan_args(argc, argv, "01", &id) == 1) {
136  uid = NUM2UIDT(id);
137  }
138  else {
139  uid = getuid();
140  }
141  pwd = getpwuid(uid);
142  if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", (int)uid);
143  return setup_passwd(pwd);
144 #else
145  return Qnil;
146 #endif
147 }
148 
149 /* Returns the /etc/passwd information for the user with specified login name.
150  *
151  * The information is returned as a Struct::Passwd; see getpwent above for
152  * details.
153  *
154  * e.g. * Etc.getpwnam('root') -> #<struct Struct::Passwd name="root",
155  * passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
156  */
157 static VALUE
159 {
160 #ifdef HAVE_GETPWENT
161  struct passwd *pwd;
162 
163  SafeStringValue(nam);
164  pwd = getpwnam(RSTRING_PTR(nam));
165  if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %s", RSTRING_PTR(nam));
166  return setup_passwd(pwd);
167 #else
168  return Qnil;
169 #endif
170 }
171 
172 #ifdef HAVE_GETPWENT
173 static int passwd_blocking = 0;
174 static VALUE
175 passwd_ensure(void)
176 {
177  passwd_blocking = (int)Qfalse;
178  return Qnil;
179 }
180 
181 static VALUE
182 passwd_iterate(void)
183 {
184  struct passwd *pw;
185 
186  setpwent();
187  while (pw = getpwent()) {
188  rb_yield(setup_passwd(pw));
189  }
190  endpwent();
191  return Qnil;
192 }
193 
194 static void
195 each_passwd(void)
196 {
197  if (passwd_blocking) {
198  rb_raise(rb_eRuntimeError, "parallel passwd iteration");
199  }
200  passwd_blocking = (int)Qtrue;
201  rb_ensure(passwd_iterate, 0, passwd_ensure, 0);
202 }
203 #endif
204 
205 /* Provides a convenient Ruby iterator which executes a block for each entry
206  * in the /etc/passwd file.
207  *
208  * The code block is passed an Struct::Passwd struct; see getpwent above for
209  * details.
210  *
211  * Example:
212  *
213  * require 'etc'
214  *
215  * Etc.passwd {|u|
216  * puts u.name + " = " + u.gecos
217  * }
218  *
219  */
220 static VALUE
222 {
223 #ifdef HAVE_GETPWENT
224  struct passwd *pw;
225 
226  rb_secure(4);
227  if (rb_block_given_p()) {
228  each_passwd();
229  }
230  else if (pw = getpwent()) {
231  return setup_passwd(pw);
232  }
233 #endif
234  return Qnil;
235 }
236 
237 /* Iterates for each entry in the /etc/passwd file if a block is given.
238  * If no block is given, returns the enumerator.
239  *
240  * The code block is passed an Struct::Passwd struct; see getpwent above for
241  * details.
242  *
243  * Example:
244  *
245  * require 'etc'
246  *
247  * Etc::Passwd.each {|u|
248  * puts u.name + " = " + u.gecos
249  * }
250  *
251  * Etc::Passwd.collect {|u| u.gecos}
252  * Etc::Passwd.collect {|u| u.gecos}
253  *
254  */
255 static VALUE
257 {
258 #ifdef HAVE_GETPWENT
259  RETURN_ENUMERATOR(obj, 0, 0);
260  each_passwd();
261 #endif
262  return obj;
263 }
264 
265 /* Resets the process of reading the /etc/passwd file, so that the next call
266  * to getpwent will return the first entry again.
267  */
268 static VALUE
270 {
271 #ifdef HAVE_GETPWENT
272  setpwent();
273 #endif
274  return Qnil;
275 }
276 
277 /* Ends the process of scanning through the /etc/passwd file begun with
278  * getpwent, and closes the file.
279  */
280 static VALUE
282 {
283 #ifdef HAVE_GETPWENT
284  endpwent();
285 #endif
286  return Qnil;
287 }
288 
289 /* Returns an entry from the /etc/passwd file. The first time it is called it
290  * opens the file and returns the first entry; each successive call returns
291  * the next entry, or nil if the end of the file has been reached.
292  *
293  * To close the file when processing is complete, call endpwent.
294  *
295  * Each entry is returned as a Struct::Passwd:
296  *
297  * - Passwd#name contains the short login name of the user as a String.
298  *
299  * - Passwd#passwd contains the encrypted password of the user as a String.
300  * an 'x' is returned if shadow passwords are in use. An '*' is returned
301  * if the user cannot log in using a password.
302  *
303  * - Passwd#uid contains the integer user ID (uid) of the user.
304  *
305  * - Passwd#gid contains the integer group ID (gid) of the user's primary group.
306  *
307  * - Passwd#gecos contains a longer String description of the user, such as
308  * a full name. Some Unix systems provide structured information in the
309  * gecos field, but this is system-dependent.
310  *
311  * - Passwd#dir contains the path to the home directory of the user as a String.
312  *
313  * - Passwd#shell contains the path to the login shell of the user as a String.
314  */
315 static VALUE
317 {
318 #ifdef HAVE_GETPWENT
319  struct passwd *pw;
320 
321  if (pw = getpwent()) {
322  return setup_passwd(pw);
323  }
324 #endif
325  return Qnil;
326 }
327 
328 #ifdef HAVE_GETGRENT
329 static VALUE
330 setup_group(struct group *grp)
331 {
332  VALUE mem;
333  char **tbl;
334 
335  mem = rb_ary_new();
336  tbl = grp->gr_mem;
337  while (*tbl) {
338  rb_ary_push(mem, safe_setup_str(*tbl));
339  tbl++;
340  }
341  return rb_struct_new(sGroup,
342  safe_setup_str(grp->gr_name),
343 #ifdef HAVE_ST_GR_PASSWD
344  safe_setup_str(grp->gr_passwd),
345 #endif
346  GIDT2NUM(grp->gr_gid),
347  mem);
348 }
349 #endif
350 
351 /* Returns information about the group with specified integer group id (gid),
352  * as found in /etc/group.
353  *
354  * The information is returned as a Struct::Group; see getgrent above for
355  * details.
356  *
357  * e.g. Etc.getgrgid(100) -> #<struct Struct::Group name="users", passwd="x",
358  * gid=100, mem=["meta", "root"]>
359  *
360  */
361 static VALUE
363 {
364 #ifdef HAVE_GETGRENT
365  VALUE id;
366  gid_t gid;
367  struct group *grp;
368 
369  rb_secure(4);
370  if (rb_scan_args(argc, argv, "01", &id) == 1) {
371  gid = NUM2GIDT(id);
372  }
373  else {
374  gid = getgid();
375  }
376  grp = getgrgid(gid);
377  if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", (int)gid);
378  return setup_group(grp);
379 #else
380  return Qnil;
381 #endif
382 }
383 
384 /* Returns information about the group with specified String name, as found
385  * in /etc/group.
386  *
387  * The information is returned as a Struct::Group; see getgrent above for
388  * details.
389  *
390  * e.g. Etc.getgrnam('users') -> #<struct Struct::Group name="users",
391  * passwd="x", gid=100, mem=["meta", "root"]>
392  *
393  */
394 static VALUE
396 {
397 #ifdef HAVE_GETGRENT
398  struct group *grp;
399 
400  rb_secure(4);
401  SafeStringValue(nam);
402  grp = getgrnam(RSTRING_PTR(nam));
403  if (grp == 0) rb_raise(rb_eArgError, "can't find group for %s", RSTRING_PTR(nam));
404  return setup_group(grp);
405 #else
406  return Qnil;
407 #endif
408 }
409 
410 #ifdef HAVE_GETGRENT
411 static int group_blocking = 0;
412 static VALUE
413 group_ensure(void)
414 {
415  group_blocking = (int)Qfalse;
416  return Qnil;
417 }
418 
419 static VALUE
420 group_iterate(void)
421 {
422  struct group *pw;
423 
424  setgrent();
425  while (pw = getgrent()) {
426  rb_yield(setup_group(pw));
427  }
428  endgrent();
429  return Qnil;
430 }
431 
432 static void
433 each_group(void)
434 {
435  if (group_blocking) {
436  rb_raise(rb_eRuntimeError, "parallel group iteration");
437  }
438  group_blocking = (int)Qtrue;
439  rb_ensure(group_iterate, 0, group_ensure, 0);
440 }
441 #endif
442 
443 /* Provides a convenient Ruby iterator which executes a block for each entry
444  * in the /etc/group file.
445  *
446  * The code block is passed an Struct::Group struct; see getgrent above for
447  * details.
448  *
449  * Example:
450  *
451  * require 'etc'
452  *
453  * Etc.group {|g|
454  * puts g.name + ": " + g.mem.join(', ')
455  * }
456  *
457  */
458 static VALUE
460 {
461 #ifdef HAVE_GETGRENT
462  struct group *grp;
463 
464  rb_secure(4);
465  if (rb_block_given_p()) {
466  each_group();
467  }
468  else if (grp = getgrent()) {
469  return setup_group(grp);
470  }
471 #endif
472  return Qnil;
473 }
474 
475 #ifdef HAVE_GETGRENT
476 /* Iterates for each entry in the /etc/group file if a block is given.
477  * If no block is given, returns the enumerator.
478  *
479  * The code block is passed an Struct::Group struct; see getpwent above for
480  * details.
481  *
482  * Example:
483  *
484  * require 'etc'
485  *
486  * Etc::Group.each {|g|
487  * puts g.name + ": " + g.mem.join(', ')
488  * }
489  *
490  * Etc::Group.collect {|g| g.name}
491  * Etc::Group.select {|g| !g.mem.empty?}
492  *
493  */
494 static VALUE
495 etc_each_group(VALUE obj)
496 {
497  RETURN_ENUMERATOR(obj, 0, 0);
498  each_group();
499  return obj;
500 }
501 #endif
502 
503 /* Resets the process of reading the /etc/group file, so that the next call
504  * to getgrent will return the first entry again.
505  */
506 static VALUE
508 {
509 #ifdef HAVE_GETGRENT
510  setgrent();
511 #endif
512  return Qnil;
513 }
514 
515 /* Ends the process of scanning through the /etc/group file begun by
516  * getgrent, and closes the file.
517  */
518 static VALUE
520 {
521 #ifdef HAVE_GETGRENT
522  endgrent();
523 #endif
524  return Qnil;
525 }
526 
527 /* Returns an entry from the /etc/group file. The first time it is called it
528  * opens the file and returns the first entry; each successive call returns
529  * the next entry, or nil if the end of the file has been reached.
530  *
531  * To close the file when processing is complete, call endgrent.
532  *
533  * Each entry is returned as a Struct::Group:
534  *
535  * - Group#name contains the name of the group as a String.
536  *
537  * - Group#passwd contains the encrypted password as a String. An 'x' is
538  * returned if password access to the group is not available; an empty
539  * string is returned if no password is needed to obtain membership of
540  * the group.
541  *
542  * - Group#gid contains the group's numeric ID as an integer.
543  *
544  * - Group#mem is an Array of Strings containing the short login names of the
545  * members of the group.
546  */
547 static VALUE
549 {
550 #ifdef HAVE_GETGRENT
551  struct group *gr;
552 
553  if (gr = getgrent()) {
554  return setup_group(gr);
555  }
556 #endif
557  return Qnil;
558 }
559 
560 #define numberof(array) (sizeof(array) / sizeof(*(array)))
561 
562 #ifdef _WIN32
564 UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
565 VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
566 #endif
567 
568 /*
569  * Returns system configuration directory.
570  */
571 static VALUE
573 {
574 #ifdef _WIN32
576 #else
577  return rb_filesystem_str_new_cstr(SYSCONFDIR);
578 #endif
579 }
580 
581 /*
582  * Returns system temporary directory.
583  */
584 static VALUE
586 {
587  VALUE tmpdir;
588 #ifdef _WIN32
589  WCHAR path[_MAX_PATH];
590  UINT len = rb_w32_system_tmpdir(path, numberof(path));
591  if (!len) return Qnil;
593 #else
594  tmpdir = rb_filesystem_str_new_cstr("/tmp");
595 #endif
596  FL_UNSET(tmpdir, FL_TAINT|FL_UNTRUSTED);
597  return tmpdir;
598 }
599 
600 /*
601  * The etc module provides access to information from the running OS.
602  *
603  * Documented by mathew <meta@pobox.com>.
604  */
605 void
606 Init_etc(void)
607 {
608  VALUE mEtc;
609 
610  mEtc = rb_define_module("Etc");
611  rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
612 
613  rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
614  rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1);
615  rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0);
616  rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0);
617  rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0);
618  rb_define_module_function(mEtc, "passwd", etc_passwd, 0);
619 
620  rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, -1);
621  rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1);
622  rb_define_module_function(mEtc, "group", etc_group, 0);
623  rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0);
624  rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
625  rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
626  rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0);
627  rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0);
628 
629  sPasswd = rb_struct_define("Passwd",
630  "name", "passwd", "uid", "gid",
631 #ifdef HAVE_ST_PW_GECOS
632  "gecos",
633 #endif
634  "dir", "shell",
635 #ifdef HAVE_ST_PW_CHANGE
636  "change",
637 #endif
638 #ifdef HAVE_ST_PW_QUOTA
639  "quota",
640 #endif
641 #ifdef HAVE_ST_PW_AGE
642  "age",
643 #endif
644 #ifdef HAVE_ST_PW_CLASS
645  "uclass",
646 #endif
647 #ifdef HAVE_ST_PW_COMMENT
648  "comment",
649 #endif
650 #ifdef HAVE_ST_PW_EXPIRE
651  "expire",
652 #endif
653  NULL);
654  rb_define_const(mEtc, "Passwd", sPasswd);
657 
658 #ifdef HAVE_GETGRENT
659  sGroup = rb_struct_define("Group", "name",
660 #ifdef HAVE_ST_GR_PASSWD
661  "passwd",
662 #endif
663  "gid", "mem", NULL);
664 
665  rb_define_const(mEtc, "Group", sGroup);
667  rb_define_singleton_method(sGroup, "each", etc_each_group, 0);
668 #endif
669 }
#define NUM2UIDT(v)
Definition: ruby.h:321
static VALUE sPasswd
Definition: etc.c:26
static VALUE etc_getpwnam(VALUE obj, VALUE nam)
Definition: etc.c:158
static VALUE etc_endgrent(VALUE obj)
Definition: etc.c:519
static VALUE etc_group(VALUE obj)
Definition: etc.c:459
rb_uid_t getuid(void)
Definition: win32.c:2279
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1343
#define FL_TAINT
Definition: ruby.h:925
static VALUE etc_setpwent(VALUE obj)
Definition: etc.c:269
static VALUE etc_getpwent(VALUE obj)
Definition: etc.c:316
#define Qtrue
Definition: ruby.h:366
static VALUE etc_setgrent(VALUE obj)
Definition: etc.c:507
const int id
Definition: nkf.c:209
VALUE rb_struct_new(VALUE,...)
Definition: struct.c:421
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:740
static VALUE INT2NUM(int v)
Definition: ruby.h:981
#define RSTRING_PTR(string)
Definition: generator.h:42
static VALUE etc_getgrnam(VALUE obj, VALUE nam)
Definition: etc.c:395
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1574
static VALUE etc_systmpdir(void)
Definition: etc.c:585
#define CSIDL_COMMON_APPDATA
Definition: win32.c:416
VALUE rb_tainted_str_new2(const char *)
static VALUE etc_getpwuid(int argc, VALUE *argv, VALUE obj)
Definition: etc.c:127
char * getenv()
#define FL_UNTRUSTED
Definition: ruby.h:926
static VALUE etc_passwd(VALUE obj)
Definition: etc.c:221
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
Definition: win32.c:1861
void Init_etc(void)
Definition: etc.c:606
int rb_block_given_p(void)
Definition: eval.c:604
VALUE rb_eRuntimeError
Definition: error.c:466
VALUE rb_ary_new(void)
Definition: array.c:339
static VALUE etc_getgrgid(int argc, VALUE *argv, VALUE obj)
Definition: etc.c:362
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:1923
int argc
Definition: ruby.c:120
#define Qfalse
Definition: ruby.h:365
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len)
Definition: win32.c:500
#define numberof(array)
Definition: etc.c:560
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1358
VALUE rb_yield(VALUE)
Definition: vm_eval.c:781
VALUE rb_mEnumerable
Definition: enum.c:17
static VALUE etc_getlogin(VALUE obj)
Definition: etc.c:51
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1416
#define Qnil
Definition: ruby.h:367
int type
Definition: tcltklib.c:107
unsigned long VALUE
Definition: ruby.h:88
void rb_extend_object(VALUE obj, VALUE module)
Definition: eval.c:888
#define NUM2GIDT(v)
Definition: ruby.h:327
register unsigned int len
Definition: name2ctype.h:22210
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:737
void rb_sys_fail(const char *mesg)
Definition: error.c:1671
#define FL_UNSET(x, f)
Definition: ruby.h:960
char * getlogin()
Definition: win32.c:703
static VALUE etc_each_passwd(VALUE obj)
Definition: etc.c:256
VALUE rb_w32_special_folder(int type)
Definition: win32.c:490
static VALUE etc_endpwent(VALUE obj)
Definition: etc.c:281
#define GIDT2NUM(v)
Definition: ruby.h:324
rb_encoding * rb_filesystem_encoding(void)
Definition: encoding.c:1205
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: intern.h:210
#define SafeStringValue(v)
Definition: ruby.h:472
VALUE rb_filesystem_str_new_cstr(const char *)
Definition: string.c:579
#define UIDT2NUM(v)
Definition: ruby.h:318
rb_gid_t getgid(void)
Definition: win32.c:2291
void rb_secure(int)
Definition: safe.c:79
VALUE rb_struct_define(const char *,...)
Definition: struct.c:274
VALUE rb_define_module(const char *name)
Definition: class.c:587
#define NULL
Definition: _sdbm.c:107
static VALUE etc_sysconfdir(VALUE obj)
Definition: etc.c:572
VALUE rb_eArgError
Definition: error.c:468
static VALUE etc_getgrent(VALUE obj)
Definition: etc.c:548
char ** argv
Definition: ruby.c:121