Last time logged in


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting Last time logged in
# 1  
Old 04-23-2007
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!
# 2  
Old 04-25-2007
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(&lt));
			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;
}

# 3  
Old 04-25-2007
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
# 4  
Old 04-25-2007
He may also want network logins...

Reading an accounting file is pretty much guaranteed to find everybody.
# 5  
Old 04-26-2007
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!!
# 6  
Old 04-26-2007
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
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

• Write a shell script that upon invocation shows the time and date and lists all the logged-in user

help me (1 Reply)
Discussion started by: sonu pandey
1 Replies

2. Homework & Coursework Questions

Sort current logged in users by log in time (supposedly to be very easy but I'm missing something)

1. The problem statement, all variables and given/known data: Show all users who are currently logged in, sorted from earliest to latest log in time. The log in time includes the month, day, and time. 2. Relevant commands, code, scripts, algorithms: finger, who, sort, pipe, head, tail, ... (8 Replies)
Discussion started by: vtmd
8 Replies

3. UNIX for Dummies Questions & Answers

Script to determine logged in time

Hi all So I am thinking my inability to cope with math is bogging me down here so Im asking for help. I want to determine how long a user has been logged on for by using the date and who commands to determine the time they have been logge don. My problem is that I keep getting the wrong... (2 Replies)
Discussion started by: losingit
2 Replies

4. Shell Programming and Scripting

Shell script to display user logged last week and time connected

Hello all, I want to display all the user logged last week and know the time tnat they are connected. I have been looking for a solution in the Forum, but I didn't find. Thanks in advance (4 Replies)
Discussion started by: ahernandez
4 Replies

5. UNIX Desktop Questions & Answers

Shell script to display user logged in within given time

how can i know which users have logged in at specified given start and end time in 24 hour format? (3 Replies)
Discussion started by: meherzad4u
3 Replies

6. UNIX for Dummies Questions & Answers

Finding users logged on time and space useage

I need to find what users are currently logged onto the system that is easy just a simple who | awk '{ print $1 }' (thats all I need for the part), but I also need to find how long they have been logged on and the total amount of file space they are using. Thanks in advance, I have been looking... (3 Replies)
Discussion started by: mauler123
3 Replies

7. UNIX for Dummies Questions & Answers

How to do a login time and date list of users never logged on?

Hello, I'm trying to do a list of user that never connected to a couple of servers. I want to do a diff between the servers lists, and print out only the users that never has logged on each server. Here my first step : SERVER01: # finger `egrep -v -e "^\s*#" /etc/passwd | awk '{ print $1 }' |... (4 Replies)
Discussion started by: gogol_bordello
4 Replies

8. UNIX for Dummies Questions & Answers

How many time have user logged last X days?

Hi all.. I was trying to do a little shell script, that would list users and their login times, lets say like last 5 days. But I couldnt figure out how to count users login times from previous days. Any tips? Funny that nobody has do this kinda script before, or atleast I couldnt find on... (2 Replies)
Discussion started by: Kimmo_
2 Replies

9. Shell Programming and Scripting

How can one know how much time user logged?

Hello, i know who command gives you the time when particular user logged in. And subtracting today's date and time from the one found in who we can get how much time user logged in. But this can get very much clumsy as we can't subtract date directly in unix . Is there any other way or command... (4 Replies)
Discussion started by: salman4u
4 Replies

10. UNIX for Dummies Questions & Answers

Finding last time users logged in

I would like to find out the last time all users have logged in or out. I tried the last command, but it could not find the wtmp file in /var/adm (I searched in othe directories also). This is an AIX rs6000 4.2.1 system. We are moving our applications from this system to an AIX 5.2 system and I... (11 Replies)
Discussion started by: jyoung
11 Replies
Login or Register to Ask a Question