mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* ext/etc/etc.c (setup_passwd, setup_group): set proper encodings to string members. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42349 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			801 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			801 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/************************************************
 | 
						|
 | 
						|
  etc.c -
 | 
						|
 | 
						|
  $Author$
 | 
						|
  created at: Tue Mar 22 18:39:19 JST 1994
 | 
						|
 | 
						|
************************************************/
 | 
						|
 | 
						|
#include "ruby.h"
 | 
						|
#include "ruby/encoding.h"
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#ifdef HAVE_UNISTD_H
 | 
						|
#include <unistd.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
#include <pwd.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
#include <grp.h>
 | 
						|
#endif
 | 
						|
 | 
						|
static VALUE sPasswd;
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
static VALUE sGroup;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
#include <shlobj.h>
 | 
						|
#ifndef CSIDL_COMMON_APPDATA
 | 
						|
#define CSIDL_COMMON_APPDATA 35
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef _WIN32
 | 
						|
char *getenv();
 | 
						|
#endif
 | 
						|
char *getlogin();
 | 
						|
 | 
						|
/* call-seq:
 | 
						|
 *	getlogin	->  String
 | 
						|
 *
 | 
						|
 * Returns the short user name of the currently logged in user.
 | 
						|
 * Unfortunately, it is often rather easy to fool ::getlogin.
 | 
						|
 *
 | 
						|
 * Avoid ::getlogin for security-related purposes.
 | 
						|
 *
 | 
						|
 * If ::getlogin fails, try ::getpwuid.
 | 
						|
 *
 | 
						|
 * See the unix manpage for <code>getpwuid(3)</code> for more detail.
 | 
						|
 *
 | 
						|
 * e.g.
 | 
						|
 *   Etc.getlogin -> 'guest'
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_getlogin(VALUE obj)
 | 
						|
{
 | 
						|
    char *login;
 | 
						|
 | 
						|
#ifdef HAVE_GETLOGIN
 | 
						|
    login = getlogin();
 | 
						|
    if (!login) login = getenv("USER");
 | 
						|
#else
 | 
						|
    login = getenv("USER");
 | 
						|
#endif
 | 
						|
 | 
						|
    if (login)
 | 
						|
	return rb_tainted_str_new2(login);
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
#if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
 | 
						|
static VALUE
 | 
						|
safe_setup_str(const char *str)
 | 
						|
{
 | 
						|
    if (str == 0) str = "";
 | 
						|
    return rb_tainted_str_new2(str);
 | 
						|
}
 | 
						|
 | 
						|
static VALUE
 | 
						|
safe_setup_locale_str(const char *str)
 | 
						|
{
 | 
						|
    if (str == 0) str = "";
 | 
						|
    return rb_locale_str_new_cstr(str);
 | 
						|
}
 | 
						|
 | 
						|
static VALUE
 | 
						|
safe_setup_filesystem_str(const char *str)
 | 
						|
{
 | 
						|
    if (str == 0) str = "";
 | 
						|
    return rb_filesystem_str_new_cstr(str);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
static VALUE
 | 
						|
setup_passwd(struct passwd *pwd)
 | 
						|
{
 | 
						|
    if (pwd == 0) rb_sys_fail("/etc/passwd");
 | 
						|
    return rb_struct_new(sPasswd,
 | 
						|
			 safe_setup_locale_str(pwd->pw_name),
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_PASSWD
 | 
						|
			 safe_setup_str(pwd->pw_passwd),
 | 
						|
#endif
 | 
						|
			 UIDT2NUM(pwd->pw_uid),
 | 
						|
			 GIDT2NUM(pwd->pw_gid),
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
 | 
						|
			 safe_setup_locale_str(pwd->pw_gecos),
 | 
						|
#endif
 | 
						|
			 safe_setup_filesystem_str(pwd->pw_dir),
 | 
						|
			 safe_setup_filesystem_str(pwd->pw_shell),
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
 | 
						|
			 INT2NUM(pwd->pw_change),
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_QUOTA
 | 
						|
			 INT2NUM(pwd->pw_quota),
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_AGE
 | 
						|
			 PW_AGE2VAL(pwd->pw_age),
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
 | 
						|
			 safe_setup_locale_str(pwd->pw_class),
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_COMMENT
 | 
						|
			 safe_setup_locale_str(pwd->pw_comment),
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
 | 
						|
			 INT2NUM(pwd->pw_expire),
 | 
						|
#endif
 | 
						|
			 0		/*dummy*/
 | 
						|
	);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/* call-seq:
 | 
						|
 *	getpwuid(uid)	->  Passwd
 | 
						|
 *
 | 
						|
 * Returns the /etc/passwd information for the user with the given integer +uid+.
 | 
						|
 *
 | 
						|
 * The information is returned as a Passwd struct.
 | 
						|
 *
 | 
						|
 * If +uid+ is omitted, the value from <code>Passwd[:uid]</code> is returned
 | 
						|
 * instead.
 | 
						|
 *
 | 
						|
 * See the unix manpage for <code>getpwuid(3)</code> for more detail.
 | 
						|
 *
 | 
						|
 * === Example:
 | 
						|
 *
 | 
						|
 *	Etc.getpwuid(0)
 | 
						|
 *	#=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_getpwuid(int argc, VALUE *argv, VALUE obj)
 | 
						|
{
 | 
						|
#if defined(HAVE_GETPWENT)
 | 
						|
    VALUE id;
 | 
						|
    rb_uid_t uid;
 | 
						|
    struct passwd *pwd;
 | 
						|
 | 
						|
    if (rb_scan_args(argc, argv, "01", &id) == 1) {
 | 
						|
	uid = NUM2UIDT(id);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	uid = getuid();
 | 
						|
    }
 | 
						|
    pwd = getpwuid(uid);
 | 
						|
    if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", (int)uid);
 | 
						|
    return setup_passwd(pwd);
 | 
						|
#else
 | 
						|
    return Qnil;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* call-seq:
 | 
						|
 *	getpwnam(name)	->  Passwd
 | 
						|
 *
 | 
						|
 * Returns the /etc/passwd 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:
 | 
						|
 *
 | 
						|
 *	Etc.getpwnam('root')
 | 
						|
 *	#=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_getpwnam(VALUE obj, VALUE nam)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
    struct passwd *pwd;
 | 
						|
 | 
						|
    SafeStringValue(nam);
 | 
						|
    pwd = getpwnam(RSTRING_PTR(nam));
 | 
						|
    if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, nam);
 | 
						|
    return setup_passwd(pwd);
 | 
						|
#else
 | 
						|
    return Qnil;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
static int passwd_blocking = 0;
 | 
						|
static VALUE
 | 
						|
passwd_ensure(void)
 | 
						|
{
 | 
						|
    endpwent();
 | 
						|
    passwd_blocking = (int)Qfalse;
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
static VALUE
 | 
						|
passwd_iterate(void)
 | 
						|
{
 | 
						|
    struct passwd *pw;
 | 
						|
 | 
						|
    setpwent();
 | 
						|
    while (pw = getpwent()) {
 | 
						|
	rb_yield(setup_passwd(pw));
 | 
						|
    }
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
each_passwd(void)
 | 
						|
{
 | 
						|
    if (passwd_blocking) {
 | 
						|
	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
 | 
						|
 *
 | 
						|
 * Provides a convenient Ruby iterator which executes a block for each entry
 | 
						|
 * in the /etc/passwd file.
 | 
						|
 *
 | 
						|
 * The code block is passed an Passwd struct.
 | 
						|
 *
 | 
						|
 * See ::getpwent above for details.
 | 
						|
 *
 | 
						|
 * Example:
 | 
						|
 *
 | 
						|
 *     require 'etc'
 | 
						|
 *
 | 
						|
 *     Etc.passwd {|u|
 | 
						|
 *       puts u.name + " = " + u.gecos
 | 
						|
 *     }
 | 
						|
 *
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_passwd(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
    struct passwd *pw;
 | 
						|
 | 
						|
    if (rb_block_given_p()) {
 | 
						|
	each_passwd();
 | 
						|
    }
 | 
						|
    else if (pw = getpwent()) {
 | 
						|
	return setup_passwd(pw);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
/* call-seq:
 | 
						|
 *	Etc::Passwd.each { |struct| block }	->  Passwd
 | 
						|
 *	Etc::Passwd.each			->  Enumerator
 | 
						|
 *
 | 
						|
 * Iterates for each entry in the /etc/passwd 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.
 | 
						|
 *
 | 
						|
 * Example:
 | 
						|
 *
 | 
						|
 *     require 'etc'
 | 
						|
 *
 | 
						|
 *     Etc::Passwd.each {|u|
 | 
						|
 *       puts u.name + " = " + u.gecos
 | 
						|
 *     }
 | 
						|
 *
 | 
						|
 *     Etc::Passwd.collect {|u| u.gecos}
 | 
						|
 *     Etc::Passwd.collect {|u| u.gecos}
 | 
						|
 *
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_each_passwd(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
    RETURN_ENUMERATOR(obj, 0, 0);
 | 
						|
    each_passwd();
 | 
						|
#endif
 | 
						|
    return obj;
 | 
						|
}
 | 
						|
 | 
						|
/* Resets the process of reading the /etc/passwd file, so that the next call
 | 
						|
 * to ::getpwent will return the first entry again.
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_setpwent(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
    setpwent();
 | 
						|
#endif
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
/* Ends the process of scanning through the /etc/passwd file begun with
 | 
						|
 * ::getpwent, and closes the file.
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_endpwent(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
    endpwent();
 | 
						|
#endif
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
/* Returns an entry from the /etc/passwd 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
 | 
						|
 * has been reached.
 | 
						|
 *
 | 
						|
 * To close the file when processing is complete, call ::endpwent.
 | 
						|
 *
 | 
						|
 * Each entry is returned as a Passwd struct.
 | 
						|
 *
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_getpwent(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETPWENT
 | 
						|
    struct passwd *pw;
 | 
						|
 | 
						|
    if (pw = getpwent()) {
 | 
						|
	return setup_passwd(pw);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
static VALUE
 | 
						|
setup_group(struct group *grp)
 | 
						|
{
 | 
						|
    VALUE mem;
 | 
						|
    char **tbl;
 | 
						|
 | 
						|
    mem = rb_ary_new();
 | 
						|
    tbl = grp->gr_mem;
 | 
						|
    while (*tbl) {
 | 
						|
	rb_ary_push(mem, safe_setup_locale_str(*tbl));
 | 
						|
	tbl++;
 | 
						|
    }
 | 
						|
    return rb_struct_new(sGroup,
 | 
						|
			 safe_setup_locale_str(grp->gr_name),
 | 
						|
#ifdef HAVE_STRUCT_GROUP_GR_PASSWD
 | 
						|
			 safe_setup_str(grp->gr_passwd),
 | 
						|
#endif
 | 
						|
			 GIDT2NUM(grp->gr_gid),
 | 
						|
			 mem);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/* call-seq:
 | 
						|
 *	getgrgid(group_id)  ->	Group
 | 
						|
 *
 | 
						|
 * Returns information about the group with specified integer +group_id+,
 | 
						|
 * as found in /etc/group.
 | 
						|
 *
 | 
						|
 * The information is returned as a Group struct.
 | 
						|
 *
 | 
						|
 * See the unix manpage for <code>getgrgid(3)</code> for more detail.
 | 
						|
 *
 | 
						|
 * === Example:
 | 
						|
 *
 | 
						|
 *	Etc.getgrgid(100)
 | 
						|
 *	#=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
 | 
						|
 *
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_getgrgid(int argc, VALUE *argv, VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
    VALUE id;
 | 
						|
    gid_t gid;
 | 
						|
    struct group *grp;
 | 
						|
 | 
						|
    if (rb_scan_args(argc, argv, "01", &id) == 1) {
 | 
						|
	gid = NUM2GIDT(id);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	gid = getgid();
 | 
						|
    }
 | 
						|
    grp = getgrgid(gid);
 | 
						|
    if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", (int)gid);
 | 
						|
    return setup_group(grp);
 | 
						|
#else
 | 
						|
    return Qnil;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* call-seq:
 | 
						|
 *	getgrnam(name)	->  Group
 | 
						|
 *
 | 
						|
 * Returns information about the group with specified +name+, as found in
 | 
						|
 * /etc/group.
 | 
						|
 *
 | 
						|
 * The information is returned as a Group struct.
 | 
						|
 *
 | 
						|
 * See the unix manpage for <code>getgrnam(3)</code> for more detail.
 | 
						|
 *
 | 
						|
 * === Example:
 | 
						|
 *
 | 
						|
 *	Etc.getgrnam('users')
 | 
						|
 *	#=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
 | 
						|
 *
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_getgrnam(VALUE obj, VALUE nam)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
    struct group *grp;
 | 
						|
 | 
						|
    SafeStringValue(nam);
 | 
						|
    grp = getgrnam(RSTRING_PTR(nam));
 | 
						|
    if (grp == 0) rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, nam);
 | 
						|
    return setup_group(grp);
 | 
						|
#else
 | 
						|
    return Qnil;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
static int group_blocking = 0;
 | 
						|
static VALUE
 | 
						|
group_ensure(void)
 | 
						|
{
 | 
						|
    endgrent();
 | 
						|
    group_blocking = (int)Qfalse;
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static VALUE
 | 
						|
group_iterate(void)
 | 
						|
{
 | 
						|
    struct group *pw;
 | 
						|
 | 
						|
    setgrent();
 | 
						|
    while (pw = getgrent()) {
 | 
						|
	rb_yield(setup_group(pw));
 | 
						|
    }
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
each_group(void)
 | 
						|
{
 | 
						|
    if (group_blocking) {
 | 
						|
	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.
 | 
						|
 *
 | 
						|
 * The code block is passed an Group struct.
 | 
						|
 *
 | 
						|
 * See ::getgrent above for details.
 | 
						|
 *
 | 
						|
 * Example:
 | 
						|
 *
 | 
						|
 *     require 'etc'
 | 
						|
 *
 | 
						|
 *     Etc.group {|g|
 | 
						|
 *       puts g.name + ": " + g.mem.join(', ')
 | 
						|
 *     }
 | 
						|
 *
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_group(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
    struct group *grp;
 | 
						|
 | 
						|
    if (rb_block_given_p()) {
 | 
						|
	each_group();
 | 
						|
    }
 | 
						|
    else if (grp = getgrent()) {
 | 
						|
	return setup_group(grp);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
/* call-seq:
 | 
						|
 *	Etc::Group.each { |group| block }   ->	obj
 | 
						|
 *	Etc::Group.each			    ->	Enumerator
 | 
						|
 *
 | 
						|
 * Iterates for each entry in the /etc/group file if a block is given.
 | 
						|
 *
 | 
						|
 * If no block is given, returns the Enumerator.
 | 
						|
 *
 | 
						|
 * The code block is passed a Group struct.
 | 
						|
 *
 | 
						|
 * Example:
 | 
						|
 *
 | 
						|
 *     require 'etc'
 | 
						|
 *
 | 
						|
 *     Etc::Group.each {|g|
 | 
						|
 *       puts g.name + ": " + g.mem.join(', ')
 | 
						|
 *     }
 | 
						|
 *
 | 
						|
 *     Etc::Group.collect {|g| g.name}
 | 
						|
 *     Etc::Group.select {|g| !g.mem.empty?}
 | 
						|
 *
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_each_group(VALUE obj)
 | 
						|
{
 | 
						|
    RETURN_ENUMERATOR(obj, 0, 0);
 | 
						|
    each_group();
 | 
						|
    return obj;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/* Resets the process of reading the /etc/group file, so that the next call
 | 
						|
 * to ::getgrent will return the first entry again.
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_setgrent(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
    setgrent();
 | 
						|
#endif
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
/* Ends the process of scanning through the /etc/group file begun by
 | 
						|
 * ::getgrent, and closes the file.
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_endgrent(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
    endgrent();
 | 
						|
#endif
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
/* Returns an entry from the /etc/group 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
 | 
						|
 * has been reached.
 | 
						|
 *
 | 
						|
 * To close the file when processing is complete, call ::endgrent.
 | 
						|
 *
 | 
						|
 * Each entry is returned as a Group struct
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_getgrent(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
    struct group *gr;
 | 
						|
 | 
						|
    if (gr = getgrent()) {
 | 
						|
	return setup_group(gr);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    return Qnil;
 | 
						|
}
 | 
						|
 | 
						|
#define numberof(array) (sizeof(array) / sizeof(*(array)))
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
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);
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * 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".
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_sysconfdir(VALUE obj)
 | 
						|
{
 | 
						|
#ifdef _WIN32
 | 
						|
    return rb_w32_special_folder(CSIDL_COMMON_APPDATA);
 | 
						|
#else
 | 
						|
    return rb_filesystem_str_new_cstr(SYSCONFDIR);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Returns system temporary directory; typically "/tmp".
 | 
						|
 */
 | 
						|
