ups

Denys Vlasenko schrieb:
> On Tuesday 10 February 2009 20:02, walter harms wrote:
>> Hello List,
>> this version add "who mom loves" and "who i am" closing the last gaps
>> for the SUS specification. I shrink the if() section just give the
>> space to the "mom loves" etc.
>>
>> please test and report bugs if you see them
>>
>>   size coreutils/who.o
>>    text    data     bss     dec     hex filename
>>    2459       0      20    2479     9af coreutils/who.o
> 
> Looks like you forgot to attach the patch.
> --
> vda
> 
> 
> 
/* vi: set sw=4 ts=4: */
/*
 * SUSv3 who implementation for busybox
 *
 * Copyright (C) 2008 by Walter Harms 
 * http://www.opengroup.org/onlinepubs/9699919799/utilities/who.html
 *
 * BB_AUDIT SUSv3 defects - 
 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
 * $Id: who.c,v 1.16 2009/02/03 22:16:39 walter Exp walter $
 */

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

#define  ENABLE_FEATURE_GLOBAL_BUFFER  0
#define  ENABLE_FEATURE_POSIX_TIMEFMT  0

#if ENABLE_FEATURE_POSIX_TIMEFMT
#define TIMEFMT       "%b %e %H:%M"
#else
#define TIMEFMT       "%Y-%m-%d %T"
#endif

/*
  who -q file
  who [-mu]-s[-bHlprt][<file>]
  -a enables:  -b,-d, -l, -p, -r, -t, -T and -u 
  no support for 'who am i' or 'mom loves'  
*/

// "%b %e %H:%M" 
//
// char bb_common_bufsiz1[COMMON_BUFSIZE]
// move this to libbb ??


#if ENABLE_FEATURE_GLOBAL_BUFFER

static char *time2str(const char *fmt, time_t t)
{
	strftime(bb_common_bufsiz1, COMMON_BUFSIZE, fmt, localtime(&t));
	return bb_common_bufsiz1;
}
#else
static char *time2str(const char *fmt, time_t t)
{
	static char buf[20];

	strftime(buf, sizeof(buf), fmt, localtime(&t));
	return buf;
}

#endif


#define OPT_a   1		/*  -b,-d, -l, -p, -r, -t, -T and -u  */
#define OPT_b   2		/* last reboot */
#define OPT_d   4		/* dead process */
#define OPT_H   8		/* add Header */
#define OPT_l   16		/* login process */
#define OPT_m   32		/* current terminal only */
#define OPT_p   64		/* processes spawn by init */
#define OPT_q   128		/* quick */
#define OPT_r   256		/* current runlevel */
#define OPT_s   512		/* default */
#define OPT_t   1024	/* last time change */
#define OPT_T   2048	/* add time of login */
#define OPT_u   4096	/* idle */
#define OPT_D   8192	/* debug DUMPFILE */


/* option -w:  like q with full info, GNU extension  */

static int _stat(char *line, struct stat *st)
{
	int ret;

	line = xasprintf("/dev/%s", line);
	ret = stat(line, st);
	free(line);
	return ret;
}

static char term_state(char *line)
{
	struct stat st;

	if (_stat(line, &st) < 0) {
		return '?';
	} else {
		if (st.st_mode & S_IWOTH)
			return '-';
	}
	return '+';
}


static void idle_time(char *line)
{
	struct stat st;
	time_t t;

	if (_stat(line, &st) < 0) {
		putchar('?');
		goto print;
	}


	/* one of the few occation we use atime */
	t = time(NULL) - st.st_atime;

	if (t < 60) {
		putchar('.');
		goto print;
	}

	/* always  t >= 0 && */
	if (t < (24 * 60 * 60)) {
		printf("%02d:%02d",
			   (int) (t / (60 * 60)), (int) ((t % (60 * 60)) / 60));

	} else
		printf("old");

  print:
	putchar('\t');

}

enum {
	NAME = 1 << 0,
	STATE = 1 << 1,
	LINE = 1 << 2,
	TIME = 1 << 3,
	ACTIVITY = 1 << 4,
	PID = 1 << 5,
	COMMENT = 1 << 6,
	EXIT = 1 << 7
};


static void print_header(int pattern)
{

#define	str             "NAME\0"\
		        "STATE\0"\
		        "LINE\0"\
		        "TIME\0"\
		        "ACTIVITY\0"\
		        "PID\0"\
		        "COMMENT\0"\
		        "EXIT"

	int i = 0;

	if (pattern < 0)
		return;

	while (pattern) {
		if (pattern & 1)
			printf("%s\t", nth_string(str, i));

		pattern >>= 1;
		i++;
	}
	putchar('\n');
#undef str
}


