![]() |
|
|
google unix.com
|
|||||||
| Forums | Register | Forum Rules | Links | Albums | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| Shell Programming and Scripting Post questions about KSH, CSH, SH, BASH, PERL, PHP, SED, AWK and OTHER shell scripts and shell scripting languages here. |
More UNIX and Linux Forum Topics You Might Find Helpful
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| su ?? Who logged in First ?? | varungupta | UNIX for Advanced & Expert Users | 2 | 01-24-2008 04:10 PM |
| logged out users | roshni | Post Here to Contact Site Administrators and Moderators | 1 | 07-06-2007 04:02 AM |
| Finding last time users logged in | jyoung | UNIX for Dummies Questions & Answers | 11 | 04-20-2005 03:03 PM |
| know who logged and logged out with their timings | vkandati | UNIX for Dummies Questions & Answers | 3 | 03-09-2005 10:04 AM |
| Is user logged on?? | provo | UNIX for Dummies Questions & Answers | 1 | 12-07-2001 05:41 PM |
![]() |
|
|
LinkBack | Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
|
|
||||
|
Last time logged in
Working in AIX (so no date -d)
How can i display all the users who have not logged in for more than 40 days? A small quick script would be usefull, my scripts are always taking to long to execute, even before they are finished. Many thanks! |
|
||||
|
Old C code to check /var/adm/wtmp - like the last command. It may compile/run on your box if the /var/adm/wtmp exists and it's not /var/adm/wtmpx - a different format. Code:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <utmp.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
/* error macro */
#define ck(x) if ((x)==NULL) \
{barf("Memory/File error");}
/* limits */
#define USER_NAME_LEN 8
#define MAX_USERS 2000
/* array of usernames and times */
typedef struct
{
char user[12];
time_t logtime;
} ulog_t;
ulog_t array[MAX_USERS]={ {0x0}, 0 };
/* exit point for errors */
void barf(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
/* return size of file in bytes */
size_t filesize(const int fd)
{
struct stat st;
if(fstat(fd, &st) == (-1) )
barf("Cannot stat file");
return st.st_size;
}
/* return time_t seconds for ndays in the past */
time_t days_ago(const time_t ndays)
{
time_t then=0;
errno=0;
then=time(NULL);
if(then == (time_t)-1 && errno)
barf("");
then-=(86400 * ndays);
return then;
}
/* map the utmp file into memory */
void *mappit(FILE *u, size_t ulen)
{
void *addr=mmap((void *)0, ulen, PROT_READ, MAP_PRIVATE, fileno(u),0);
if (addr==MAP_FAILED)
barf("mmap failed");
return addr;
}
/* unmap file */
int unmappit(void *addr, size_t len)
{
if( munmap(addr,len)==(-1))
return 1;
return 0;
}
/* find user in array, change time or (if not found) add to array */
void find(const struct utmp *src, int *cnt)
{
int i=0;
int found=0;
int limit=*cnt;
char tmp[10]={0x0};
snprintf(tmp, USER_NAME_LEN+1, "%s",src->ut_user);
if(strlen(tmp)> 0 )
{
for(i=0; !found && i < limit; i++)
{
if(strncmp(tmp, array[i].user, USER_NAME_LEN)==0)
{
found=1;
if(src->ut_time > array[i].logtime)
array[i].logtime=src->ut_time;
}
}
if(found==0)
{
memcpy(array[limit].user, tmp, USER_NAME_LEN);
array[limit].logtime=src->ut_time;
limit++;
}
*cnt=limit;
}
}
void setup_array(const void *addr, int *arrlen, const size_t ulen)
{
int i=0;
int max=ulen/sizeof(struct utmp);
int cnt=0;
const struct utmp *f=(const struct utmp *)addr;
for(i=0; i<max; i++, f++)
{
if(f->ut_type==USER_PROCESS && strlen(f->ut_user))
{
find(f, &cnt);
}
}
*arrlen=cnt;
}
int between(const time_t ckval, const time_t low, const time_t high)
{
int retval=(ckval >= low && ckval <= high);
return retval;
}
int search(const time_t low_limit, const time_t high_limit, int arrlen)
{
int i=0;
char tmp[80]={0x0};
time_t lt=0;
ulog_t *p=array;
for(i=0; i < arrlen; i++, p++)
{
if( (high_limit && between(p->logtime, low_limit, high_limit)) ||
(!high_limit && p->logtime < low_limit) )
{
lt=p->logtime;
strftime(tmp, sizeof(tmp), "%c", localtime(<));
printf("%s: last login %s\n", p->user, tmp);
}
}
return 0;
}
/*************************
*
* search for the last time each one logged on
* if logon in time range prt it
***************************/
int process(FILE *u, const time_t low_limit, const time_t high_limit)
{
int retval=0;
size_t ulen=filesize(fileno(u));
int arrlen=0;
void *addr=mappit(u, ulen);
setup_array(addr, &arrlen, ulen);
retval=search(low_limit, high_limit, arrlen);
retval|=unmappit(addr, ulen);
return retval;
}
/*
first argument req'd: # days
read from /var/adm/wtmp - (file used by last)
print all users with last logins < low_limit or with
last logins between low_limit and high_limit when
high_limit is non-zero
*/
int main(int argc, char **argv)
{
int retval=0;
const time_t low_limit= (argc>1) ? days_ago(atoi(argv[1])): 0;
const time_t high_limit=(argc>2) ? days_ago(atoi(argv[2])): 0;
FILE *u=fopen("/var/adm/wtmp", "r");
ck(u);
if ( low_limit > 0 && (high_limit==0 || high_limit >= low_limit))
retval=process(u, low_limit, high_limit);
else
{
fprintf(stderr,
"Bad parameters.\n\tONE required: <number days ago>\n\tOptional: <most recent day>\n");
fprintf(stderr," usage: utmp 10 5\n");
retval=1;
}
return retval;
}
|
|
||||
|
Is there a ".lastlogin" file in the users home directory. If this exists it has a size of 0 and its mtime is equal to the last login time.
So presumably: find / -name .lastlogin -mtime +40 If it doesn't exist you could add "touch .lastlogin" to each user's .profile and wait 40 days for the first occurence |
|
||||
|
Many thanks so far!!
Thanks for the suggestions!
Meanwhile I have come up with this! It's not fast, but it does the job! #!/usr/bin/ksh ##### # # Set up Global Variables # ##### MIN_DAYS=2 MAX_DAYS=90 DEF_GROUP="cpx" DATECALC="<patch_to_datecalc>" ##### # # Preliminary Tests # ##### # # Test for the correct parameters are passed or report Usage # case $# in 1) NUM_DAYS=$1 SEARCH_GROUP=$DEF_GROUP ;; 2) NUM_DAYS=$1 SEARCH_GROUP=$2 ;; *) echo "Usage: $(basename $0) <num_days> [ <group> ]" exit 1 ;; esac # # Test that the number of days passed is in range (and therefore a number) # if [ ${NUM_DAYS} -lt ${MIN_DAYS} ] || [ ${NUM_DAYS} -gt ${MAX_DAYS} ] then echo "<num_days> (${NUM_DAYS}) should be > ${MIN_DAYS} && < ${MAX_DAYS}" exit 1 fi # # Test that the group name passed exists # grep -q "^${SEARCH_GROUP}" /etc/group if [ $? = 1 ] then echo "<group> (${SEARCH_GROUP}) not found!" exit 1 fi ##### # # Declare Local Functions and populate arrays # ##### dateformat () { DATE_MONTH=$(echo "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec" | grep -n $2 | awk -F':' '{print$1}') print "$5 ${DATE_MONTH} $3" return 0 } ##### # # Start the program!!! # ##### SEARCH_NUM=$(grep "^${SEARCH_GROUP}" /etc/group | awk -F':' '{print$3}') TODAY=$(dateformat $(date | awk '{print $1" "$2" "$3" "$4" "$6}')) for i in $(grep "${SEARCH_NUM}" /etc/passwd | awk -F':' '{print$1}') do # # Make sure that this user has logged in before trying to process them # grep -p "^${i}" /etc/security/lastlog | grep -q time_last_login if [ $? = 0 ] then LOGGED_DATE=$(perl -le 'print scalar localtime shift' $(grep -p "^${i}" /etc/security/lastlog | grep time_last_login | awk '{print$3}')) LOGGED_IN=$(dateformat ${LOGGED_DATE}) DIFF_DAYS=$(${DATECALC} -a ${TODAY} - ${LOGGED_IN}) if [ ${DIFF_DAYS} -ge ${NUM_DAYS} ] then typeset -L9 USER="${i}:" typeset -R4 NUMBER=${DIFF_DAYS} echo "${USER} ${NUMBER} days (${LOGGED_DATE})" fi fi done Of course, my AIX coding is a bit rubbish, so if anyone can see how to speed this up I would be interested. I have used the datecalc script from this forum to perform the one date take away the other!! |
|
||||
|
My Linux code for those interested
#!/bin/bash
NUM_DAYS="0" TODAY_CODE=$(echo "$(date +%s) / 86400" | bc) for i in $(cat /etc/passwd | awk -F':' '{print $1}') do last | grep ${i} > /dev/null 2>&1 if [ $? -eq 0 ] then DATE_TEXT=$(last | grep ${i} | head -1 | awk '{print $5" "$6}') DATE_CODE=$(echo "$(date -d"${DATE_TEXT}" +%s) / 86400" | bc) DIFF_DAYS=$(echo "${TODAY_CODE} - ${DATE_CODE}" | bc) if [ ${DIFF_DAYS} -ge ${NUM_DAYS} ] then echo "${i} - ${DIFF_DAYS}" fi fi done |
![]() |
| Bookmarks |
| Tags |
| linux, mtime, perl, perl shift, shift, shift perl |
| Thread Tools | Search this Thread |
| Display Modes | Rate This Thread |
|
|