static VALUE
 | 
						|
etc_systmpdir(void)
 | 
						|
{
 | 
						|
    VALUE tmpdir;
 | 
						|
#ifdef _WIN32
 | 
						|
    WCHAR path[_MAX_PATH];
 | 
						|
    UINT len = rb_w32_system_tmpdir(path, numberof(path));
 | 
						|
    if (!len) return Qnil;
 | 
						|
    tmpdir = rb_w32_conv_from_wchar(path, rb_filesystem_encoding());
 | 
						|
#else
 | 
						|
    tmpdir = rb_filesystem_str_new_cstr("/tmp");
 | 
						|
#endif
 | 
						|
    FL_UNSET(tmpdir, FL_TAINT);
 | 
						|
    return tmpdir;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * The Etc module provides access to information typically stored in
 | 
						|
 * files in the /etc 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).
 | 
						|
 *
 | 
						|
 * The Etc module provides a more reliable way to access information about
 | 
						|
 * the logged in user than environment variables such as +$USER+.
 | 
						|
 *
 | 
						|
 * == Example:
 | 
						|
 *
 | 
						|
 *     require 'etc'
 | 
						|
 *
 | 
						|
 *     login = Etc.getlogin
 | 
						|
 *     info = Etc.getpwnam(login)
 | 
						|
 *     username = info.gecos.split(/,/).first
 | 
						|
 *     puts "Hello #{username}, I see your login name is #{login}"
 | 
						|
 *
 | 
						|
 * Note that the methods provided by this module are not always secure.
 | 
						|
 * It should be used for informational purposes, and not for security.
 | 
						|
 *
 | 
						|
 * All operations defined in this module are class methods, so that you can
 | 
						|
 * include the Etc module into your class.
 | 
						|
 */
 | 
						|