/*
 print content of struct utmp, select what with mask 
*/

static void print_ut(struct utmp *ut, int mask)
{
#define str            "EMPTY\0"\
                       "RUN_LVL\0"\
                       "BOOT_TIME\0"\
                       "NEW_TIME\0"\
                       "OLD_TIME\0"\
	               "INIT_PROCESS\0"\
                       "LOGIN_PROCESS\0"\
	               "USER_PROCESS\0"\
	               "DEAD_PROCESS\0"\
		       "ACCOUNTING"

/*
   10 = number of strings in str
*/


	if (option_mask32 & OPT_D)
		printf("%s\t", nth_string(str, ut->ut_type % 10));
#undef str

	if (mask & NAME)
		printf("%s\t", ut->ut_user);	/* NAME */

	if (mask & STATE)
		printf("%c\t", term_state(ut->ut_line));	/* STATE */

	if (mask & LINE)
		printf("%s\t", ut->ut_line);	/* LINE */

	if (mask & TIME)
		printf("%s\t", time2str(TIMEFMT, ut->ut_tv.tv_sec));	/* TIME */

	if (mask & ACTIVITY)
		idle_time(ut->ut_line);	/* ACTIVITY */

	if (mask & PID)
		printf("%d\t", ut->ut_pid);	/* PID */

	if (mask & COMMENT)
		printf("ID=%s\t%s\t", ut->ut_id, ut->ut_host);	/* COMMENT */


	if (mask & EXIT)
		printf("%d/%d", ut->ut_exit.e_termination, ut->ut_exit.e_exit);	/* EXIT */

	putchar('\n');
}

