SUSv3 who for Busybox

Bernhard Reutner-Fischer rep.dot.nop at gmail.com
Mon Dec 8 17:16:16 UTC 2008


On Mon, Dec 08, 2008 at 05:55:19PM +0100, 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.

>/* 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

+ /* BB_AUDIT SUSv3 defects - missing long options, missing file support */

Makes it easier to grep for them.

> * 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 $

Please remove the $Id: line

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

>#include <time.h>

redundant include
>
>// who -q file
>
>// who [-mu]-s[-bHlprt][<file>]
>// -a schaltet:  -b,-d, -l, -p, -r, -t, -T and -u 

Niemand schaltet hier irgendetwas ;)
-a forces on / turns on: ....

>
>// -b time date of last reboot

And it would be awesome if you could use C89 comments, i.e. /* */
otherwise there are warnings from C89 compilers.

>#if 0
>
>  </name/>*[*</state/>*]*</line/></time/>*[*</activity/>*][*</pid/>*][*</comment/>*][*</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;
>}
>
>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;
>}
>
>
>static char *idle_time(char *line)
>{
>        struct stat st;
>	time_t t;
>	static char buf[6]="old";    

whitespace damage above.

>	line=xasprintf("/dev/%s",line);
>	if ( stat(line,&st) < 0 )	  

ditto, twice.

>	  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));
>        

ditto
>        }
>        return buf;
>        

ditto
>}
>
>static const char *str[]= { " EMPTY"," RUN_LVL"," BOOT_TIME"," NEW_TIME"," OLD_TIME",
>		      " INIT_PROCESS"," LOGIN_PROCESS"," USER_PROCESS"," DEAD_PROCESS",
>		      " ACCOUNTING" };
>
>
>
>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);
>  printf("line:%s\n",ut->ut_line);
>  printf("id  :%s\n",ut->ut_id);
>  printf("user:%s\n",ut->ut_user);
>  printf("host:%s\n",ut->ut_host);
>  printf("term: %d\n",ut->ut_exit. e_termination);
>  printf("exit: %d\n",ut->ut_exit. e_exit);
>}
>
>
>#define OPT_a   1
>#define OPT_b   2		/* done */
>#define OPT_d   4               /* done */
>#define OPT_H   8		/* done */
>#define OPT_l   16		/* done */
>#define OPT_m   32 		/* done */
>#define OPT_p   64 		/* done */
>#define OPT_q   128  		/* done */
>#define OPT_r   256		/* done */
>#define OPT_s   512             /* default done */
>#define OPT_t   1024		/* done */
>#define OPT_T   2048		/* done */
>#define OPT_u   4096		/* done */
>#define OPT_D   8192		/* debug DUMPFILE */
>
>//
>//#define OPT_w   8192		/* like q with full info, GNU extension  */
>//
>
>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
>};
>
>#define HEAD(NAME)   if (pattern&NAME) printf("%s\t",#NAME)
>
>static void   print_header( int pattern)
>{
>  if (pattern<0) return;

better make sure that pattern has to be valid in the caller?

>  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) {
>    printf("ID=%s\t",ut->ut_id);	                             /* COMMENT */
>    printf("%s\t",ut->ut_host);	                             /* COMMENT */
>  }
>
>  if (mask&EXIT) {
>    printf("%d/",ut->ut_exit. e_termination);                 /* EXIT */
>    printf("%d\t",ut->ut_exit. e_exit);                        /* EXIT */     

whitespace damage
>  }
>  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;
>	
whitespace damage
>	/*
>	  filename hier setzen
>	int utmpname();
>	*/
>
>	opt_complementary="q-abdHlmqprstuD";

you're using non-standard spacing about everywhere. Please run that file through indent perusing the
toplevel .indent.pro. This is used per default if you do:
$ indent */who.c

>	getopt32(argv, "abdHlmpqrstTuD");
>
>	if (option_mask32 == 0) option_mask32=OPT_s;
>	if (option_mask32 == OPT_u) option_mask32|=OPT_s;
>
>	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");

please put those on their own line.

>		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;
>	
>
whitespace damage

and please use "else if"

