From: "Berger, Daniel" Date: 2005-02-04T07:57:30+09:00 Subject: Adding lastlog info to etc Hi all, Any chance of adding lastlog information to the etc module? I have a patch, but it only works for Solaris at the moment. Basically, it means altering the extconf.rb file and doing the following: Look for a last_log struct in utmp.h. If it's not there, look for a lastlog.h file. If either of these are present, then check for the ll_time struct member (doesn't appear to be defined in Linux, but is defined in Solaris and FreeBSD). Within etc.c: Use appropriate macros derived from extconf.rb. Point the lastlog name to _PATH_LASTLOG if present. If not, use "/var/adm/lastlog". Add the time (ll_time, if present), device name (ll_line) and host info (ll_host) to the data returned by Etc.passwd. Does this sound like a good idea? I've included a Solaris patch below which works fine (just to demonstrate), but needs adjustment for other Unix platforms. Regards, Dan --- extconf.orig Wed Feb 2 11:55:35 2005 +++ extconf.rb Wed Feb 2 12:00:45 2005 @@ -14,5 +14,6 @@ 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') + have_header("lastlog.h") create_makefile("etc") end --- etc.bak Wed Feb 2 11:54:24 2005 +++ etc.c Wed Feb 2 13:02:53 2005 @@ -23,8 +23,17 @@ #include #endif +#ifdef HAVE_LASTLOG_H +#include +#include +#endif + static VALUE sPasswd, sGroup; +#ifdef HAVE_LASTLOG_H +static struct lastlog* getllnam(const char* name); +#endif + #ifndef _WIN32 char *getenv(); #endif @@ -64,7 +73,18 @@ setup_passwd(pwd) struct passwd *pwd; { +#ifdef HAVE_LASTLOG_H + struct lastlog* ll_entry; + time_t time; + VALUE rbTime = Qnil; +#endif if (pwd == 0) rb_sys_fail("/etc/passwd"); +#ifdef HAVE_LASTLOG_H + ll_entry = getllnam(pwd->pw_name); + time = ll_entry->ll_time; + if(time != 0) + rbTime = rb_time_new(time,0); +#endif return rb_struct_new(sPasswd, safe_setup_str(pwd->pw_name), #ifdef HAVE_ST_PW_PASSWD @@ -95,6 +115,11 @@ #ifdef HAVE_ST_PW_EXPIRE INT2FIX(pwd->pw_expire), #endif +#ifdef HAVE_LASTLOG_H + rbTime, + safe_setup_str(ll_entry->ll_line), + safe_setup_str(ll_entry->ll_host), +#endif 0 /*dummy*/ ); } @@ -157,7 +182,7 @@ struct passwd *pw; setpwent(); - while (pw = getpwent()) { + while((pw = getpwent())) { rb_yield(setup_passwd(pw)); } endpwent(); @@ -180,7 +205,7 @@ passwd_blocking = Qtrue; rb_ensure(passwd_iterate, 0, passwd_ensure, 0); } - if (pw = getpwent()) { + if((pw = getpwent())) { return setup_passwd(pw); } #endif @@ -214,7 +239,7 @@ #ifdef HAVE_GETPWENT struct passwd *pw; - if (pw = getpwent()) { + if((pw = getpwent())) { return setup_passwd(pw); } #endif @@ -295,7 +320,7 @@ struct group *pw; setgrent(); - while (pw = getgrent()) { + while((pw = getgrent())) { rb_yield(setup_group(pw)); } endgrent(); @@ -318,7 +343,7 @@ group_blocking = Qtrue; rb_ensure(group_iterate, 0, group_ensure, 0); } - if (grp = getgrent()) { + if((grp = getgrent())) { return setup_group(grp); } #endif @@ -352,7 +377,7 @@ #ifdef HAVE_GETGRENT struct group *gr; - if (gr = getgrent()) { + if((gr = getgrent())) { return setup_group(gr); } #endif @@ -359,6 +384,24 @@ return Qnil; } +#ifdef HAVE_LASTLOG_H +static struct lastlog* getllnam(const char* name){ + static struct lastlog ll_entry; + struct passwd* pwd; + int fd; + + if((fd = open("/var/adm/lastlog",O_RDONLY)) == -1) + rb_sys_fail("/var/adm/lastlog"); + + if((pwd = getpwnam(name)) == NULL) + rb_sys_fail("getpwnam failed"); + + pread(fd,&ll_entry,sizeof(struct lastlog),pwd->pw_uid * sizeof(struct lastlog)); + close(fd); + return (&ll_entry); +} +#endif + static VALUE mEtc; void @@ -406,6 +449,11 @@ #ifdef HAVE_ST_PW_EXPIRE "expire", #endif +#ifdef HAVE_LASTLOG_H + "last_login", + "device_name", + "host_name", +#endif NULL); rb_global_variable(&sPasswd);