#include "yawho.h"
#include <utmp.h>

#ifndef UTMP_FILE
#define UTMP_FILE 	"/var/run/utmp"
#endif

#ifdef HAVE_USER_IN_UTMP
#define	__user		ut_user
#endif

#ifdef HAVE_NAME_IN_UTMP
#define __user		ut_name
#endif

#define WIDTH_TO_COMMAND 	55

struct utmp ent;

int check_args(char *login, char **argv, int i)
{
	while(argv[i]) {
		if(!strncmp(argv[i], login, UT_NAMESIZE))
			return 1;
		i++;
	}
	return 0;
}

int main(int argc, char **argv)
{
	int all = 0;
	int ssh_users, telnet_users, local_users;
    	int fd, pid, ppid, i, tab_el, longopt = 0;
    	int columns = -1;
    	char login[UT_NAMESIZE + 1], *command;    
	struct winsize win;
	struct procinfo p;
		
	void *tab[] = { 
#ifdef LINUX
		     "(sshd)",   	&ssh_users,
		     "(sshd1)", 	&ssh_users,
		     "(sshd2)",		&ssh_users,
		     "(in.telnetd)", 	&telnet_users,
		     "(init)", 		&local_users
#endif
#ifdef BSDISH
		     "telnetd",		&telnet_users,
		     "sshd", 		&ssh_users,
		     "sshd1",		&ssh_users,
		     "sshd2",		&ssh_users,
		     "init", 		&local_users
#endif
		    };
	if(argc > 1 && argv[1][0] == '-') {
		if(argv[1][1] == 'l') longopt = 1;
		else {
			fprintf(stderr,
				"Unknown option.\nUsage: yawho [-l] [user ...] \n"
				"-l\tLong display (don't cut processes names)\n");
			exit(1);
		}
	}
#ifdef HAVE_SYS_IOCTL_H
	if(ioctl(1,TIOCGWINSZ,&win) != -1) {
		columns = win.ws_col;
		if (columns < 80) {
			fprintf(stderr,"\t####### WARNING #######\n");
			fprintf(stderr,"Screen width less than 80. Output could be unreadable.\n");
		}
	}
#endif

	tab_el = sizeof tab/sizeof(void*);
	for(i = 0; i < tab_el ; i += 2) 
		*(int *)tab[i+1] = 0;
		
    	if((fd = open(UTMP_FILE ,O_RDONLY)) == -1) {
		fprintf(stderr, "Cannot open " UTMP_FILE "\n"); 
		exit(1);
	}

    	printf("DAEMON        USER      TTY    SHP    FROM             WHAT\n");
    
    	while(read(fd, &ent, sizeof(ent))) {
		strncpy(login, ent.__user, UT_NAMESIZE);
		login[UT_NAMESIZE] = '\0';	
#ifdef HAVE_PID_IN_UTMP
		pid = ent.ut_pid;
#endif

#ifdef HAVE_UPROCESS_TYPE
		if(ent.ut_type != USER_PROCESS) continue;
#else
		if(ent.__user[0] == '\0') continue;
#endif
		all++;

#ifndef HAVE_PID_IN_UTMP
		pid = get_login_pid(ent.ut_line);
#endif
		ppid = get_ppid(pid);
 		get_info(ppid, &p);
		do {
			if (p.exec_file[0] != '(') break;
			for(i = 0; i < tab_el ; i += 2)
				if (!strcmp((char *) tab[i], p.exec_file))
					goto found;
			ppid = get_ppid(ppid);
			get_info(ppid, &p);
		} while (ppid != 1);
found:
		if(ppid == 1) {
			ppid = get_ppid(pid);
			get_info(ppid, &p);
		}
		for(i = 0; i < tab_el ; i += 2)
			if (!strcmp((char *) tab[i], p.exec_file))
				( *(int *)tab[i+1] )++;
		if((argc > 1 && !longopt) || argc > 2)
			if(!check_args(ent.__user, argv, longopt + 1))
				continue;

		printf("%-13.13s %-9.9s %-6.6s %-6d %-16.16s ",
	    		p.exec_file, 
	    		login,
	    		ent.ut_line + (strncmp("tty",ent.ut_line,3)?0:3),
	    		pid, 
	    		ent.ut_host
			);
		command = get_command(pid);
		/* don't know real screen width, assume it is 80 */
		if(columns == -1) {
			printf(longopt?"%s\n":"%-24.24s\n", command);
			continue;
		}
		/* screen is really too small so we don't care */
		if(columns <= WIDTH_TO_COMMAND) {
			printf("%s\n", command);
			continue;
		}
		for(i = 0; *(command + i); i++) {
			if(!longopt && i == columns - WIDTH_TO_COMMAND) 
				break;
			printf("%c",*(command+i));
		}
		if(i != columns - WIDTH_TO_COMMAND) printf("\n");
    	}
	close(fd);
	printf("\n%d user%s",all,all?"s ":" ");
	printf ("(%d local, %d telnet, %d ssh, %d other)\n",
		local_users,
		telnet_users ,
		ssh_users, 
		all-telnet_users-ssh_users-local_users
		);
	return 0;
}

syntax highlighted by Code2HTML, v. 0.9.1