void
 | 
						|
Init_etc(void)
 | 
						|
{
 | 
						|
    VALUE mEtc;
 | 
						|
 | 
						|
    mEtc = rb_define_module("Etc");
 | 
						|
    rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
 | 
						|
 | 
						|
    rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
 | 
						|
    rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1);
 | 
						|
    rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0);
 | 
						|
    rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0);
 | 
						|
    rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0);
 | 
						|
    rb_define_module_function(mEtc, "passwd", etc_passwd, 0);
 | 
						|
 | 
						|
    rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, -1);
 | 
						|
    rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1);
 | 
						|
    rb_define_module_function(mEtc, "group", etc_group, 0);
 | 
						|
    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);
 | 
						|
    rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0);
 | 
						|
    rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0);
 | 
						|
 | 
						|
    sPasswd =  rb_struct_define_under(mEtc, "Passwd",
 | 
						|
				      "name",
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_PASSWD
 | 
						|
				      "passwd",
 | 
						|
#endif
 | 
						|
				      "uid",
 | 
						|
				      "gid",
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
 | 
						|
				      "gecos",
 | 
						|
#endif
 | 
						|
				      "dir",
 | 
						|
				      "shell",
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
 | 
						|
				      "change",
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_QUOTA
 | 
						|
				      "quota",
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_AGE
 | 
						|
				      "age",
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
 | 
						|
				      "uclass",
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_COMMENT
 | 
						|
				      "comment",
 | 
						|
#endif
 | 
						|
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
 | 
						|
				      "expire",
 | 
						|
#endif
 | 
						|
				      NULL);
 | 
						|
