/*
    yamm, Yet Another Micro Monitor
    get_user.c
    Copyright (C) 1992  Andrea Marangoni
    Copyright (C) 1994, 1995  Riccardo Facchetti

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <pwd.h>
#include <grp.h>
#include <sys/stat.h>
#if !defined(linux) || (KERNEL_VERSION < 1001076)
#include <string.h>
#else
#include <linux/string.h>
#endif
#if defined(NCURSES)
# include "ncurses.h"
#else
# include <curses.h>
#endif /* NCURSES */

#include "yamm.h"

static struct _myuser {
	long uid, procs, t_size, t_rss;
	char name [ MAX_LOGIN + 1 ];
} user [ MAX_PROC ];

/*
 * actu: actual users in system
 */
static int actu = 0;

void set_users (void)
{
	register int count;

	for ( count = 0; count < MAX_PROC; ++count ) {
		user [ count ].name[ 0 ] = '\0';
		user [ count ].uid = -1L;
		user [ count ].procs = user [ count ].t_size =
								user [ count ].t_rss = 0L;
	}
}

#if defined(linux) && defined(MODULE)
char *get_group ( int index )
{
	struct group *g;
	int gid = pbuf [ index ].pst_gid;

	g = getgrgid(gid);

	if (g == NULL)
		return "???";
	return g->gr_name;
}
#endif /* linux && MODULE */

char *get_user_info ( int index )
{
	register int count;
	int uid = pbuf [ index ].pst_uid;

	for ( count = 0 ; count < actu && user [ count ].uid != uid; ++count );

	if ( count == actu ) {
/*
 * new_user in system
 */
		struct passwd *buf;

		if ( ( buf = getpwuid ( uid ) ) == NULL ) /* problem */
			sprintf ( user [ actu ].name, "(%d)", uid );
		else
			strncpy ( user [ actu ].name,  buf->pw_name, MAX_LOGIN );
			
		user [ actu ].name[ MAX_LOGIN ] = '\0';
		user [ actu ].uid = uid;
		++actu;
	}
				
	return ( user [ count ].name );
}

long get_user_id ( char *name )
{
	register int count;
	struct passwd *pwd;
	long uid;

	if ( !name )
		return ( -1L );

	if ( actu ) {
		for ( count = 0; count < actu &&
							strcmp ( user [ count ].name, name); ++count );
		if ( count != actu )
			return ( user [ count ].uid );
	}

	if ( ( pwd = getpwnam ( name ) ) == NULL )
		uid = -1L;
	else
		uid = pwd->pw_uid;
	
	return ( uid );
}

void get_user_sum ( int nproc, long *processes, long *t_size, long *t_rss )
{
	register int count;

	*processes = *t_size = *t_rss = 0L;

	for ( count = 0; count < nproc; ++count ) { 
		if ( pbuf [ count ].pst_uid != look_uid )
			continue;
		(*processes)++;
#if !defined(linux)
		*t_size += pbuf [ count ].pst_dsize +
				   pbuf [ count ].pst_tsize +
				   pbuf [ count ].pst_ssize;
#else
		*t_size += pbuf [ count ].pst_vsize;
#endif /* linux */
		*t_rss += pbuf [ count ].pst_rssize;
	}
}

