diff options
Diffstat (limited to 'ext/etc')
| -rw-r--r-- | ext/etc/.document | 2 | ||||
| -rw-r--r-- | ext/etc/depend | 159 | ||||
| -rw-r--r-- | ext/etc/etc.c | 352 | ||||
| -rw-r--r-- | ext/etc/etc.gemspec | 19 | ||||
| -rw-r--r-- | ext/etc/extconf.rb | 61 | ||||
| -rw-r--r-- | ext/etc/mkconstants.rb | 32 |
6 files changed, 460 insertions, 165 deletions
diff --git a/ext/etc/.document b/ext/etc/.document new file mode 100644 index 0000000000..9bbea23b92 --- /dev/null +++ b/ext/etc/.document @@ -0,0 +1,2 @@ +etc.c +constdefs.h diff --git a/ext/etc/depend b/ext/etc/depend index 99e812c7e4..77fe56a6bf 100644 --- a/ext/etc/depend +++ b/ext/etc/depend @@ -7,10 +7,169 @@ etc.o: $(RUBY_EXTCONF_H) etc.o: $(arch_hdrdir)/ruby/config.h etc.o: $(hdrdir)/ruby.h etc.o: $(hdrdir)/ruby/assert.h +etc.o: $(hdrdir)/ruby/atomic.h etc.o: $(hdrdir)/ruby/backward.h +etc.o: $(hdrdir)/ruby/backward/2/assume.h +etc.o: $(hdrdir)/ruby/backward/2/attributes.h +etc.o: $(hdrdir)/ruby/backward/2/bool.h +etc.o: $(hdrdir)/ruby/backward/2/inttypes.h +etc.o: $(hdrdir)/ruby/backward/2/limits.h +etc.o: $(hdrdir)/ruby/backward/2/long_long.h +etc.o: $(hdrdir)/ruby/backward/2/stdalign.h +etc.o: $(hdrdir)/ruby/backward/2/stdarg.h etc.o: $(hdrdir)/ruby/defines.h etc.o: $(hdrdir)/ruby/encoding.h etc.o: $(hdrdir)/ruby/intern.h +etc.o: $(hdrdir)/ruby/internal/abi.h +etc.o: $(hdrdir)/ruby/internal/anyargs.h +etc.o: $(hdrdir)/ruby/internal/arithmetic.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/char.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/double.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/int.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/long.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/short.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +etc.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +etc.o: $(hdrdir)/ruby/internal/assume.h +etc.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +etc.o: $(hdrdir)/ruby/internal/attr/artificial.h +etc.o: $(hdrdir)/ruby/internal/attr/cold.h +etc.o: $(hdrdir)/ruby/internal/attr/const.h +etc.o: $(hdrdir)/ruby/internal/attr/constexpr.h +etc.o: $(hdrdir)/ruby/internal/attr/deprecated.h +etc.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +etc.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +etc.o: $(hdrdir)/ruby/internal/attr/error.h +etc.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +etc.o: $(hdrdir)/ruby/internal/attr/forceinline.h +etc.o: $(hdrdir)/ruby/internal/attr/format.h +etc.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +etc.o: $(hdrdir)/ruby/internal/attr/noalias.h +etc.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +etc.o: $(hdrdir)/ruby/internal/attr/noexcept.h +etc.o: $(hdrdir)/ruby/internal/attr/noinline.h +etc.o: $(hdrdir)/ruby/internal/attr/nonnull.h +etc.o: $(hdrdir)/ruby/internal/attr/noreturn.h +etc.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +etc.o: $(hdrdir)/ruby/internal/attr/pure.h +etc.o: $(hdrdir)/ruby/internal/attr/restrict.h +etc.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +etc.o: $(hdrdir)/ruby/internal/attr/warning.h +etc.o: $(hdrdir)/ruby/internal/attr/weakref.h +etc.o: $(hdrdir)/ruby/internal/cast.h +etc.o: $(hdrdir)/ruby/internal/compiler_is.h +etc.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +etc.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +etc.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +etc.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +etc.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +etc.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +etc.o: $(hdrdir)/ruby/internal/compiler_since.h +etc.o: $(hdrdir)/ruby/internal/config.h +etc.o: $(hdrdir)/ruby/internal/constant_p.h +etc.o: $(hdrdir)/ruby/internal/core.h +etc.o: $(hdrdir)/ruby/internal/core/rarray.h +etc.o: $(hdrdir)/ruby/internal/core/rbasic.h +etc.o: $(hdrdir)/ruby/internal/core/rbignum.h +etc.o: $(hdrdir)/ruby/internal/core/rclass.h +etc.o: $(hdrdir)/ruby/internal/core/rdata.h +etc.o: $(hdrdir)/ruby/internal/core/rfile.h +etc.o: $(hdrdir)/ruby/internal/core/rhash.h +etc.o: $(hdrdir)/ruby/internal/core/robject.h +etc.o: $(hdrdir)/ruby/internal/core/rregexp.h +etc.o: $(hdrdir)/ruby/internal/core/rstring.h +etc.o: $(hdrdir)/ruby/internal/core/rstruct.h +etc.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +etc.o: $(hdrdir)/ruby/internal/ctype.h +etc.o: $(hdrdir)/ruby/internal/dllexport.h +etc.o: $(hdrdir)/ruby/internal/dosish.h +etc.o: $(hdrdir)/ruby/internal/encoding/coderange.h +etc.o: $(hdrdir)/ruby/internal/encoding/ctype.h +etc.o: $(hdrdir)/ruby/internal/encoding/encoding.h +etc.o: $(hdrdir)/ruby/internal/encoding/pathname.h +etc.o: $(hdrdir)/ruby/internal/encoding/re.h +etc.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +etc.o: $(hdrdir)/ruby/internal/encoding/string.h +etc.o: $(hdrdir)/ruby/internal/encoding/symbol.h +etc.o: $(hdrdir)/ruby/internal/encoding/transcode.h +etc.o: $(hdrdir)/ruby/internal/error.h +etc.o: $(hdrdir)/ruby/internal/eval.h +etc.o: $(hdrdir)/ruby/internal/event.h +etc.o: $(hdrdir)/ruby/internal/fl_type.h +etc.o: $(hdrdir)/ruby/internal/gc.h +etc.o: $(hdrdir)/ruby/internal/glob.h +etc.o: $(hdrdir)/ruby/internal/globals.h +etc.o: $(hdrdir)/ruby/internal/has/attribute.h +etc.o: $(hdrdir)/ruby/internal/has/builtin.h +etc.o: $(hdrdir)/ruby/internal/has/c_attribute.h +etc.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +etc.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +etc.o: $(hdrdir)/ruby/internal/has/extension.h +etc.o: $(hdrdir)/ruby/internal/has/feature.h +etc.o: $(hdrdir)/ruby/internal/has/warning.h +etc.o: $(hdrdir)/ruby/internal/intern/array.h +etc.o: $(hdrdir)/ruby/internal/intern/bignum.h +etc.o: $(hdrdir)/ruby/internal/intern/class.h +etc.o: $(hdrdir)/ruby/internal/intern/compar.h +etc.o: $(hdrdir)/ruby/internal/intern/complex.h +etc.o: $(hdrdir)/ruby/internal/intern/cont.h +etc.o: $(hdrdir)/ruby/internal/intern/dir.h +etc.o: $(hdrdir)/ruby/internal/intern/enum.h +etc.o: $(hdrdir)/ruby/internal/intern/enumerator.h +etc.o: $(hdrdir)/ruby/internal/intern/error.h +etc.o: $(hdrdir)/ruby/internal/intern/eval.h +etc.o: $(hdrdir)/ruby/internal/intern/file.h +etc.o: $(hdrdir)/ruby/internal/intern/hash.h +etc.o: $(hdrdir)/ruby/internal/intern/io.h +etc.o: $(hdrdir)/ruby/internal/intern/load.h +etc.o: $(hdrdir)/ruby/internal/intern/marshal.h +etc.o: $(hdrdir)/ruby/internal/intern/numeric.h +etc.o: $(hdrdir)/ruby/internal/intern/object.h +etc.o: $(hdrdir)/ruby/internal/intern/parse.h +etc.o: $(hdrdir)/ruby/internal/intern/proc.h +etc.o: $(hdrdir)/ruby/internal/intern/process.h +etc.o: $(hdrdir)/ruby/internal/intern/random.h +etc.o: $(hdrdir)/ruby/internal/intern/range.h +etc.o: $(hdrdir)/ruby/internal/intern/rational.h +etc.o: $(hdrdir)/ruby/internal/intern/re.h +etc.o: $(hdrdir)/ruby/internal/intern/ruby.h +etc.o: $(hdrdir)/ruby/internal/intern/select.h +etc.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +etc.o: $(hdrdir)/ruby/internal/intern/set.h +etc.o: $(hdrdir)/ruby/internal/intern/signal.h +etc.o: $(hdrdir)/ruby/internal/intern/sprintf.h +etc.o: $(hdrdir)/ruby/internal/intern/string.h +etc.o: $(hdrdir)/ruby/internal/intern/struct.h +etc.o: $(hdrdir)/ruby/internal/intern/thread.h +etc.o: $(hdrdir)/ruby/internal/intern/time.h +etc.o: $(hdrdir)/ruby/internal/intern/variable.h +etc.o: $(hdrdir)/ruby/internal/intern/vm.h +etc.o: $(hdrdir)/ruby/internal/interpreter.h +etc.o: $(hdrdir)/ruby/internal/iterator.h +etc.o: $(hdrdir)/ruby/internal/memory.h +etc.o: $(hdrdir)/ruby/internal/method.h +etc.o: $(hdrdir)/ruby/internal/module.h +etc.o: $(hdrdir)/ruby/internal/newobj.h +etc.o: $(hdrdir)/ruby/internal/scan_args.h +etc.o: $(hdrdir)/ruby/internal/special_consts.h +etc.o: $(hdrdir)/ruby/internal/static_assert.h +etc.o: $(hdrdir)/ruby/internal/stdalign.h +etc.o: $(hdrdir)/ruby/internal/stdbool.h +etc.o: $(hdrdir)/ruby/internal/stdckdint.h +etc.o: $(hdrdir)/ruby/internal/symbol.h +etc.o: $(hdrdir)/ruby/internal/value.h +etc.o: $(hdrdir)/ruby/internal/value_type.h +etc.o: $(hdrdir)/ruby/internal/variable.h +etc.o: $(hdrdir)/ruby/internal/warning_push.h +etc.o: $(hdrdir)/ruby/internal/xmalloc.h etc.o: $(hdrdir)/ruby/io.h etc.o: $(hdrdir)/ruby/missing.h etc.o: $(hdrdir)/ruby/onigmo.h diff --git a/ext/etc/etc.c b/ext/etc/etc.c index 2f3fbb737b..8d50a96a62 100644 --- a/ext/etc/etc.c +++ b/ext/etc/etc.c @@ -47,15 +47,55 @@ static VALUE sGroup; #define HAVE_UNAME 1 #endif -#ifndef _WIN32 -char *getenv(); +#ifdef STDC_HEADERS +# include <stdlib.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif #endif -char *getlogin(); +RUBY_EXTERN char *getlogin(void); + +#define RUBY_ETC_VERSION "1.4.6" -#define RUBY_ETC_VERSION "1.1.0" +#define SYMBOL_LIT(str) ID2SYM(rb_intern_const(str "")) + +#ifdef HAVE_RB_DEPRECATE_CONSTANT +void rb_deprecate_constant(VALUE mod, const char *name); +#else +# define rb_deprecate_constant(mod,name) ((void)(mod),(void)(name)) +#endif #include "constdefs.h" +#ifndef HAVE_RB_IO_DESCRIPTOR +static int +io_descriptor_fallback(VALUE io) +{ + rb_io_t *fptr; + GetOpenFile(io, fptr); + return fptr->fd; +} +#define rb_io_descriptor io_descriptor_fallback +#endif + +#ifdef HAVE_RUBY_ATOMIC_H +# include "ruby/atomic.h" +#else +typedef int rb_atomic_t; +# define RUBY_ATOMIC_CAS(var, oldval, newval) \ + ((var) == (oldval) ? ((var) = (newval), (oldval)) : (var)) +# define RUBY_ATOMIC_EXCHANGE(var, newval) \ + atomic_exchange(&var, newval) +static inline rb_atomic_t +atomic_exchange(volatile rb_atomic_t *var, rb_atomic_t newval) +{ + rb_atomic_t oldval = *var; + *var = newval; + return oldval; +} +#endif + /* call-seq: * getlogin -> String * @@ -119,6 +159,12 @@ safe_setup_filesystem_str(const char *str) #endif #ifdef HAVE_GETPWENT +# ifdef __APPLE__ +# define PW_TIME2VAL(t) INT2NUM((int)(t)) +# else +# define PW_TIME2VAL(t) TIMET2NUM(t) +# endif + static VALUE setup_passwd(struct passwd *pwd) { @@ -136,7 +182,7 @@ setup_passwd(struct passwd *pwd) safe_setup_filesystem_str(pwd->pw_dir), safe_setup_filesystem_str(pwd->pw_shell), #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE - INT2NUM(pwd->pw_change), + PW_TIME2VAL(pwd->pw_change), #endif #ifdef HAVE_STRUCT_PASSWD_PW_QUOTA INT2NUM(pwd->pw_quota), @@ -151,7 +197,7 @@ setup_passwd(struct passwd *pwd) safe_setup_locale_str(pwd->pw_comment), #endif #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE - INT2NUM(pwd->pw_expire), + PW_TIME2VAL(pwd->pw_expire), #endif 0 /*dummy*/ ); @@ -159,9 +205,10 @@ setup_passwd(struct passwd *pwd) #endif /* call-seq: - * getpwuid(uid) -> Passwd + * getpwuid(uid) -> Etc::Passwd * - * Returns the /etc/passwd information for the user with the given integer +uid+. + * Returns the <tt>/etc/passwd</tt> information for the user with the given + * integer +uid+. * * The information is returned as a Passwd struct. * @@ -170,7 +217,7 @@ setup_passwd(struct passwd *pwd) * * See the unix manpage for <code>getpwuid(3)</code> for more detail. * - * === Example: + * *Example:* * * Etc.getpwuid(0) * #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash"> @@ -198,16 +245,16 @@ etc_getpwuid(int argc, VALUE *argv, VALUE obj) } /* call-seq: - * getpwnam(name) -> Passwd + * getpwnam(name) -> Etc::Passwd * - * Returns the /etc/passwd information for the user with specified login - * +name+. + * Returns the <tt>/etc/passwd</tt> information for the user with specified + * login +name+. * * The information is returned as a Passwd struct. * * See the unix manpage for <code>getpwnam(3)</code> for more detail. * - * === Example: + * *Example:* * * Etc.getpwnam('root') * #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash"> @@ -228,12 +275,14 @@ etc_getpwnam(VALUE obj, VALUE nam) } #ifdef HAVE_GETPWENT -static int passwd_blocking = 0; +static rb_atomic_t passwd_blocking; static VALUE passwd_ensure(VALUE _) { endpwent(); - passwd_blocking = (int)Qfalse; + if (RUBY_ATOMIC_EXCHANGE(passwd_blocking, 0) != 1) { + rb_raise(rb_eRuntimeError, "unexpected passwd_blocking"); + } return Qnil; } @@ -252,26 +301,25 @@ passwd_iterate(VALUE _) static void each_passwd(void) { - if (passwd_blocking) { + if (RUBY_ATOMIC_CAS(passwd_blocking, 0, 1)) { rb_raise(rb_eRuntimeError, "parallel passwd iteration"); } - passwd_blocking = (int)Qtrue; rb_ensure(passwd_iterate, 0, passwd_ensure, 0); } #endif /* call-seq: - * Etc.passwd { |struct| block } -> Passwd - * Etc.passwd -> Passwd + * passwd { |struct| block } + * passwd -> Etc::Passwd * * Provides a convenient Ruby iterator which executes a block for each entry - * in the /etc/passwd file. + * in the <tt>/etc/passwd</tt> file. * * The code block is passed an Passwd struct. * * See ::getpwent above for details. * - * Example: + * *Example:* * * require 'etc' * @@ -297,18 +345,19 @@ etc_passwd(VALUE obj) } /* call-seq: - * Etc::Passwd.each { |struct| block } -> Passwd + * Etc::Passwd.each { |struct| block } -> Etc::Passwd * Etc::Passwd.each -> Enumerator * - * Iterates for each entry in the /etc/passwd file if a block is given. + * Iterates for each entry in the <tt>/etc/passwd</tt> file if a block is + * given. * * If no block is given, returns the Enumerator. * * The code block is passed an Passwd struct. * - * See ::getpwent above for details. + * See Etc.getpwent above for details. * - * Example: + * *Example:* * * require 'etc' * @@ -330,8 +379,11 @@ etc_each_passwd(VALUE obj) return obj; } -/* Resets the process of reading the /etc/passwd file, so that the next call - * to ::getpwent will return the first entry again. +/* call-seq: + * setpwent + * + * Resets the process of reading the <tt>/etc/passwd</tt> file, so that the + * next call to ::getpwent will return the first entry again. */ static VALUE etc_setpwent(VALUE obj) @@ -342,8 +394,11 @@ etc_setpwent(VALUE obj) return Qnil; } -/* Ends the process of scanning through the /etc/passwd file begun with - * ::getpwent, and closes the file. +/* call-seq: + * endpwent + * + * Ends the process of scanning through the <tt>/etc/passwd</tt> file begun + * with ::getpwent, and closes the file. */ static VALUE etc_endpwent(VALUE obj) @@ -354,7 +409,10 @@ etc_endpwent(VALUE obj) return Qnil; } -/* Returns an entry from the /etc/passwd file. +/* call-seq: + * getpwent -> Etc::Passwd + * + * Returns an entry from the <tt>/etc/passwd</tt> file. * * The first time it is called it opens the file and returns the first entry; * each successive call returns the next entry, or +nil+ if the end of the file @@ -402,16 +460,16 @@ setup_group(struct group *grp) #endif /* call-seq: - * getgrgid(group_id) -> Group + * getgrgid(group_id) -> Etc::Group * * Returns information about the group with specified integer +group_id+, - * as found in /etc/group. + * as found in <tt>/etc/group</tt>. * * The information is returned as a Group struct. * * See the unix manpage for <code>getgrgid(3)</code> for more detail. * - * === Example: + * *Example:* * * Etc.getgrgid(100) * #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]> @@ -440,16 +498,16 @@ etc_getgrgid(int argc, VALUE *argv, VALUE obj) } /* call-seq: - * getgrnam(name) -> Group + * getgrnam(name) -> Etc::Group * * Returns information about the group with specified +name+, as found in - * /etc/group. + * <tt>/etc/group</tt>. * * The information is returned as a Group struct. * * See the unix manpage for <code>getgrnam(3)</code> for more detail. * - * === Example: + * *Example:* * * Etc.getgrnam('users') * #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]> @@ -471,16 +529,17 @@ etc_getgrnam(VALUE obj, VALUE nam) } #ifdef HAVE_GETGRENT -static int group_blocking = 0; +static rb_atomic_t group_blocking; static VALUE group_ensure(VALUE _) { endgrent(); - group_blocking = (int)Qfalse; + if (RUBY_ATOMIC_EXCHANGE(group_blocking, 0) != 1) { + rb_raise(rb_eRuntimeError, "unexpected group_blocking"); + } return Qnil; } - static VALUE group_iterate(VALUE _) { @@ -496,22 +555,25 @@ group_iterate(VALUE _) static void each_group(void) { - if (group_blocking) { + if (RUBY_ATOMIC_CAS(group_blocking, 0, 1)) { rb_raise(rb_eRuntimeError, "parallel group iteration"); } - group_blocking = (int)Qtrue; rb_ensure(group_iterate, 0, group_ensure, 0); } #endif -/* Provides a convenient Ruby iterator which executes a block for each entry - * in the /etc/group file. +/* call-seq: + * group { |struct| block } + * group -> Etc::Group + * + * Provides a convenient Ruby iterator which executes a block for each entry + * in the <tt>/etc/group</tt> file. * * The code block is passed an Group struct. * * See ::getgrent above for details. * - * Example: + * *Example:* * * require 'etc' * @@ -538,16 +600,17 @@ etc_group(VALUE obj) #ifdef HAVE_GETGRENT /* call-seq: - * Etc::Group.each { |group| block } -> obj + * Etc::Group.each { |group| block } -> Etc::Group * Etc::Group.each -> Enumerator * - * Iterates for each entry in the /etc/group file if a block is given. + * Iterates for each entry in the <tt>/etc/group</tt> file if a block is + * given. * * If no block is given, returns the Enumerator. * * The code block is passed a Group struct. * - * Example: + * *Example:* * * require 'etc' * @@ -568,8 +631,11 @@ etc_each_group(VALUE obj) } #endif -/* Resets the process of reading the /etc/group file, so that the next call - * to ::getgrent will return the first entry again. +/* call-seq: + * setgrent + * + * Resets the process of reading the <tt>/etc/group</tt> file, so that the + * next call to ::getgrent will return the first entry again. */ static VALUE etc_setgrent(VALUE obj) @@ -580,8 +646,11 @@ etc_setgrent(VALUE obj) return Qnil; } -/* Ends the process of scanning through the /etc/group file begun by - * ::getgrent, and closes the file. +/* call-seq: + * endgrent + * + * Ends the process of scanning through the <tt>/etc/group</tt> file begun + * by ::getgrent, and closes the file. */ static VALUE etc_endgrent(VALUE obj) @@ -592,7 +661,10 @@ etc_endgrent(VALUE obj) return Qnil; } -/* Returns an entry from the /etc/group file. +/* call-seq: + * getgrent -> Etc::Group + * + * Returns an entry from the <tt>/etc/group</tt> file. * * The first time it is called it opens the file and returns the first entry; * each successive call returns the next entry, or +nil+ if the end of the file @@ -621,14 +693,28 @@ etc_getgrent(VALUE obj) VALUE rb_w32_special_folder(int type); UINT rb_w32_system_tmpdir(WCHAR *path, UINT len); VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc); +#elif defined(LOAD_RELATIVE) +static inline VALUE +rbconfig(void) +{ + VALUE config; + rb_require("rbconfig"); + config = rb_const_get(rb_path2class("RbConfig"), rb_intern_const("CONFIG")); + Check_Type(config, T_HASH); + return config; +} #endif -/* +/* call-seq: + * sysconfdir -> String + * * Returns system configuration directory. * - * This is typically "/etc", but is modified by the prefix used when Ruby was - * compiled. For example, if Ruby is built and installed in /usr/local, - * returns "/usr/local/etc" on other platforms than Windows. + * This is typically <code>"/etc"</code>, but is modified by the prefix used + * when Ruby was compiled. For example, if Ruby is built and installed in + * <tt>/usr/local</tt>, returns <code>"/usr/local/etc"</code> on other + * platforms than Windows. + * * On Windows, this always returns the directory provided by the system. */ static VALUE @@ -636,12 +722,16 @@ etc_sysconfdir(VALUE obj) { #ifdef _WIN32 return rb_w32_special_folder(CSIDL_COMMON_APPDATA); +#elif defined(LOAD_RELATIVE) + return rb_hash_aref(rbconfig(), rb_str_new_lit("sysconfdir")); #else return rb_filesystem_str_new_cstr(SYSCONFDIR); #endif } -/* +/* call-seq: + * systmpdir -> String + * * Returns system temporary directory; typically "/tmp". */ static VALUE @@ -685,13 +775,15 @@ etc_systmpdir(VALUE _) } #ifdef HAVE_UNAME -/* +/* call-seq: + * uname -> hash + * * Returns the system information obtained by uname system call. * * The return value is a hash which has 5 keys at least: * :sysname, :nodename, :release, :version, :machine * - * Example: + * *Example:* * * require 'etc' * require 'pp' @@ -733,18 +825,14 @@ etc_uname(VALUE obj) sysname = "Windows"; break; } - rb_hash_aset(result, ID2SYM(rb_intern("sysname")), rb_str_new_cstr(sysname)); + rb_hash_aset(result, SYMBOL_LIT("sysname"), rb_str_new_cstr(sysname)); release = rb_sprintf("%lu.%lu.%lu", v.dwMajorVersion, v.dwMinorVersion, v.dwBuildNumber); - rb_hash_aset(result, ID2SYM(rb_intern("release")), release); + rb_hash_aset(result, SYMBOL_LIT("release"), release); version = rb_sprintf("%s Version %"PRIsVALUE": %"PRIsVALUE, sysname, release, rb_w32_conv_from_wchar(v.szCSDVersion, rb_utf8_encoding())); - rb_hash_aset(result, ID2SYM(rb_intern("version")), version); + rb_hash_aset(result, SYMBOL_LIT("version"), version); -# if defined _MSC_VER && _MSC_VER < 1300 -# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameW(ptr, plen) -# else # define GET_COMPUTER_NAME(ptr, plen) GetComputerNameExW(ComputerNameDnsFullyQualified, ptr, plen) -# endif GET_COMPUTER_NAME(NULL, &len); buf = ALLOCV_N(WCHAR, vbuf, len); if (GET_COMPUTER_NAME(buf, &len)) { @@ -752,7 +840,7 @@ etc_uname(VALUE obj) } ALLOCV_END(vbuf); if (NIL_P(nodename)) nodename = rb_str_new(0, 0); - rb_hash_aset(result, ID2SYM(rb_intern("nodename")), nodename); + rb_hash_aset(result, SYMBOL_LIT("nodename"), nodename); # ifndef PROCESSOR_ARCHITECTURE_AMD64 # define PROCESSOR_ARCHITECTURE_AMD64 9 @@ -776,7 +864,7 @@ etc_uname(VALUE obj) break; } - rb_hash_aset(result, ID2SYM(rb_intern("machine")), rb_str_new_cstr(mach)); + rb_hash_aset(result, SYMBOL_LIT("machine"), rb_str_new_cstr(mach)); #else struct utsname u; int ret; @@ -787,11 +875,11 @@ etc_uname(VALUE obj) rb_sys_fail("uname"); result = rb_hash_new(); - rb_hash_aset(result, ID2SYM(rb_intern("sysname")), rb_str_new_cstr(u.sysname)); - rb_hash_aset(result, ID2SYM(rb_intern("nodename")), rb_str_new_cstr(u.nodename)); - rb_hash_aset(result, ID2SYM(rb_intern("release")), rb_str_new_cstr(u.release)); - rb_hash_aset(result, ID2SYM(rb_intern("version")), rb_str_new_cstr(u.version)); - rb_hash_aset(result, ID2SYM(rb_intern("machine")), rb_str_new_cstr(u.machine)); + rb_hash_aset(result, SYMBOL_LIT("sysname"), rb_str_new_cstr(u.sysname)); + rb_hash_aset(result, SYMBOL_LIT("nodename"), rb_str_new_cstr(u.nodename)); + rb_hash_aset(result, SYMBOL_LIT("release"), rb_str_new_cstr(u.release)); + rb_hash_aset(result, SYMBOL_LIT("version"), rb_str_new_cstr(u.version)); + rb_hash_aset(result, SYMBOL_LIT("machine"), rb_str_new_cstr(u.machine)); #endif return result; @@ -801,7 +889,9 @@ etc_uname(VALUE obj) #endif #ifdef HAVE_SYSCONF -/* +/* call-seq: + * sysconf(name) -> Integer + * * Returns system configuration variable using sysconf(). * * _name_ should be a constant under <code>Etc</code> which begins with <code>SC_</code>. @@ -835,7 +925,9 @@ etc_sysconf(VALUE obj, VALUE arg) #endif #ifdef HAVE_CONFSTR -/* +/* call-seq: + * confstr(name) -> String + * * Returns system configuration variable using confstr(). * * _name_ should be a constant under <code>Etc</code> which begins with <code>CS_</code>. @@ -882,7 +974,9 @@ etc_confstr(VALUE obj, VALUE arg) #endif #ifdef HAVE_FPATHCONF -/* +/* call-seq: + * pathconf(name) -> Integer + * * Returns pathname configuration variable using fpathconf(). * * _name_ should be a constant under <code>Etc</code> which begins with <code>PC_</code>. @@ -901,14 +995,11 @@ io_pathconf(VALUE io, VALUE arg) { int name; long ret; - rb_io_t *fptr; name = NUM2INT(arg); - GetOpenFile(io, fptr); - errno = 0; - ret = fpathconf(fptr->fd, name); + ret = fpathconf(rb_io_descriptor(io), name); if (ret == -1) { if (errno == 0) /* no limit */ return Qnil; @@ -926,11 +1017,13 @@ io_pathconf(VALUE io, VALUE arg) static int etc_nprocessors_affin(void) { - cpu_set_t *cpuset; + cpu_set_t *cpuset, cpuset_buff[1024 / sizeof(cpu_set_t)]; size_t size; int ret; int n; + CPU_ZERO_S(sizeof(cpuset_buff), cpuset_buff); + /* * XXX: * man page says CPU_ALLOC takes number of cpus. But it is not accurate @@ -949,13 +1042,12 @@ etc_nprocessors_affin(void) */ for (n=64; n <= 16384; n *= 2) { size = CPU_ALLOC_SIZE(n); - if (size >= 1024) { + if (size >= sizeof(cpuset_buff)) { cpuset = xcalloc(1, size); if (!cpuset) return -1; } else { - cpuset = alloca(size); - CPU_ZERO_S(size, cpuset); + cpuset = cpuset_buff; } ret = sched_getaffinity(0, size, cpuset); @@ -964,10 +1056,10 @@ etc_nprocessors_affin(void) ret = CPU_COUNT_S(size, cpuset); } - if (size >= 1024) { + if (size >= sizeof(cpuset_buff)) { xfree(cpuset); } - if (ret > 0) { + if (ret > 0 || errno != EINVAL) { return ret; } } @@ -976,7 +1068,9 @@ etc_nprocessors_affin(void) } #endif -/* +/* call-seq: + * nprocessors -> Integer + * * Returns the number of online processors. * * The result is intended as the number of processes to @@ -986,7 +1080,7 @@ etc_nprocessors_affin(void) * - sched_getaffinity(): Linux * - sysconf(_SC_NPROCESSORS_ONLN): GNU/Linux, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, OpenIndiana, Mac OS X, AIX * - * Example: + * *Example:* * * require 'etc' * p Etc.nprocessors #=> 4 @@ -995,7 +1089,7 @@ etc_nprocessors_affin(void) * process is bound to specific cpus. This is intended for getting better * parallel processing. * - * Example: (Linux) + * *Example:* (Linux) * * linux$ taskset 0x3 ./ruby -retc -e "p Etc.nprocessors" #=> 2 * @@ -1035,16 +1129,17 @@ etc_nprocessors(VALUE obj) /* * The Etc module provides access to information typically stored in - * files in the /etc directory on Unix systems. + * files in the <tt>/etc</tt> directory on Unix systems. * * The information accessible consists of the information found in the - * /etc/passwd and /etc/group files, plus information about the system's - * temporary directory (/tmp) and configuration directory (/etc). + * <tt>/etc/passwd</tt> and <tt>/etc/group</tt> files, plus information + * about the system's temporary directory (<tt>/tmp</tt>) and configuration + * directory (<tt>/etc</tt>). * * The Etc module provides a more reliable way to access information about * the logged in user than environment variables such as +$USER+. * - * == Example: + * *Example:* * * require 'etc' * @@ -1065,9 +1160,25 @@ Init_etc(void) VALUE mEtc; mEtc = rb_define_module("Etc"); + /* The version */ rb_define_const(mEtc, "VERSION", rb_str_new_cstr(RUBY_ETC_VERSION)); init_constants(mEtc); + /* Ractor-safe methods */ +#ifdef HAVE_RB_EXT_RACTOR_SAFE + RB_EXT_RACTOR_SAFE(true); +#endif + rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0); + rb_define_module_function(mEtc, "uname", etc_uname, 0); + rb_define_module_function(mEtc, "sysconf", etc_sysconf, 1); + rb_define_module_function(mEtc, "confstr", etc_confstr, 1); + rb_define_method(rb_cIO, "pathconf", io_pathconf, 1); + rb_define_module_function(mEtc, "nprocessors", etc_nprocessors, 0); + + /* Non-Ractor-safe methods, see https://bugs.ruby-lang.org/issues/21115 */ +#ifdef HAVE_RB_EXT_RACTOR_SAFE + RB_EXT_RACTOR_SAFE(false); +#endif rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0); rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1); @@ -1083,13 +1194,9 @@ Init_etc(void) rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0); rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0); rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0); + + /* Uses RbConfig::CONFIG so does not work in a Ractor */ rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0); - rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0); - rb_define_module_function(mEtc, "uname", etc_uname, 0); - rb_define_module_function(mEtc, "sysconf", etc_sysconf, 1); - rb_define_module_function(mEtc, "confstr", etc_confstr, 1); - rb_define_method(rb_cIO, "pathconf", io_pathconf, 1); - rb_define_module_function(mEtc, "nprocessors", etc_nprocessors, 0); sPasswd = rb_struct_define_under(mEtc, "Passwd", "name", @@ -1123,16 +1230,18 @@ Init_etc(void) #endif NULL); #if 0 - /* Define-const: Passwd + /* + * Passwd is a placeholder Struct for user database on Unix systems. * - * Passwd is a Struct that contains the following members: + * === The struct contains the following members * * name:: * contains the short login name of the user as a String. * passwd:: * contains the encrypted password of the user as a String. - * an 'x' is returned if shadow passwords are in use. An '*' is returned - * if the user cannot log in using a password. + * an <code>'x'</code> is returned if shadow passwords are in + * use. An <code>'*'</code> is returned if the user cannot + * log in using a password. * uid:: * contains the integer user ID (uid) of the user. * gid:: @@ -1142,29 +1251,27 @@ Init_etc(void) * shell:: * contains the path to the login shell of the user as a String. * - * === The following members below are optional, and must be compiled with special flags: + * === The following members below are system-dependent * * gecos:: * contains a longer String description of the user, such as * a full name. Some Unix systems provide structured information in the * gecos field, but this is system-dependent. - * must be compiled with +HAVE_STRUCT_PASSWD_PW_GECOS+ * change:: - * password change time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_CHANGE+ + * password change time(integer). * quota:: - * quota value(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_QUOTA+ + * quota value(integer). * age:: - * password age(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_AGE+ + * password age(integer). * class:: - * user access class(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_CLASS+ + * user access class(string). * comment:: - * comment(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_COMMENT+ + * comment(string). * expire:: - * account expiration time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_EXPIRE+ + * account expiration time(integer). */ - rb_define_const(mEtc, "Passwd", sPasswd); + sPasswd = rb_define_class_under(mEtc, "Passwd", rb_cStruct); #endif - rb_define_const(rb_cStruct, "Passwd", sPasswd); /* deprecated name */ rb_extend_object(sPasswd, rb_mEnumerable); rb_define_singleton_method(sPasswd, "each", etc_each_passwd, 0); @@ -1176,31 +1283,32 @@ Init_etc(void) "gid", "mem", NULL); #if 0 - /* Define-const: Group - * - * Group is a Struct that is only available when compiled with +HAVE_GETGRENT+. + /* + * Group is a placeholder Struct for user group database on Unix systems. * - * The struct contains the following members: + * === The struct contains the following members * * name:: * contains the name of the group as a String. * passwd:: - * contains the encrypted password as a String. An 'x' is + * contains the encrypted password as a String. An <code>'x'</code> is * returned if password access to the group is not available; an empty * string is returned if no password is needed to obtain membership of * the group. - * - * Must be compiled with +HAVE_STRUCT_GROUP_GR_PASSWD+. + * This is system-dependent. * gid:: * contains the group's numeric ID as an integer. * mem:: * is an Array of Strings containing the short login names of the * members of the group. */ - rb_define_const(mEtc, "Group", sGroup); + sGroup = rb_define_class_under(mEtc, "Group", rb_cStruct); #endif - rb_define_const(rb_cStruct, "Group", sGroup); /* deprecated name */ rb_extend_object(sGroup, rb_mEnumerable); rb_define_singleton_method(sGroup, "each", etc_each_group, 0); #endif + +#if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT) + (void)safe_setup_str; +#endif } diff --git a/ext/etc/etc.gemspec b/ext/etc/etc.gemspec index f28016925f..0e9803dc62 100644 --- a/ext/etc/etc.gemspec +++ b/ext/etc/etc.gemspec @@ -20,26 +20,25 @@ Gem::Specification.new do |spec| spec.summary = %q{Provides access to information typically stored in UNIX /etc directory.} spec.description = spec.summary spec.homepage = "https://github.com/ruby/etc" - spec.license = "BSD-2-Clause" + spec.licenses = ["Ruby", "BSD-2-Clause"] + changelogs = Dir.glob("logs/ChangeLog-[1-9]*[^~]", base: __dir__) spec.files = %w[ - LICENSE.txt + BSDL + COPYING README.md + ChangeLog ext/etc/constdefs.h ext/etc/etc.c ext/etc/extconf.rb ext/etc/mkconstants.rb - stub/etc.rb test/etc/test_etc.rb - ] + ] + changelogs + spec.rdoc_options = ["--main", "README.md"] + spec.extra_rdoc_files = spec.files.grep_v(/\.{rb,[ch]}\z/) spec.bindir = "exe" spec.require_paths = ["lib"] spec.extensions = %w{ext/etc/extconf.rb} - spec.required_ruby_version = ">= 2.3.0" - - spec.add_development_dependency "bundler" - spec.add_development_dependency "rake" - spec.add_development_dependency "rake-compiler" - spec.add_development_dependency "test-unit" + spec.required_ruby_version = ">= 2.7.0" end diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb index 435fbe7f3d..497303a4fa 100644 --- a/ext/etc/extconf.rb +++ b/ext/etc/extconf.rb @@ -10,8 +10,30 @@ headers = [] have_library("sun", "getpwnam") # NIS (== YP) interface for IRIX 4 have_func("uname((struct utsname *)NULL)", headers) have_func("getlogin") -have_func("getpwent") -have_func("getgrent") +if have_func("getpwent") + have_struct_member('struct passwd', 'pw_gecos', 'pwd.h') + have_struct_member('struct passwd', 'pw_change', 'pwd.h') + have_struct_member('struct passwd', 'pw_quota', 'pwd.h') + if have_struct_member('struct passwd', 'pw_age', 'pwd.h') + case what_type?('struct passwd', 'pw_age', 'pwd.h') + when "string" + f = "safe_setup_str" + when "long long" + f = "LL2NUM" + else + f = "INT2NUM" + end + $defs.push("-DPW_AGE2VAL="+f) + end + have_struct_member('struct passwd', 'pw_class', 'pwd.h') + have_struct_member('struct passwd', 'pw_comment', 'pwd.h') unless /cygwin/ === RUBY_PLATFORM + have_struct_member('struct passwd', 'pw_expire', 'pwd.h') + have_struct_member('struct passwd', 'pw_passwd', 'pwd.h') +end +if have_func("getgrent") + have_struct_member('struct group', 'gr_passwd', 'grp.h') +end + if (sysconfdir = RbConfig::CONFIG["sysconfdir"] and !RbConfig.expand(sysconfdir.dup, "prefix"=>"", "DESTDIR"=>"").empty?) $defs.push("-DSYSCONFDIR=#{Shellwords.escape(sysconfdir.dump)}") @@ -21,31 +43,24 @@ have_func("sysconf") have_func("confstr") have_func("fpathconf") -have_struct_member('struct passwd', 'pw_gecos', 'pwd.h') -have_struct_member('struct passwd', 'pw_change', 'pwd.h') -have_struct_member('struct passwd', 'pw_quota', 'pwd.h') -if have_struct_member('struct passwd', 'pw_age', 'pwd.h') - case what_type?('struct passwd', 'pw_age', 'pwd.h') - when "string" - f = "safe_setup_str" - when "long long" - f = "LL2NUM" +# for https://github.com/ruby/etc +srcdir = File.expand_path("..", __FILE__) +constdefs = "#{srcdir}/constdefs.h" +if !File.exist?(constdefs) + ruby = RbConfig.ruby + if File.file?(ruby) + ruby = [ruby] else - f = "INT2NUM" + require "shellwords" + ruby = Shellwords.split(ruby) end - $defs.push("-DPW_AGE2VAL="+f) + system(*ruby, "#{srcdir}/mkconstants.rb", "-o", constdefs) end -have_struct_member('struct passwd', 'pw_class', 'pwd.h') -have_struct_member('struct passwd', 'pw_comment', 'pwd.h') unless /cygwin/ === RUBY_PLATFORM -have_struct_member('struct passwd', 'pw_expire', 'pwd.h') -have_struct_member('struct passwd', 'pw_passwd', 'pwd.h') -have_struct_member('struct group', 'gr_passwd', 'grp.h') -# for https://github.com/ruby/etc -srcdir = File.expand_path("..", __FILE__) -if !File.exist?("#{srcdir}/depend") - %x[#{RbConfig.ruby} #{srcdir}/mkconstants.rb -o #{srcdir}/constdefs.h] -end +# TODO: remove when dropping 2.7 support, as exported since 3.0 +have_func('rb_deprecate_constant(Qnil, "None")') + +have_func("rb_io_descriptor", "ruby/io.h") $distcleanfiles << "constdefs.h" diff --git a/ext/etc/mkconstants.rb b/ext/etc/mkconstants.rb index a752d64519..a766560a8a 100644 --- a/ext/etc/mkconstants.rb +++ b/ext/etc/mkconstants.rb @@ -35,6 +35,12 @@ opt.def_option('-H FILE', 'specify output header file') {|filename| opt.parse! +CONST_PREFIXES = { + 'SC' => 'for Etc.sysconf; See <tt>man sysconf</tt>', + 'CS' => 'for Etc.confstr; See <tt>man constr</tt>', + 'PC' => 'for IO#pathconf; See <tt>man fpathconf</tt>', +} + h = {} COMMENTS = {} @@ -49,6 +55,13 @@ DATA.each_line {|s| next end h[name] = default_value + if additional = CONST_PREFIXES[name[/\A_([A-Z]+)_/, 1]] + if comment&.match(/\w\z/) + comment << " " << additional + else + (comment ||= String.new) << " " << additional.sub(/\A\w/) {$&.upcase} + end + end COMMENTS[name] = comment if comment } DEFS = h.to_a @@ -66,15 +79,11 @@ def each_name(pat) } end -erb_new = lambda do |src, safe, trim| - if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+ - ERB.new(src, trim_mode: trim) - else - ERB.new(src, safe, trim) - end +erb_new = lambda do |src, trim| + ERB.new(src, trim_mode: trim) end -erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_decls") +erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_decls") % each_const {|name, default_value| #if !defined(<%=name%>) # if defined(HAVE_CONST_<%=name.upcase%>) @@ -88,7 +97,7 @@ erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_decls") % } EOS -erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_defs") +erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_defs") % each_const {|name, default_value| #if defined(<%=name%>) % if comment = COMMENTS[name] @@ -99,13 +108,13 @@ erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_defs") % } EOS -header_result = erb_new.call(<<'EOS', nil, '%').result(binding) +header_result = erb_new.call(<<'EOS', '%').result(binding) /* autogenerated file */ <%= gen_const_decls %> EOS -result = erb_new.call(<<'EOS', nil, '%').result(binding) +result = erb_new.call(<<'EOS', '%').result(binding) /* autogenerated file */ #ifdef HAVE_LONG_LONG @@ -123,6 +132,9 @@ result = erb_new.call(<<'EOS', nil, '%').result(binding) static void init_constants(VALUE mod) { +#if 0 + mod = rb_define_module("Etc"); +#endif <%= gen_const_defs %> } EOS |