>	 else
>	  if (option_mask32&OPT_l)
>	  pattern=(option_mask32&OPT_u) ? NAME|LINE|TIME|PID|COMMENT|ACTIVITY
>		                        : NAME|LINE|TIME|PID|COMMENT;
>
>	 else
>	   if (option_mask32&OPT_p)
>	   pattern=(option_mask32&OPT_u) ? NAME|LINE|TIME|PID|COMMENT|EXIT|ACTIVITY
>	                                 : NAME|LINE|TIME|PID|COMMENT|EXIT;
>	else
>	  if (option_mask32&OPT_p)
>	    pattern=NAME|LINE|TIME|PID|COMMENT;
>
>
>
>
>
excess whitespace
>
>	if (option_mask32&OPT_m) {
>	  name=ttyname(0);
>	  if (!name)
>	    fprintf(stderr,"not a tty\n");

There must already be a function that does the above, perhaps.
>
>	  /* skip leading dev */
>	  if ( !strncmp(name,"/dev/",5) ) name+=5;

open_device() (spelling?) does that already, doesn't it.
>
>	  //  printf("dev=%s\n",name);
>	}
>
>
>
>	/* use alternative file  */     
whitespace damage
>
>#if 0
>	if (optind==1) {
>		argv += optind;	
whitespace damage
>	        printf("file=%s\n",*argv);
>		if ( utmpname(*argv) <0 )
>		{
>			bb_error_msg_and_die("can not get %s",*argv);
>		}
>
>	}
>#endif
>
>	if (option_mask32&OPT_H)
>	  print_header(pattern);
>
>	while ((ut = getutent()) != NULL) {
>
>	    /* -m : only current terminal */
>	  if (option_mask32&OPT_m && strcmp(name,ut->ut_line)) continue;
>
>
>  	  /* -b */
>	  if (  (option_mask32&OPT_b) && BOOT_TIME == ut->ut_type) {
>	    if (option_mask32&OPT_H) printf("last reboot\t");
>	    //printf("%s\n",time2str("%b %e %H:%M",ut->ut_tv.tv_sec) );
>	    print_ut(ut,TIME);
>	    if (option_mask32&OPT_a) 
whitespace damage
>	      option_mask32 &= ~OPT_b;
>	    else
>	      break;
>	  }
>
>
>    	  /* -d */
>	  if (  (option_mask32&OPT_d) && DEAD_PROCESS== ut->ut_type) {
>	    print_ut(ut,pattern);
>	    //	    print_ut(ut,  (option_mask32&OPT_u) ? NAME|LINE|TIME|PID|COMMENT|EXIT|ACTIVITY
>	    //		                                : NAME|LINE|TIME|PID|COMMENT|EXIT );
>
>	  }
>
>
>  	  /* -l */
>	  if ( (option_mask32&OPT_l) && LOGIN_PROCESS == ut->ut_type) {
>	    //	    print_ut(ut,  (option_mask32&OPT_u) ? NAME|LINE|TIME|PID|COMMENT|ACTIVITY
>	    //	                                : NAME|LINE|TIME|PID|COMMENT);
>	    print_ut(ut,pattern);
>	    
whitespace damage
>	  }
>
>  	  /* -p */
>	  if ( (option_mask32&OPT_p) && INIT_PROCESS == ut->ut_type) {
>	    // print_ut(ut,NAME|LINE|TIME|PID|COMMENT);
>	    print_ut(ut,pattern);
>	    
whitespace damage
>	  }
>
>
>  	  /* -q */
>	    if ( (option_mask32&OPT_q) && USER_PROCESS == ut->ut_type) {
>		    printf("%s ",ut->ut_user);
>		    ucnt++;
>	    }
>
>
>  	  /* -r */
>	    if ( (option_mask32&OPT_r) && RUN_LVL == ut->ut_type) {
>	      if (option_mask32&OPT_H) { printf ("\t Current\tTime\tLast\n"); }
>	      printf("%s %c\t",ut->ut_user,ut->ut_pid &255 ); 
whitespace damage
>	      printf("%s\t",time2str("%Y-%m-%d %H:%M",ut->ut_tv.tv_sec) );
>	      printf("%c\n", (ut->ut_pid >> 8)?'N':(ut->ut_pid >> 8));
>
>	      /*
>		if OPT_a is set we have to show this here only once
>		and continue to handle the other options
>	      */
>	      if (option_mask32&OPT_a) 
whitespace damage
>		option_mask32 &= ~OPT_r;
>	      else
>		break;
>             }
>
>	  /* -s | default */
>	    if ( (option_mask32&OPT_s) && USER_PROCESS == ut->ut_type) {
>	    print_ut(ut,pattern);
>	  }
>
>
>
>  	  /* -t */
>	  if (  (option_mask32&OPT_t) && NEW_TIME == ut->ut_type) {
>	    if (option_mask32&OPT_H) printf("last time change\t");
>    	    print_ut(ut,TIME);
>	    break;
>	  }
>
>	  /* -T */
>	  if ( (option_mask32&OPT_T) && USER_PROCESS == ut->ut_type) {
>
>	    print_ut(ut,pattern);
>	    //	    print_ut(ut,  (option_mask32&OPT_u) ? NAME|STATE|LINE|TIME|PID|COMMENT|ACTIVITY
>	    //		                                : NAME|STATE|LINE|TIME|PID|COMMENT);
>
>	  }
>
>
>
>/* -D debug option */
>	  if (option_mask32&OPT_D)
>		  print_all(ut);
>
>
>
>	  } /* while */
>
>/*
>  write user count
>*/
>
>	if (option_mask32&OPT_q)
>		printf("\n#User %d\n",ucnt);
>
>	endutent();
>	return EXIT_SUCCESS;
>}

Most of the layout should be fixed by one indent invocation. Please resend
a cleaned up version.



More information about the busybox mailing list