Ruby  2.5.0dev(2017-10-22revision60238)
etc.c
Go to the documentation of this file.
1 /************************************************
2 
3  etc.c -
4 
5  $Author$
6  created at: Tue Mar 22 18:39:19 JST 1994
7 
8 ************************************************/
9 
10 #include "ruby.h"
11 #include "ruby/encoding.h"
12 #include "ruby/io.h"
13 
14 #include <sys/types.h>
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 
19 #ifdef HAVE_GETPWENT
20 #include <pwd.h>
21 #endif
22 
23 #ifdef HAVE_GETGRENT
24 #include <grp.h>
25 #endif
26 
27 #include <errno.h>
28 
29 #ifdef HAVE_SYS_UTSNAME_H
30 #include <sys/utsname.h>
31 #endif
32 
33 #ifdef HAVE_SCHED_GETAFFINITY
34 #include <sched.h>
35 #endif
36 
37 static VALUE sPasswd;
38 #ifdef HAVE_GETGRENT
39 static VALUE sGroup;
40 #endif
41 
42 #ifdef _WIN32
43 #include <shlobj.h>
44 #ifndef CSIDL_COMMON_APPDATA
45 #define CSIDL_COMMON_APPDATA 35
46 #endif
47 #define HAVE_UNAME 1
48 #endif
49 
50 #ifndef _WIN32
51 char *getenv();
52 #endif
53 char *getlogin();
54 
55 #include "constdefs.h"
56 
57 /* call-seq:
58  * getlogin -> String
59  *
60  * Returns the short user name of the currently logged in user.
61  * Unfortunately, it is often rather easy to fool ::getlogin.
62  *
63  * Avoid ::getlogin for security-related purposes.
64  *
65  * If ::getlogin fails, try ::getpwuid.
66  *
67  * See the unix manpage for <code>getpwuid(3)</code> for more detail.
68  *
69  * e.g.
70  * Etc.getlogin -> 'guest'
71  */
72 static VALUE
73 etc_getlogin(VALUE obj)
74 {
75  char *login;
76 
77 #ifdef HAVE_GETLOGIN
78  login = getlogin();
79  if (!login) login = getenv("USER");
80 #else
81  login = getenv("USER");
82 #endif
83 
84  if (login) {
85 #ifdef _WIN32
86  rb_encoding *extenc = rb_utf8_encoding();
87 #else
88  rb_encoding *extenc = rb_locale_encoding();
89 #endif
90  return rb_external_str_new_with_enc(login, strlen(login), extenc);
91  }
92 
93  return Qnil;
94 }
95 
96 #if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
97 static VALUE
98 safe_setup_str(const char *str)
99 {
100  if (str == 0) str = "";
101  return rb_tainted_str_new2(str);
102 }
103 
104 static VALUE
105 safe_setup_locale_str(const char *str)
106 {
107  if (str == 0) str = "";
108  return rb_locale_str_new_cstr(str);
109 }
110 
111 static VALUE
112 safe_setup_filesystem_str(const char *str)
113 {
114  if (str == 0) str = "";
115  return rb_filesystem_str_new_cstr(str);
116 }
117 #endif
118 
119 #ifdef HAVE_GETPWENT
120 static VALUE
121 setup_passwd(struct passwd *pwd)
122 {
123  if (pwd == 0) rb_sys_fail("/etc/passwd");
124  return rb_struct_new(sPasswd,
125  safe_setup_locale_str(pwd->pw_name),
126 #ifdef HAVE_STRUCT_PASSWD_PW_PASSWD
127  safe_setup_str(pwd->pw_passwd),
128 #endif
129  UIDT2NUM(pwd->pw_uid),
130  GIDT2NUM(pwd->pw_gid),
131 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
132  safe_setup_locale_str(pwd->pw_gecos),
133 #endif
134  safe_setup_filesystem_str(pwd->pw_dir),
135  safe_setup_filesystem_str(pwd->pw_shell),
136 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
137  INT2NUM(pwd->pw_change),
138 #endif
139 #ifdef HAVE_STRUCT_PASSWD_PW_QUOTA
140  INT2NUM(pwd->pw_quota),
141 #endif
142 #ifdef HAVE_STRUCT_PASSWD_PW_AGE
143  PW_AGE2VAL(pwd->pw_age),
144 #endif
145 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
146  safe_setup_locale_str(pwd->pw_class),
147 #endif
148 #ifdef HAVE_STRUCT_PASSWD_PW_COMMENT
149  safe_setup_locale_str(pwd->pw_comment),
150 #endif
151 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
152  INT2NUM(pwd->pw_expire),
153 #endif
154  0 /*dummy*/
155  );
156 }
157 #endif
158 
159 /* call-seq:
160  * getpwuid(uid) -> Passwd
161  *
162  * Returns the /etc/passwd information for the user with the given integer +uid+.
163  *
164  * The information is returned as a Passwd struct.
165  *
166  * If +uid+ is omitted, the value from <code>Passwd[:uid]</code> is returned
167  * instead.
168  *
169  * See the unix manpage for <code>getpwuid(3)</code> for more detail.
170  *
171  * === Example:
172  *
173  * Etc.getpwuid(0)
174  * #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
175  */
176 static VALUE
177 etc_getpwuid(int argc, VALUE *argv, VALUE obj)
178 {
179 #if defined(HAVE_GETPWENT)
180  VALUE id;
181  rb_uid_t uid;
182  struct passwd *pwd;
183 
184  if (rb_scan_args(argc, argv, "01", &id) == 1) {
185  uid = NUM2UIDT(id);
186  }
187  else {
188  uid = getuid();
189  }
190  pwd = getpwuid(uid);
191  if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", (int)uid);
192  return setup_passwd(pwd);
193 #else
194  return Qnil;
195 #endif
196 }
197 
198 /* call-seq:
199  * getpwnam(name) -> Passwd
200  *
201  * Returns the /etc/passwd information for the user with specified login
202  * +name+.
203  *
204  * The information is returned as a Passwd struct.
205  *
206  * See the unix manpage for <code>getpwnam(3)</code> for more detail.
207  *
208  * === Example:
209  *
210  * Etc.getpwnam('root')
211  * #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
212  */
213 static VALUE
214 etc_getpwnam(VALUE obj, VALUE nam)
215 {
216 #ifdef HAVE_GETPWENT
217  struct passwd *pwd;
218  const char *p = StringValueCStr(nam);
219 
220  rb_check_safe_obj(nam);
221  pwd = getpwnam(p);
222  if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, nam);
223  return setup_passwd(pwd);
224 #else
225  return Qnil;
226 #endif
227 }
228 
229 #ifdef HAVE_GETPWENT
230 static int passwd_blocking = 0;
231 static VALUE
232 passwd_ensure(void)
233 {
234  endpwent();
235  passwd_blocking = (int)Qfalse;
236  return Qnil;
237 }
238 
239 static VALUE
240 passwd_iterate(void)
241 {
242  struct passwd *pw;
243 
244  setpwent();
245  while ((pw = getpwent()) != 0) {
246  rb_yield(setup_passwd(pw));
247  }
248  return Qnil;
249 }
250 
251 static void
252 each_passwd(void)
253 {
254  if (passwd_blocking) {
255  rb_raise(rb_eRuntimeError, "parallel passwd iteration");
256  }
257  passwd_blocking = (int)Qtrue;
258  rb_ensure(passwd_iterate, 0, passwd_ensure, 0);
259 }
260 #endif
261 
262 /* call-seq:
263  * Etc.passwd { |struct| block } -> Passwd
264  * Etc.passwd -> Passwd
265  *
266  * Provides a convenient Ruby iterator which executes a block for each entry
267  * in the /etc/passwd file.
268  *
269  * The code block is passed an Passwd struct.
270  *
271  * See ::getpwent above for details.
272  *
273  * Example:
274  *
275  * require 'etc'
276  *
277  * Etc.passwd {|u|
278  * puts u.name + " = " + u.gecos
279  * }
280  *
281  */
282 static VALUE
283 etc_passwd(VALUE obj)
284 {
285 #ifdef HAVE_GETPWENT
286  struct passwd *pw;
287 
288  if (rb_block_given_p()) {
289  each_passwd();
290  }
291  else if ((pw = getpwent()) != 0) {
292  return setup_passwd(pw);
293  }
294 #endif
295  return Qnil;
296 }
297 
298 /* call-seq:
299  * Etc::Passwd.each { |struct| block } -> Passwd
300  * Etc::Passwd.each -> Enumerator
301  *
302  * Iterates for each entry in the /etc/passwd file if a block is given.
303  *
304  * If no block is given, returns the Enumerator.
305  *
306  * The code block is passed an Passwd struct.
307  *
308  * See ::getpwent above for details.
309  *
310  * Example:
311  *
312  * require 'etc'
313  *
314  * Etc::Passwd.each {|u|
315  * puts u.name + " = " + u.gecos
316  * }
317  *
318  * Etc::Passwd.collect {|u| u.gecos}
319  * Etc::Passwd.collect {|u| u.gecos}
320  *
321  */
322 static VALUE
323 etc_each_passwd(VALUE obj)
324 {
325 #ifdef HAVE_GETPWENT
326  RETURN_ENUMERATOR(obj, 0, 0);
327  each_passwd();
328 #endif
329  return obj;
330 }
331 
332 /* Resets the process of reading the /etc/passwd file, so that the next call
333  * to ::getpwent will return the first entry again.
334  */
335 static VALUE
336 etc_setpwent(VALUE obj)
337 {
338 #ifdef HAVE_GETPWENT
339  setpwent();
340 #endif
341  return Qnil;
342 }
343 
344 /* Ends the process of scanning through the /etc/passwd file begun with
345  * ::getpwent, and closes the file.
346  */
347 static VALUE
348 etc_endpwent(VALUE obj)
349 {
350 #ifdef HAVE_GETPWENT
351  endpwent();
352 #endif
353  return Qnil;
354 }
355 
356 /* Returns an entry from the /etc/passwd file.
357  *
358  * The first time it is called it opens the file and returns the first entry;
359  * each successive call returns the next entry, or +nil+ if the end of the file
360  * has been reached.
361  *
362  * To close the file when processing is complete, call ::endpwent.
363  *
364  * Each entry is returned as a Passwd struct.
365  *
366  */
367 static VALUE
368 etc_getpwent(VALUE obj)
369 {
370 #ifdef HAVE_GETPWENT
371  struct passwd *pw;
372 
373  if ((pw = getpwent()) != 0) {
374  return setup_passwd(pw);
375  }
376 #endif
377  return Qnil;
378 }
379 
380 #ifdef HAVE_GETGRENT
381 static VALUE
382 setup_group(struct group *grp)
383 {
384  VALUE mem;
385  char **tbl;
386 
387  mem = rb_ary_new();
388  tbl = grp->gr_mem;
389  while (*tbl) {
390  rb_ary_push(mem, safe_setup_locale_str(*tbl));
391  tbl++;
392  }
393  return rb_struct_new(sGroup,
394  safe_setup_locale_str(grp->gr_name),
395 #ifdef HAVE_STRUCT_GROUP_GR_PASSWD
396  safe_setup_str(grp->gr_passwd),
397 #endif
398  GIDT2NUM(grp->gr_gid),
399  mem);
400 }
401 #endif
402 
403 /* call-seq:
404  * getgrgid(group_id) -> Group
405  *
406  * Returns information about the group with specified integer +group_id+,
407  * as found in /etc/group.
408  *
409  * The information is returned as a Group struct.
410  *
411  * See the unix manpage for <code>getgrgid(3)</code> for more detail.
412  *
413  * === Example:
414  *
415  * Etc.getgrgid(100)
416  * #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
417  *
418  */
419 static VALUE
420 etc_getgrgid(int argc, VALUE *argv, VALUE obj)
421 {
422 #ifdef HAVE_GETGRENT
423  VALUE id;
424  gid_t gid;
425  struct group *grp;
426 
427  if (rb_scan_args(argc, argv, "01", &id) == 1) {
428  gid = NUM2GIDT(id);
429  }
430  else {
431  gid = getgid();
432  }
433  grp = getgrgid(gid);
434  if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", (int)gid);
435  return setup_group(grp);
436 #else
437  return Qnil;
438 #endif
439 }
440 
441 /* call-seq:
442  * getgrnam(name) -> Group
443  *
444  * Returns information about the group with specified +name+, as found in
445  * /etc/group.
446  *
447  * The information is returned as a Group struct.
448  *
449  * See the unix manpage for <code>getgrnam(3)</code> for more detail.
450  *
451  * === Example:
452  *
453  * Etc.getgrnam('users')
454  * #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
455  *
456  */
457 static VALUE
458 etc_getgrnam(VALUE obj, VALUE nam)
459 {
460 #ifdef HAVE_GETGRENT
461  struct group *grp;
462  const char *p = StringValueCStr(nam);
463 
464  rb_check_safe_obj(nam);
465  grp = getgrnam(p);
466  if (grp == 0) rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, nam);
467  return setup_group(grp);
468 #else
469  return Qnil;
470 #endif
471 }
472 
473 #ifdef HAVE_GETGRENT
474 static int group_blocking = 0;
475 static VALUE
476 group_ensure(void)
477 {
478  endgrent();
479  group_blocking = (int)Qfalse;
480  return Qnil;
481 }
482 
483 
484 static VALUE
485 group_iterate(void)
486 {
487  struct group *pw;
488 
489  setgrent();
490  while ((pw = getgrent()) != 0) {
491  rb_yield(setup_group(pw));
492  }
493  return Qnil;
494 }
495 
496 static void
497 each_group(void)
498 {
499  if (group_blocking) {
500  rb_raise(rb_eRuntimeError, "parallel group iteration");
501  }
502  group_blocking = (int)Qtrue;
503  rb_ensure(group_iterate, 0, group_ensure, 0);
504 }
505 #endif
506 
507 /* Provides a convenient Ruby iterator which executes a block for each entry
508  * in the /etc/group file.
509  *
510  * The code block is passed an Group struct.
511  *
512  * See ::getgrent above for details.
513  *
514  * Example:
515  *
516  * require 'etc'
517  *
518  * Etc.group {|g|
519  * puts g.name + ": " + g.mem.join(', ')
520  * }
521  *
522  */
523 static VALUE
524 etc_group(VALUE obj)
525 {
526 #ifdef HAVE_GETGRENT
527  struct group *grp;
528 
529  if (rb_block_given_p()) {
530  each_group();
531  }
532  else if ((grp = getgrent()) != 0) {
533  return setup_group(grp);
534  }
535 #endif
536  return Qnil;
537 }
538 
539 #ifdef HAVE_GETGRENT
540 /* call-seq:
541  * Etc::Group.each { |group| block } -> obj
542  * Etc::Group.each -> Enumerator
543  *
544  * Iterates for each entry in the /etc/group file if a block is given.
545  *
546  * If no block is given, returns the Enumerator.
547  *
548  * The code block is passed a Group struct.
549  *
550  * Example:
551  *
552  * require 'etc'
553  *
554  * Etc::Group.each {|g|
555  * puts g.name + ": " + g.mem.join(', ')
556  * }
557  *
558  * Etc::Group.collect {|g| g.name}
559  * Etc::Group.select {|g| !g.mem.empty?}
560  *
561  */
562 static VALUE
563 etc_each_group(VALUE obj)
564 {
565  RETURN_ENUMERATOR(obj, 0, 0);
566  each_group();
567  return obj;
568 }
569 #endif
570 
571 /* Resets the process of reading the /etc/group file, so that the next call
572  * to ::getgrent will return the first entry again.
573  */
574 static VALUE
575 etc_setgrent(VALUE obj)
576 {
577 #ifdef HAVE_GETGRENT
578  setgrent();
579 #endif
580  return Qnil;
581 }
582 
583 /* Ends the process of scanning through the /etc/group file begun by
584  * ::getgrent, and closes the file.
585  */
586 static VALUE
587 etc_endgrent(VALUE obj)
588 {
589 #ifdef HAVE_GETGRENT
590  endgrent();
591 #endif
592  return Qnil;
593 }
594 
595 /* Returns an entry from the /etc/group file.
596  *
597  * The first time it is called it opens the file and returns the first entry;
598  * each successive call returns the next entry, or +nil+ if the end of the file
599  * has been reached.
600  *
601  * To close the file when processing is complete, call ::endgrent.
602  *
603  * Each entry is returned as a Group struct
604  */
605 static VALUE
606 etc_getgrent(VALUE obj)
607 {
608 #ifdef HAVE_GETGRENT
609  struct group *gr;
610 
611  if ((gr = getgrent()) != 0) {
612  return setup_group(gr);
613  }
614 #endif
615  return Qnil;
616 }
617 
618 #define numberof(array) (sizeof(array) / sizeof(*(array)))
619 
620 #ifdef _WIN32
621 VALUE rb_w32_special_folder(int type);
622 UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
623 VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
624 #endif
625 
626 /*
627  * Returns system configuration directory.
628  *
629  * This is typically "/etc", but is modified by the prefix used when Ruby was
630  * compiled. For example, if Ruby is built and installed in /usr/local, returns
631  * "/usr/local/etc" on other than Windows. On Windows, this returns system
632  * provided directory always.
633  */
634 static VALUE
635 etc_sysconfdir(VALUE obj)
636 {
637 #ifdef _WIN32
639 #else
640  return rb_filesystem_str_new_cstr(SYSCONFDIR);
641 #endif
642 }
643 
644 /*
645  * Returns system temporary directory; typically "/tmp".
646  */
647 static VALUE
648 etc_systmpdir(void)
649 {
650  VALUE tmpdir;
651 #ifdef _WIN32
652  WCHAR path[_MAX_PATH];
653  UINT len = rb_w32_system_tmpdir(path, numberof(path));
654  if (!len) return Qnil;
656 #else
657  const char default_tmp[] = "/tmp";
658  const char *tmpstr = default_tmp;
659  size_t tmplen = strlen(default_tmp);
660 # if defined _CS_DARWIN_USER_TEMP_DIR
661  #ifndef MAXPATHLEN
662  #define MAXPATHLEN 1024
663  #endif
664  char path[MAXPATHLEN];
665  size_t len;
666  len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
667  if (len > 0) {
668  tmpstr = path;
669  tmplen = len - 1;
670  if (len > sizeof(path)) tmpstr = 0;
671  }
672 # endif
673  tmpdir = rb_filesystem_str_new(tmpstr, tmplen);
674 # if defined _CS_DARWIN_USER_TEMP_DIR
675  if (!tmpstr) {
676  confstr(_CS_DARWIN_USER_TEMP_DIR, RSTRING_PTR(tmpdir), len);
677  }
678 # endif
679 #endif
680  FL_UNSET(tmpdir, FL_TAINT);
681  return tmpdir;
682 }
683 
684 #ifdef HAVE_UNAME
685 /*
686  * Returns the system information obtained by uname system call.
687  *
688  * The return value is a hash which has 5 keys at least:
689  * :sysname, :nodename, :release, :version, :machine
690  *
691  * Example:
692  *
693  * require 'etc'
694  * require 'pp'
695  *
696  * pp Etc.uname
697  * #=> {:sysname=>"Linux",
698  * # :nodename=>"boron",
699  * # :release=>"2.6.18-6-xen-686",
700  * # :version=>"#1 SMP Thu Nov 5 19:54:42 UTC 2009",
701  * # :machine=>"i686"}
702  *
703  */
704 static VALUE
705 etc_uname(VALUE obj)
706 {
707 #ifdef _WIN32
708  OSVERSIONINFOW v;
709  SYSTEM_INFO s;
710  const char *sysname, *mach;
711  VALUE result, release, version;
712  VALUE vbuf, nodename = Qnil;
713  DWORD len = 0;
714  WCHAR *buf;
715 
716  v.dwOSVersionInfoSize = sizeof(v);
717  if (!GetVersionExW(&v))
718  rb_sys_fail("GetVersionEx");
719 
720  result = rb_hash_new();
721  switch (v.dwPlatformId) {
722  case VER_PLATFORM_WIN32s:
723  sysname = "Win32s";
724  break;
725  case VER_PLATFORM_WIN32_NT:
726  sysname = "Windows_NT";
727  break;
728  case VER_PLATFORM_WIN32_WINDOWS:
729  default:
730  sysname = "Windows";
731  break;
732  }
733  rb_hash_aset(result, ID2SYM(rb_intern("sysname")), rb_str_new_cstr(sysname));
734  release = rb_sprintf("%lu.%lu.%lu", v.dwMajorVersion, v.dwMinorVersion, v.dwBuildNumber);
735  rb_hash_aset(result, ID2SYM(rb_intern("release")), release);
736  version = rb_sprintf("%s Version %"PRIsVALUE": %"PRIsVALUE, sysname, release,
737  rb_w32_conv_from_wchar(v.szCSDVersion, rb_utf8_encoding()));
738  rb_hash_aset(result, ID2SYM(rb_intern("version")), version);
739 
740 # if defined _MSC_VER && _MSC_VER < 1300
741 # define GET_COMPUTER_NAME(ptr, plen) GetComputerNameW(ptr, plen)
742 # else
743 # define GET_COMPUTER_NAME(ptr, plen) GetComputerNameExW(ComputerNameDnsFullyQualified, ptr, plen)
744 # endif
745  GET_COMPUTER_NAME(NULL, &len);
746  buf = ALLOCV_N(WCHAR, vbuf, len);
747  if (GET_COMPUTER_NAME(buf, &len)) {
748  nodename = rb_w32_conv_from_wchar(buf, rb_utf8_encoding());
749  }
750  ALLOCV_END(vbuf);
751  if (NIL_P(nodename)) nodename = rb_str_new(0, 0);
752  rb_hash_aset(result, ID2SYM(rb_intern("nodename")), nodename);
753 
754 # ifndef PROCESSOR_ARCHITECTURE_AMD64
755 # define PROCESSOR_ARCHITECTURE_AMD64 9
756 # endif
757 # ifndef PROCESSOR_ARCHITECTURE_IA64
758 # define PROCESSOR_ARCHITECTURE_IA64 6
759 # endif
760 # ifndef PROCESSOR_ARCHITECTURE_INTEL
761 # define PROCESSOR_ARCHITECTURE_INTEL 0
762 # endif
763  GetSystemInfo(&s);
764  switch (s.wProcessorArchitecture) {
765  case PROCESSOR_ARCHITECTURE_AMD64:
766  mach = "x64";
767  break;
768  case PROCESSOR_ARCHITECTURE_ARM:
769  mach = "ARM";
770  break;
771  case PROCESSOR_ARCHITECTURE_IA64:
772  mach = "IA64";
773  break;
774  case PROCESSOR_ARCHITECTURE_INTEL:
775  mach = "x86";
776  break;
777  default:
778  mach = "unknown";
779  break;
780  }
781 
782  rb_hash_aset(result, ID2SYM(rb_intern("machine")), rb_str_new_cstr(mach));
783 #else
784  struct utsname u;
785  int ret;
786  VALUE result;
787 
788  ret = uname(&u);
789  if (ret == -1)
790  rb_sys_fail("uname");
791 
792  result = rb_hash_new();
793  rb_hash_aset(result, ID2SYM(rb_intern("sysname")), rb_str_new_cstr(u.sysname));
794  rb_hash_aset(result, ID2SYM(rb_intern("nodename")), rb_str_new_cstr(u.nodename));
795  rb_hash_aset(result, ID2SYM(rb_intern("release")), rb_str_new_cstr(u.release));
796  rb_hash_aset(result, ID2SYM(rb_intern("version")), rb_str_new_cstr(u.version));
797  rb_hash_aset(result, ID2SYM(rb_intern("machine")), rb_str_new_cstr(u.machine));
798 #endif
799 
800  return result;
801 }
802 #else
803 #define etc_uname rb_f_notimplement
804 #endif
805 
806 #ifdef HAVE_SYSCONF
807 /*
808  * Returns system configuration variable using sysconf().
809  *
810  * _name_ should be a constant under <code>Etc</code> which begins with <code>SC_</code>.
811  *
812  * The return value is an integer or nil.
813  * nil means indefinite limit. (sysconf() returns -1 but errno is not set.)
814  *
815  * Etc.sysconf(Etc::SC_ARG_MAX) #=> 2097152
816  * Etc.sysconf(Etc::SC_LOGIN_NAME_MAX) #=> 256
817  *
818  */
819 static VALUE
820 etc_sysconf(VALUE obj, VALUE arg)
821 {
822  int name;
823  long ret;
824 
825  name = NUM2INT(arg);
826 
827  errno = 0;
828  ret = sysconf(name);
829  if (ret == -1) {
830  if (errno == 0) /* no limit */
831  return Qnil;
832  rb_sys_fail("sysconf");
833  }
834  return LONG2NUM(ret);
835 }
836 #else
837 #define etc_sysconf rb_f_notimplement
838 #endif
839 
840 #ifdef HAVE_CONFSTR
841 /*
842  * Returns system configuration variable using confstr().
843  *
844  * _name_ should be a constant under <code>Etc</code> which begins with <code>CS_</code>.
845  *
846  * The return value is a string or nil.
847  * nil means no configuration-defined value. (confstr() returns 0 but errno is not set.)
848  *
849  * Etc.confstr(Etc::CS_PATH) #=> "/bin:/usr/bin"
850  *
851  * # GNU/Linux
852  * Etc.confstr(Etc::CS_GNU_LIBC_VERSION) #=> "glibc 2.18"
853  * Etc.confstr(Etc::CS_GNU_LIBPTHREAD_VERSION) #=> "NPTL 2.18"
854  *
855  */
856 static VALUE
857 etc_confstr(VALUE obj, VALUE arg)
858 {
859  int name;
860  char localbuf[128], *buf = localbuf;
861  size_t bufsize = sizeof(localbuf), ret;
862  VALUE tmp;
863 
864  name = NUM2INT(arg);
865 
866  errno = 0;
867  ret = confstr(name, buf, bufsize);
868  if (bufsize < ret) {
869  bufsize = ret;
870  buf = ALLOCV_N(char, tmp, bufsize);
871  errno = 0;
872  ret = confstr(name, buf, bufsize);
873  }
874  if (bufsize < ret)
875  rb_bug("required buffer size for confstr() changed dynamically.");
876  if (ret == 0) {
877  if (errno == 0) /* no configuration-defined value */
878  return Qnil;
879  rb_sys_fail("confstr");
880  }
881  return rb_str_new_cstr(buf);
882 }
883 #else
884 #define etc_confstr rb_f_notimplement
885 #endif
886 
887 #ifdef HAVE_FPATHCONF
888 /*
889  * Returns pathname configuration variable using fpathconf().
890  *
891  * _name_ should be a constant under <code>Etc</code> which begins with <code>PC_</code>.
892  *
893  * The return value is an integer or nil.
894  * nil means indefinite limit. (fpathconf() returns -1 but errno is not set.)
895  *
896  * require 'etc'
897  * IO.pipe {|r, w|
898  * p w.pathconf(Etc::PC_PIPE_BUF) #=> 4096
899  * }
900  *
901  */
902 static VALUE
903 io_pathconf(VALUE io, VALUE arg)
904 {
905  int name;
906  long ret;
907  rb_io_t *fptr;
908 
909  name = NUM2INT(arg);
910 
911  GetOpenFile(io, fptr);
912 
913  errno = 0;
914  ret = fpathconf(fptr->fd, name);
915  if (ret == -1) {
916  if (errno == 0) /* no limit */
917  return Qnil;
918  rb_sys_fail("fpathconf");
919  }
920  return LONG2NUM(ret);
921 }
922 #else
923 #define io_pathconf rb_f_notimplement
924 #endif
925 
926 #if (defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)) || defined(_WIN32)
927 
928 #if defined(HAVE_SCHED_GETAFFINITY) && defined(CPU_ALLOC)
929 static int
930 etc_nprocessors_affin(void)
931 {
932  cpu_set_t *cpuset;
933  size_t size;
934  int ret;
935  int n;
936 
937  /*
938  * XXX:
939  * man page says CPU_ALLOC takes number of cpus. But it is not accurate
940  * explanation. sched_getaffinity() returns EINVAL if cpuset bitmap is
941  * smaller than kernel internal bitmap.
942  * That said, sched_getaffinity() can fail when a kernel have sparse bitmap
943  * even if cpuset bitmap is larger than number of cpus.
944  * The precious way is to use /sys/devices/system/cpu/online. But there are
945  * two problems,
946  * - Costly calculation
947  * It is a minor issue, but possibly kill a benefit of a parallel processing.
948  * - No guarantee to exist /sys/devices/system/cpu/online
949  * This is an issue especially when using Linux containers.
950  * So, we use hardcode number for a workaround. Current linux kernel
951  * (Linux 3.17) support 8192 cpus at maximum. Then 16384 must be enough.
952  */
953  for (n=64; n <= 16384; n *= 2) {
954  size = CPU_ALLOC_SIZE(n);
955  if (size >= 1024) {
956  cpuset = xcalloc(1, size);
957  if (!cpuset)
958  return -1;
959  } else {
960  cpuset = alloca(size);
961  CPU_ZERO_S(size, cpuset);
962  }
963 
964  ret = sched_getaffinity(0, size, cpuset);
965  if (ret == 0) {
966  /* On success, count number of cpus. */
967  ret = CPU_COUNT_S(size, cpuset);
968  }
969 
970  if (size >= 1024) {
971  xfree(cpuset);
972  }
973  if (ret > 0) {
974  return ret;
975  }
976  }
977 
978  return ret;
979 }
980 #endif
981 
982 /*
983  * Returns the number of online processors.
984  *
985  * The result is intended as the number of processes to
986  * use all available processors.
987  *
988  * This method is implemented using:
989  * - sched_getaffinity(): Linux
990  * - sysconf(_SC_NPROCESSORS_ONLN): GNU/Linux, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, OpenIndiana, Mac OS X, AIX
991  *
992  * Example:
993  *
994  * require 'etc'
995  * p Etc.nprocessors #=> 4
996  *
997  * The result might be smaller number than physical cpus especially when ruby
998  * process is bound to specific cpus. This is intended for getting better
999  * parallel processing.
1000  *
1001  * Example: (Linux)
1002  *
1003  * linux$ taskset 0x3 ./ruby -retc -e "p Etc.nprocessors" #=> 2
1004  *
1005  */
1006 static VALUE
1008 {
1009  long ret;
1010 
1011 #if !defined(_WIN32)
1012 
1013 #if defined(HAVE_SCHED_GETAFFINITY) && defined(CPU_ALLOC)
1014  int ncpus;
1015 
1016  ncpus = etc_nprocessors_affin();
1017  if (ncpus != -1) {
1018  return INT2NUM(ncpus);
1019  }
1020  /* fallback to _SC_NPROCESSORS_ONLN */
1021 #endif
1022 
1023  errno = 0;
1024  ret = sysconf(_SC_NPROCESSORS_ONLN);
1025  if (ret == -1) {
1026  rb_sys_fail("sysconf(_SC_NPROCESSORS_ONLN)");
1027  }
1028 #else
1029  SYSTEM_INFO si;
1030  GetSystemInfo(&si);
1031  ret = (long)si.dwNumberOfProcessors;
1032 #endif
1033  return LONG2NUM(ret);
1034 }
1035 #else
1036 #define etc_nprocessors rb_f_notimplement
1037 #endif
1038 
1039 /*
1040  * The Etc module provides access to information typically stored in
1041  * files in the /etc directory on Unix systems.
1042  *
1043  * The information accessible consists of the information found in the
1044  * /etc/passwd and /etc/group files, plus information about the system's
1045  * temporary directory (/tmp) and configuration directory (/etc).
1046  *
1047  * The Etc module provides a more reliable way to access information about
1048  * the logged in user than environment variables such as +$USER+.
1049  *
1050  * == Example:
1051  *
1052  * require 'etc'
1053  *
1054  * login = Etc.getlogin
1055  * info = Etc.getpwnam(login)
1056  * username = info.gecos.split(/,/).first
1057  * puts "Hello #{username}, I see your login name is #{login}"
1058  *
1059  * Note that the methods provided by this module are not always secure.
1060  * It should be used for informational purposes, and not for security.
1061  *
1062  * All operations defined in this module are class methods, so that you can
1063  * include the Etc module into your class.
1064  */
1065 void
1067 {
1068  VALUE mEtc;
1069 
1070  mEtc = rb_define_module("Etc");
1071  init_constants(mEtc);
1072 
1073  rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
1074 
1075  rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
1076  rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1);
1077  rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0);
1078  rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0);
1079  rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0);
1080  rb_define_module_function(mEtc, "passwd", etc_passwd, 0);
1081 
1082  rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, -1);
1083  rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1);
1084  rb_define_module_function(mEtc, "group", etc_group, 0);
1085  rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0);
1086  rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
1087  rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
1088  rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0);
1089  rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0);
1090  rb_define_module_function(mEtc, "uname", etc_uname, 0);
1091  rb_define_module_function(mEtc, "sysconf", etc_sysconf, 1);
1092  rb_define_module_function(mEtc, "confstr", etc_confstr, 1);
1093  rb_define_method(rb_cIO, "pathconf", io_pathconf, 1);
1094  rb_define_module_function(mEtc, "nprocessors", etc_nprocessors, 0);
1095 
1096  sPasswd = rb_struct_define_under(mEtc, "Passwd",
1097  "name",
1098 #ifdef HAVE_STRUCT_PASSWD_PW_PASSWD
1099  "passwd",
1100 #endif
1101  "uid",
1102  "gid",
1103 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
1104  "gecos",
1105 #endif
1106  "dir",
1107  "shell",
1108 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
1109  "change",
1110 #endif
1111 #ifdef HAVE_STRUCT_PASSWD_PW_QUOTA
1112  "quota",
1113 #endif
1114 #ifdef HAVE_STRUCT_PASSWD_PW_AGE
1115  "age",
1116 #endif
1117 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
1118  "uclass",
1119 #endif
1120 #ifdef HAVE_STRUCT_PASSWD_PW_COMMENT
1121  "comment",
1122 #endif
1123 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
1124  "expire",
1125 #endif
1126  NULL);
1127 #if 0
1128  /* Define-const: Passwd
1129  *
1130  * Passwd is a Struct that contains the following members:
1131  *
1132  * name::
1133  * contains the short login name of the user as a String.
1134  * passwd::
1135  * contains the encrypted password of the user as a String.
1136  * an 'x' is returned if shadow passwords are in use. An '*' is returned
1137  * if the user cannot log in using a password.
1138  * uid::
1139  * contains the integer user ID (uid) of the user.
1140  * gid::
1141  * contains the integer group ID (gid) of the user's primary group.
1142  * dir::
1143  * contains the path to the home directory of the user as a String.
1144  * shell::
1145  * contains the path to the login shell of the user as a String.
1146  *
1147  * === The following members below are optional, and must be compiled with special flags:
1148  *
1149  * gecos::
1150  * contains a longer String description of the user, such as
1151  * a full name. Some Unix systems provide structured information in the
1152  * gecos field, but this is system-dependent.
1153  * must be compiled with +HAVE_STRUCT_PASSWD_PW_GECOS+
1154  * change::
1155  * password change time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_CHANGE+
1156  * quota::
1157  * quota value(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_QUOTA+
1158  * age::
1159  * password age(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_AGE+
1160  * class::
1161  * user access class(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_CLASS+
1162  * comment::
1163  * comment(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_COMMENT+
1164  * expire::
1165  * account expiration time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_EXPIRE+
1166  */
1167  rb_define_const(mEtc, "Passwd", sPasswd);
1168 #endif
1169  rb_define_const(rb_cStruct, "Passwd", sPasswd); /* deprecated name */
1170  rb_extend_object(sPasswd, rb_mEnumerable);
1171  rb_define_singleton_method(sPasswd, "each", etc_each_passwd, 0);
1172 
1173 #ifdef HAVE_GETGRENT
1174  sGroup = rb_struct_define_under(mEtc, "Group", "name",
1175 #ifdef HAVE_STRUCT_GROUP_GR_PASSWD
1176  "passwd",
1177 #endif
1178  "gid", "mem", NULL);
1179 
1180 #if 0
1181  /* Define-const: Group
1182  *
1183  * Group is a Struct that is only available when compiled with +HAVE_GETGRENT+.
1184  *
1185  * The struct contains the following members:
1186  *
1187  * name::
1188  * contains the name of the group as a String.
1189  * passwd::
1190  * contains the encrypted password as a String. An 'x' is
1191  * returned if password access to the group is not available; an empty
1192  * string is returned if no password is needed to obtain membership of
1193  * the group.
1194  *
1195  * Must be compiled with +HAVE_STRUCT_GROUP_GR_PASSWD+.
1196  * gid::
1197  * contains the group's numeric ID as an integer.
1198  * mem::
1199  * is an Array of Strings containing the short login names of the
1200  * members of the group.
1201  */
1202  rb_define_const(mEtc, "Group", sGroup);
1203 #endif
1204  rb_define_const(rb_cStruct, "Group", sGroup); /* deprecated name */
1206  rb_define_singleton_method(sGroup, "each", etc_each_group, 0);
1207 #endif
1208 }
#define NUM2UIDT(v)
Definition: ruby.h:332
void rb_bug(const char *fmt,...)
Definition: error.c:521
size_t strlen(const char *)
#define INT2NUM(x)
Definition: ruby.h:1538
#define NUM2INT(x)
Definition: ruby.h:684
rb_uid_t getuid(void)
Definition: win32.c:2710
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1716
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:835
#define MAXPATHLEN
Definition: dln.c:68
#define FL_TAINT
Definition: ruby.h:1213
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2284
#define Qtrue
Definition: ruby.h:437
Definition: io.h:62
const int id
Definition: nkf.c:209
VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *)
Definition: string.c:1008
VALUE rb_struct_new(VALUE,...)
Definition: struct.c:605
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:924
#define CSIDL_COMMON_APPDATA
Definition: win32.c:420
#define FL_UNSET(x, f)
Definition: ruby.h:1290
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1035
rb_encoding * rb_utf8_encoding(void)
Definition: encoding.c:1320
#define GetOpenFile(obj, fp)
Definition: io.h:120
VALUE rb_struct_define_under(VALUE, const char *,...)
Definition: struct.c:425
VALUE rb_eArgError
Definition: error.c:802
char * getenv()
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
Definition: win32.c:2174
void Init_etc(void)
Definition: etc.c:1066
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:1616
#define io_pathconf
Definition: etc.c:923
IUnknown DWORD
Definition: win32ole.c:32
VALUE rb_ary_new(void)
Definition: array.c:499
#define NIL_P(v)
Definition: ruby.h:451
int fd
Definition: io.h:64
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2691
int argc
Definition: ruby.c:187
#define Qfalse
Definition: ruby.h:436
#define ALLOCV_N(type, v, n)
Definition: ruby.h:1657
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len)
Definition: win32.c:515
#define ALLOCV_END(v)
Definition: ruby.h:1658
#define numberof(array)
Definition: etc.c:618
void rb_sys_fail(const char *mesg)
Definition: error.c:2403
RUBY_EXTERN VALUE rb_cIO
Definition: ruby.h:1913
VALUE rb_locale_str_new_cstr(const char *)
Definition: string.c:1073
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1731
VALUE rb_yield(VALUE)
Definition: vm_eval.c:973
int errno
VALUE rb_mEnumerable
Definition: enum.c:19
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1452
VALUE rb_hash_new(void)
Definition: hash.c:424
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1908
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4309
#define PRIsVALUE
Definition: ruby.h:135
#define Qnil
Definition: ruby.h:438
unsigned long VALUE
Definition: ruby.h:85
rb_encoding * rb_locale_encoding(void)
Definition: encoding.c:1370
#define etc_confstr
Definition: etc.c:884
#define NUM2GIDT(v)
Definition: ruby.h:338
VALUE rb_str_new_cstr(const char *)
Definition: string.c:771
#define rb_tainted_str_new2
Definition: intern.h:839
#define etc_sysconf
Definition: etc.c:837
#define LONG2NUM(x)
Definition: ruby.h:1573
register unsigned int len
Definition: zonetab.h:51
#define StringValueCStr(v)
Definition: ruby.h:571
#define endpwent()
#define RSTRING_PTR(str)
Definition: ruby.h:975
char * getlogin()
Definition: win32.c:867
int size
Definition: encoding.c:57
RUBY_EXTERN VALUE rb_cStruct
Definition: ruby.h:1928
VALUE rb_w32_special_folder(int type)
Definition: win32.c:499
VALUE rb_eRuntimeError
Definition: error.c:800
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
Definition: eval.c:1596
#define GIDT2NUM(v)
Definition: ruby.h:335
void rb_check_safe_obj(VALUE)
Definition: safe.c:117
rb_encoding * rb_filesystem_encoding(void)
Definition: encoding.c:1385
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: intern.h:238
VALUE rb_filesystem_str_new_cstr(const char *)
Definition: string.c:1085
#define etc_uname
Definition: etc.c:803
const char * name
Definition: nkf.c:208
#define ID2SYM(x)
Definition: ruby.h:383
RUBY_SYMBOL_EXPORT_BEGIN void * alloca()
#define UIDT2NUM(v)
Definition: ruby.h:329
rb_gid_t getgid(void)
Definition: win32.c:2724
#define etc_nprocessors
Definition: etc.c:1036
void void xfree(void *)
VALUE rb_define_module(const char *name)
Definition: class.c:768
#define rb_intern(str)
#define NULL
Definition: _sdbm.c:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
char ** argv
Definition: ruby.c:188
VALUE rb_filesystem_str_new(const char *, long)
Definition: string.c:1079
VALUE rb_str_new(const char *, long)
Definition: string.c:737
#define xcalloc
Definition: defines.h:185