SUSv3 who for Busybox
Tito
farmatito at tiscali.it
Mon Dec 8 20:24:41 UTC 2008
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.
> 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.
> 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
> };
Code obfuscation? ;-)
> #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.
> 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?
>
> 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;
>
>
>
>
>
>
> if (option_mask32&OPT_m) {
> name=ttyname(0);
> if (!name)
> fprintf(stderr,"not a tty\n");
>
> /* skip leading dev */
> if ( !strncmp(name,"/dev/",5) ) name+=5;
>
> // printf("dev=%s\n",name);
> }
>
>
>
> /* use alternative file */
>
> #if 0
> if (optind==1) {
> argv += optind;
> 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)
> 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);
>
> }
>
> /* -p */
> if ( (option_mask32&OPT_p) && INIT_PROCESS == ut->ut_type) {
> // print_ut(ut,NAME|LINE|TIME|PID|COMMENT);
> print_ut(ut,pattern);
>
> }
>
>
> /* -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"); }
One printf call should be enough.
> printf("%s %c\t",ut->ut_user,ut->ut_pid &255 );
> 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)
> 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;
> }
> re,
> wh
>
More information about the busybox
mailing list