SUSv3 who for Busybox

walter harms wharms at bfs.de
Tue Dec 9 08:44:14 UTC 2008



Tito schrieb:
> Hi,
> here a few comments on who.c
> Just my 2 cents.
> 
> Ciao,
> Tito
> 
> On Monday 08 December 2008 17:55:19 walter harms wrote:
>> Hi list,
>> while replacing "touch" with a SUSv3 "touch" i noticed that the "who"-command
>> does support only one of several option that a propper "who" should support.
>>
>> The who.c is a drop-in-replacement for the current who.c. it will support
>> all SUSv3 options but the file support.
>>
>> please give the current version a try.
>>> /* vi: set sw=4 ts=4: */
>> /*
>>  * SUSv3 who implementation for busybox
>>  *
>>  * Copyright (C) 2008 by  <u173034 at informatik.uni-oldenburg.de>
>>  * http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html
>>  *
>>  * no long option support yet
>>  * Licensed under GPLv2 or later, see file LICENSE in this tarball for
>> details. * $Id: who.c,v 1.4 2008/12/07 19:13:17 walter Exp walter $
>>  */
>>
>> #include "libbb.h"
>> #include <utmp.h>
>> #include <time.h>
>>
>> // who -q file
>>
>> // who [-mu]-s[-bHlprt][<file>]
>> // -a schaltet:  -b,-d, -l, -p, -r, -t, -T and -u
>>
>> // -b time date of last reboot
>>
>> #if 0
>>
>>  
>> </name/>*[*</state/>*]*</line/></time/>*[*</activity/>*][*</pid/>*][*</comm
>> ent/>*][*</exit/>*]*
>>
>> struct utmp
>> {
>>   short int ut_type;            /* Type of login.  */
>>   pid_t ut_pid;                 /* Process ID of login process.  */        
>>        </pid /> char ut_line[UT_LINESIZE];    /* Devicename.  */           
>>                      </line/> char ut_id[4];                /* Inittab ID. 
>> */
>>   char ut_user[UT_NAMESIZE];    /* Username.  */                           
>>      </name/> char ut_host[UT_HOSTSIZE];    /* Hostname for remote login. 
>> */
>>   struct exit_status ut_exit;   /* Exit status of a process marked
>>                                    as DEAD_PROCESS.  */
>> /* The ut_session and ut_tv fields must be the same size when compiled
>>    32- and 64-bit.  This allows data files and shared memory to be
>>    shared between 32- and 64-bit applications.  */
>> #if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
>>   int32_t ut_session;           /* Session ID, used for windowing.  */
>>   struct
>>   {
>>     int32_t tv_sec;             /* Seconds.  */
>>     int32_t tv_usec;            /* Microseconds.  */
>>   } ut_tv;                      /* Time entry was made.  */
>> #else
>>   long int ut_session;          /* Session ID, used for windowing.  */
>>   struct timeval ut_tv;         /* Time entry was made.  */
>> #endif
>>
>>   int32_t ut_addr_v6[4];        /* Internet address of remote host.  */
>>   char __unused[20];            /* Reserved for future use.  */
>> };
>>
>> #endif
>>
>>
>> // "%b %e %H:%M"
>>
>> static char *time2str(const char *fmt,time_t t)
>> {
>>   static char buf[20];
>>   strftime(buf,sizeof(buf),fmt,localtime(&t));
>>   return buf;
>> }
> 
>  Just one caller for term_state.
> 

	yep, reason:
	1. it is more easy to debug
        2. gcc will inline optimized code, i got some good results with that


>> static char term_state(char *line)
>> {
>>   struct stat st;
>>   char c='+';
>>
>>   line=xasprintf("/dev/%s",line);
>>
>>
>>   if (stat(line,&st)<0)   {
>>     c= '?' ;
>>     }
>>   else    {
>>       if ( st.st_mode & S_IWOTH )
>>       c='-' ;
>>     }
>>
>>   free(line);
>>   return c;
>> }
> 
> Just one caller for idle time and could share some code
> with term state.
> 
>   line=xasprintf("/dev/%s",line);
>    if (stat(line,&st)<0)   {
>      c= '?' ;
> 
>   line=xasprintf("/dev/%s",line);
>    if ( stat(line,&st) < 0 )
>      return (char *)"?";
>> static char *idle_time(char *line)
>> {
>>         struct stat st;
>> 	time_t t;
>> 	static char buf[6]="old";
>> 	line=xasprintf("/dev/%s",line);
>> 	if ( stat(line,&st) < 0 )
>> 	  return (char *)"?";
>>
>> 	/* one of the few occation we use atime */
>>         t = time(NULL) - st.st_atime;
>>
>>         if (t < 60) {
>>                 return (char *)".";
>>         }
>>
>>         if (t >= 0 && t < (24 * 60 * 60)) {
>>                 sprintf(buf, "%02d:%02d",
>>                                 (int) (t / (60 * 60)),
>>                                 (int) ((t % (60 * 60)) / 60));
>>
>>         }
>>         return buf;
>>
>> }
>>
>> static const char *str[]= { " EMPTY"," RUN_LVL"," BOOT_TIME"," NEW_TIME","
>> OLD_TIME", " INIT_PROCESS"," LOGIN_PROCESS"," USER_PROCESS","
>> DEAD_PROCESS", " ACCOUNTING" };
>>
>>
> 
> Just one caller and one printf call should be enough.
> 
	you are right, i have already merge that with print_ut


>> static void print_all(struct utmp *ut)
>> {
>>   printf("type:%s\n",str[ut->ut_type % ARRAY_SIZE(str)] );
>>   printf("pid :%d\n",ut->ut_pid);

>> };
> 
> 
> Code obfuscation? ;-)
> 
it was not intended that way, i can use expand-macro if you like that better :)