void user_info(void)
{
	struct passwd *buf;
	struct group *grp;
	struct stat home;
	
#if !defined(NO_CURSES)
	if ( look_lines() < 24 ) {
		curses_error( "Sorry, you must have at least 24 lines." );
		return;
	}

/*	clear_screen();*/
#define PF (void)printw
#else
#define PF (void)printf
#endif /* !NO_CURSES */

	PF  ( "\nInformations about uid %ld.\n", look_uid );

	if ( ( buf = getpwuid ( look_uid ) ) == NULL ) { /* problem */
		PF  ( "\n\nProblems...! Can't get struct passwd of uid %ld\n",
			look_uid );
	} else {
		grp = getgrgid ( buf->pw_gid );


		PF  ( "\n\nName    : %s\n", buf->pw_name );
		PF  ( "Passwd  : \"%s\"", buf->pw_passwd );

#if !defined(linux)
		if ( buf->pw_passwd [ 0 ] == '*' && 
			buf->pw_audid == -1 && buf->pw_audid == -1 )
			PF ( " ( Probably You don't have permission to read encrypted password )\n");
		else
#else
		if (buf->pw_passwd [ 0 ] == '*' || (buf->pw_passwd [ 0 ] == 'x' &&  buf->pw_passwd [ 1 ] == '\0'))
			PF ( " ( Probably You don't have permission to read encrypted password )\n");
		else
#endif /* !linux */
			PF ("\n");

		PF  ( "Uid     : %d ( %s )\n", buf->pw_uid, buf->pw_name );
		PF  ( "Gid     : %d ( %s )\n", buf->pw_gid,
			grp ? grp->gr_name : "???" );
#if !defined(linux)
		PF  ( "Age     : %s\n", buf->pw_age );
		PF  ( "Comment : %s\n", buf->pw_comment );
#endif /* !linux */
		PF  ( "Gecos   : %s\n", buf->pw_gecos );
		PF  ( "Home Dir: %s", buf->pw_dir );

		if ( stat ( buf->pw_dir, &home ) == -1 )
			PF ( " ( Can't read permission )\n" );
		else
			PF ( " ( %c%c%c%c%c%c%c%c%c )\n",
				home.st_mode & S_IRUSR ? 'r' : '-',
				home.st_mode & S_IWUSR ? 'w' : '-',
				home.st_mode & S_IXUSR ? 'x' : '-',
				home.st_mode & S_IRGRP ? 'r' : '-',
				home.st_mode & S_IWGRP ? 'w' : '-',
				home.st_mode & S_IXGRP ? 'x' : '-',
				home.st_mode & S_IROTH ? 'r' : '-',
				home.st_mode & S_IWOTH ? 'w' : '-',
				home.st_mode & S_IXOTH ? 'x' : '-' );

		PF  ( "Shell   : %s\n", buf->pw_shell );
#if !defined(linux)
		PF  ( "Audid   : %ld\n", buf->pw_audid );
		PF  ( "Audflg  : %ld\n", buf->pw_audflg );
#endif /* !linux */
	}
}

void Print_Who( int nproc )
{
	register int count, count2;
	char *cp;

	/********** setup_user *********/

	for ( count = 0; count < MAX_PROC; ++count )
		user [ count ].procs =
		user [ count ].t_size =
		user [ count ].t_rss = 0L;

/*
 * Read in all the user list, to be sure to compute all the users
 */
	for ( count = 0; count < nproc; ++count )
		cp = get_user_info(count);

/*
 * Compute
 */
	for ( count = 0; count < nproc; ++count )
		for ( count2 = 0; count2 < actu; ++count2 ) {
			if ( pbuf [ count ].pst_uid != user [ count2 ].uid )
				continue;
			user [ count2 ].procs++;
#if !defined(linux)
			user [ count2 ].t_size += pbuf [ count ].pst_dsize +
								 pbuf [ count ].pst_tsize +
								 pbuf [ count ].pst_ssize;
#else
			user [ count2 ].t_size += pbuf [ count ].pst_vsize;
#endif /* !linux */
			user [ count2 ].t_rss += pbuf [ count ].pst_rssize;
		}

	/******************************/


#if !defined(NO_CURSES)
#define PF (void)printw
#else
#define PF (void)printf
#endif /* !NO_CURSES */

/*
 * This loop is similar to the main loop
 */
	PF ( "\nUSER        UID    NPROCS    TOTAL_SIZE        TOTAL_RSS\n" );

	for ( count = count2 = displayed = 0; count < actu; ++count ) {

#if !defined(NO_CURSES)
		if ( count2++ < pages*Num_display_proc )
			continue;
#endif /* !NO_CURSES */

		if ( user [ count ].procs == 0 )   /* user logout */
			continue;

		if ( Num_display_proc >= 0 && displayed >= Num_display_proc )
			break;

		displayed++;

		PF ( "%-*s  %5ld    %4ld        %s", MAX_LOGIN,
			user [ count ].name,
			user [ count ].uid,
			user [ count ].procs,
			get_dimension ( user [ count ].t_size ));
		PF ( "          %s\n",
			get_dimension ( user [ count ].t_rss ));
	}
}
