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