int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;

	int who_main(int argc UNUSED_PARAM, char **argv)
{
	struct utmp *ut;
	char *name;
	unsigned int ucnt = 0;
	//	int pattern = -1;
	int pattern= NAME| LINE | TIME ;
	unsigned int opt;

	/*
	   FIXME: make better use of opt_complementary
	 */
	//  opt_complementary = "q-abdHlmqprstuD";

	opt = getopt32(argv, "abdHlmpqrstTuD");
	argv += optind;

	argc-=optind;
/*
  utmpname() will not fail if the file does not exists
*/


	if (opt == 0)
		opt = OPT_s;
	if (opt == OPT_u)
		opt |= OPT_s;

	if (opt & OPT_a)
		opt |= (OPT_b | OPT_d | OPT_l | OPT_p | OPT_r | OPT_T | OPT_u);



	switch (argc) {

	case 1:
	     utmpname(*argv);
	     break;

	case 2:
	      if ( (strcmp(*argv,"mom") == 0 && strcmp(*(argv+1),"loves") == 0) ||
	           (strcmp(*argv,"am")  == 0 && strcmp(*(argv+1),"i") == 0) )
		opt|=OPT_m;	   
		/* fall tru */
	case 0:
	  break;	  

	default:
	  fprintf(stderr,"to many arguments\n");
	  exit(1);
	}
	/*
	   figure out pattern to figure out pattern for heading
	 */

	if (opt & OPT_T)
		pattern |= (opt & OPT_u) ?  STATE | COMMENT | ACTIVITY :  STATE | COMMENT;

	else if (opt & OPT_s) {
	     if (opt & OPT_u)  
	       pattern |= ACTIVITY ;
	}

	else if (opt & OPT_l)
		pattern |= (opt & OPT_u) ?  PID | COMMENT | ACTIVITY :   PID | COMMENT;

	else if (opt & OPT_p)
		pattern |= (opt & OPT_u) ?  PID | COMMENT | EXIT | ACTIVITY :  PID | COMMENT | EXIT;
	else if (opt & OPT_D)
		pattern |=   PID | COMMENT | EXIT;

	/*
	 * if anyone has a console outside /dev we will ignore it
	 */
	if (opt & OPT_m) {
		name = ttyname(STDIN_FILENO);
		if (!name || strncmp(name, "/dev/", 5))
			bb_perror_msg_and_die("ttyname()");
		name += 5;
		/*
		   else 
		   something strange is going on
		   can this ever happen ?
		 */

	}

	setutent();

	if (opt & OPT_H)
		print_header(pattern);
#if 0

	while ((ut = getutent()) != NULL) {

		/* -m : only current terminal */
		if (opt & OPT_m && strcmp(name, ut->ut_line))
			continue;

		/* -b */
		if ((opt & OPT_b) && BOOT_TIME == ut->ut_type) {
			if (opt & OPT_H)
				printf("last reboot\t");

			print_ut(ut, TIME);

			/*
			   if OPT_a is set we have to show this here only once
			   and continue to handle the other options
			 */

			if (opt & OPT_a)
				opt &= ~OPT_b;
			else
				break;
		}

		/* -d */
		if ((opt & OPT_d) && DEAD_PROCESS == ut->ut_type) {
			print_ut(ut, pattern);
		}

		/* -l */
		if ((opt & OPT_l) && LOGIN_PROCESS == ut->ut_type) {
			print_ut(ut, pattern);
		}

		/* -p */
		if ((opt & OPT_p) && INIT_PROCESS == ut->ut_type) {
			print_ut(ut, pattern);
		}

		/* -q */
		if ((opt & OPT_q) && USER_PROCESS == ut->ut_type) {
			printf("%s ", ut->ut_user);
			ucnt++;
		}

		/* -r */
		if ((opt & OPT_r) && RUN_LVL == ut->ut_type) {
			if (opt & OPT_H)
				printf("Current\tTime\t\tLast\n");

			printf("%s %c\t%s\t%c\n",
				   ut->ut_user, ut->ut_pid & 255,
				   time2str(TIMEFMT, ut->ut_tv.tv_sec),
				   (ut->ut_pid >> 8) ? 'N' : (ut->ut_pid >> 8));

			if (opt & OPT_a)
				opt &= ~OPT_r;
			else
				break;
		}

		/* -s | default */
		if ((opt & OPT_s) && USER_PROCESS == ut->ut_type) {
			print_ut(ut, pattern);
		}

		/* -t */
		if ((opt & OPT_t) && NEW_TIME == ut->ut_type) {
			if (opt & OPT_H)
				printf("last time change\t");
			print_ut(ut, TIME);
			break;
		}

		/* -T */
		if ((opt & OPT_T) && USER_PROCESS == ut->ut_type) {
			print_ut(ut, pattern);
		}

		/* -D debug option */
		if (opt & OPT_D)
			print_ut(ut, pattern);

	}					/* while */
#else

	while ((ut = getutent()) != NULL) {

		/* -m : only current terminal */
		if (opt & OPT_m && strcmp(name, ut->ut_line))
			continue;

		/* -b */
		if ((opt & OPT_b) && BOOT_TIME == ut->ut_type) {
			if (opt & OPT_H)
				printf("last reboot\t");

			print_ut(ut, TIME);

			/*
			   if OPT_a is set we have to show this here only once
			   and continue to handle the other options
			 */

			if (opt & OPT_a)
				opt &= ~OPT_b;
			else
				break;
		}


		if (
		    ((opt & OPT_d) && DEAD_PROCESS == ut->ut_type)  ||		/* -d */
		    ((opt & OPT_l) && LOGIN_PROCESS == ut->ut_type) ||           /* -l */
	            ((opt & OPT_p) && INIT_PROCESS == ut->ut_type)  ||           /* -p */
		    ((opt & OPT_s) && USER_PROCESS == ut->ut_type)  ||          /* -q */
                    ((opt & OPT_T) && USER_PROCESS == ut->ut_type)  ||           /* -T */
		    (opt & OPT_D) ) {
			print_ut(ut, pattern);
		}

		
		/* -q */
		if ((opt & OPT_q) && USER_PROCESS == ut->ut_type) {
			printf("%s ", ut->ut_user);
			ucnt++;
		}

		/* -r */
		if ((opt & OPT_r) && RUN_LVL == ut->ut_type) {
			if (opt & OPT_H)
				printf("Current\tTime\t\tLast\n");

			printf("%s %c\t%s\t%c\n",
				   ut->ut_user, ut->ut_pid & 255,
				   time2str(TIMEFMT, ut->ut_tv.tv_sec),
				   (ut->ut_pid >> 8) ? 'N' : (ut->ut_pid >> 8));

			if (opt & OPT_a)
				opt &= ~OPT_r;
			else
				break;
		}


		/* -t */
		if ((opt & OPT_t) && NEW_TIME == ut->ut_type) {
			if (opt & OPT_H)
				printf("last time change\t");
			print_ut(ut, TIME);
			break;
		}


	}					/* while */



#endif




/*
  write user count
*/

	if (opt & OPT_q)
		printf("\n#User %d\n", ucnt);

	if (ENABLE_FEATURE_CLEAN_UP)
		endutent();


	return EXIT_SUCCESS;
}
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to