>> #define HEAD(NAME)   if (pattern&NAME) printf("%s\t",#NAME)
>>
>> static void   print_header( int pattern)
>> {
>>   if (pattern<0) return;
>>   HEAD(NAME);
>>   HEAD(STATE);
>>   HEAD(LINE);
>>   HEAD(TIME);
>>   HEAD(ACTIVITY);
>>   HEAD(PID);
>>   HEAD(COMMENT);
>>   HEAD(EXIT);
>> }
>>
>>
>> static void print_ut(struct utmp *ut, int mask)
>> {
>>   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("%b %e %H:%M",ut->ut_tv.tv_sec) );  /* TIME */
>>
>>   if (mask&ACTIVITY)
>>     printf("%s\t",idle_time(ut->ut_line) );                    /* ACTIVITY
>> */
>>
>>   if (mask&PID)
>>     printf("%d\t",ut->ut_pid);	                             /* PID */
>>
>>   if (mask&COMMENT) {
> 
> One printf call should be enough
> 
>>     printf("ID=%s\t",ut->ut_id);	                             /* COMMENT */
>>     printf("%s\t",ut->ut_host);	                             /* COMMENT */
>>   }
>>
>>   if (mask&EXIT) {
> 
> One printf call should be enough
> 
>>     printf("%d/",ut->ut_exit. e_termination);                 /* EXIT */
>>     printf("%d\t",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;
>>
>> 	/*
>> 	  filename hier setzen
>> 	int utmpname();
>> 	*/
>>
>> 	opt_complementary="q-abdHlmqprstuD";
>> 	getopt32(argv, "abdHlmpqrstTuD");
>>
>> 	if (option_mask32 == 0) option_mask32=OPT_s;
>> 	if (option_mask32 == OPT_u) option_mask32|=OPT_s;
> 
> Could be done witj getopt32:
>  "abc"  If groups of two or more chars are specified, the first char
>         is the main option and the other chars are secondary options.
>         Their flags will be turned on if the main option is found even
>         if they are not specifed on the command line.
> 


i could not figure out what i could do with opt_complementary and testing was very laborious.
I thing we will fix that after with the code is working propperly.


>> 	if (option_mask32 & OPT_a )
>> option_mask32|=(OPT_b|OPT_d|OPT_l|OPT_p|OPT_r|OPT_T|OPT_u);
>>
>> #if 0
>> 	if (option_mask32 & OPT_H)
>> 	if (option_mask32 & (OPT_s|OPT_d|OPT_l) ) {
>> 		printf("name\t");
>> 		if (option_mask32 & OPT_H)  printf("state\t");
>> 		printf("line\t");
>> 		printf("time\t");
>> 		if (option_mask32 & (OPT_u|OPT_H) )  printf("activity\t");
>> 		if (option_mask32 & (OPT_d|OPT_H) )  printf("pid\t");
>> 		if (option_mask32 & OPT_H)  printf("comment\t");
>> 		if (option_mask32 & (OPT_d|OPT_H) )  printf("exit");
>> 		putchar('\n');
>> 	}
>> #endif
>> 	/*
>> 	  figure out pattern to figure out pattern for heading
>> 	*/
>>
>> 	if (option_mask32&OPT_T)
>> 	  pattern=(option_mask32&OPT_u) ?
>> NAME|STATE|LINE|TIME|PID|COMMENT|ACTIVITY
>>
>> 		                        : NAME|STATE|LINE|TIME|PID|COMMENT ;
>>
>> 	else
>> 	  if (option_mask32&OPT_s)
>> 	  pattern=(option_mask32&OPT_u) ? NAME|LINE|TIME|ACTIVITY
>>
>> 		                        : NAME|LINE|TIME;
>>
>> 	 else
>> 	  if (option_mask32&OPT_l)
>> 	  pattern=(option_mask32&OPT_u) ? NAME|LINE|TIME|PID|COMMENT|ACTIVITY
>>
>> 		                        : NAME|LINE|TIME|PID|COMMENT;
> 
> Option p is listed 2 times, is this ok?

 good catch noone noticed that before.



>> 	 else
>> 	   if (option_mask32&OPT_p)
>> 	   pattern=(option_mask32&OPT_u) ?
>> NAME|LINE|TIME|PID|COMMENT|EXIT|ACTIVITY
>>
>> 	                                 : NAME|LINE|TIME|PID|COMMENT|EXIT;
>>
>


for testing i will keep the printf separated. i will merge them shortly before the code will move into the svn.

thx for your testing,

re,
 wh





More information about the busybox mailing list