#if 0
 | 
						|
    /* Define-const: Passwd
 | 
						|
     *
 | 
						|
     * Passwd is a Struct that 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.
 | 
						|
     * uid::
 | 
						|
     *	    contains the integer user ID (uid) of the user.
 | 
						|
     * gid::
 | 
						|
     *	    contains the integer group ID (gid) of the user's primary group.
 | 
						|
     * dir::
 | 
						|
     *	    contains the path to the home directory of the user as a String.
 | 
						|
     * 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:
 | 
						|
     *
 | 
						|
     * 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+
 | 
						|
     * quota::
 | 
						|
     *     quota value(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_QUOTA+
 | 
						|
     * age::
 | 
						|
     *     password age(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_AGE+
 | 
						|
     * class::
 | 
						|
     *     user access class(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_CLASS+
 | 
						|
     * comment::
 | 
						|
     *     comment(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_COMMENT+
 | 
						|
     * expire::
 | 
						|
     *	    account expiration time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_EXPIRE+
 | 
						|
     */
 | 
						|
    rb_define_const(mEtc, "Passwd", sPasswd);
 | 
						|
#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);
 | 
						|
 | 
						|
#ifdef HAVE_GETGRENT
 | 
						|
    sGroup = rb_struct_define_under(mEtc, "Group", "name",
 | 
						|
#ifdef HAVE_STRUCT_GROUP_GR_PASSWD
 | 
						|
				    "passwd",
 | 
						|
#endif
 | 
						|
				    "gid", "mem", NULL);
 | 
						|
 | 
						|
#if 0
 | 
						|
    /* Define-const: Group
 | 
						|
     *
 | 
						|
     * Group is a Struct that is only available when compiled with +HAVE_GETGRENT+.
 | 
						|
     *
 | 
						|
     * 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
 | 
						|
     *	    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+.
 | 
						|
     * 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);
 | 
						|
#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
 | 
						|
}
 |