Hi list, this is latest version of a SUSv3 compliant busybox who i have replaced option_mask32 with a local opt. The save is impressiv.
re, wh Final link with: <none> function old new delta .rodata 1434 1418 -16 who_main 1237 1168 -69 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-85) Total: -85 bytes
/* vi: set sw=4 ts=4: */ /* * SUSv3 who implementation for busybox * * Copyright (C) 2008 by <[email protected]> * http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html * * BB_AUDIT SUSv3 defects - missing long options * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * $Id: who.c,v 1.14 2009/01/30 20:31:25 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 'mon 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; unsigned int opt; /* FIXME: make better use of opt_complementary */ // opt_complementary = "q-abdHlmqprstuD"; opt=getopt32(argv, "abdHlmpqrstTuD"); argv += optind; /* utmpname() will not fail if the file does not exists */ if (*argv) utmpname(*argv); 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); /* figure out pattern to figure out pattern for heading */ if (opt & OPT_T) pattern = (opt & OPT_u) ? NAME | STATE | LINE | TIME | PID | COMMENT | ACTIVITY : NAME | STATE | LINE | TIME | PID | COMMENT; else if (opt & OPT_s) pattern = (opt & OPT_u) ? NAME | LINE | TIME | ACTIVITY : NAME | LINE | TIME; else if (opt & OPT_l) pattern = (opt & OPT_u) ? NAME | LINE | TIME | PID | COMMENT | ACTIVITY : NAME | LINE | TIME | PID | COMMENT; else if (opt & OPT_p) pattern = (opt & OPT_u) ? NAME | LINE | TIME | PID | COMMENT | EXIT | ACTIVITY : NAME | LINE | TIME | PID | COMMENT | EXIT; else if (opt & OPT_D) pattern = NAME | LINE | TIME | PID | COMMENT |EXIT; 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); 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 */ /* 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
