diff options
author | landley <landley@driftwood> | 2006-10-30 01:38:00 -0500 |
---|---|---|
committer | landley <landley@driftwood> | 2006-10-30 01:38:00 -0500 |
commit | 09ea7ac1a269db3c9a3b76840b37a7cb1eccbc24 (patch) | |
tree | 83d36320286fee20f7a7b4cc317f9cc3802926fe | |
parent | 2f588f7f47c43b5949e520b80cfd755a6b4ca4e6 (diff) | |
download | toybox-09ea7ac1a269db3c9a3b76840b37a7cb1eccbc24.tar.gz |
Implement df. Add -Wall to build and fix up warnings. Add copyright notices.
Add error_msg() and itoa() to library. Remove argc from globals (since argv is
null terminated), add optflags to globals.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | lib/functions.c | 112 | ||||
-rw-r--r-- | lib/getmountlist.c | 15 | ||||
-rw-r--r-- | lib/lib.h | 21 | ||||
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | toys.h | 19 | ||||
-rw-r--r-- | toys/df.c | 106 | ||||
-rw-r--r-- | toys/toysh.c | 4 |
8 files changed, 256 insertions, 24 deletions
@@ -1,5 +1,5 @@ all: - $(CC) -Os -s $(CFLAGS) -I . main.c toys/*.c lib/*.c -o toybox + $(CC) -Wall -Os -s $(CFLAGS) -I . main.c toys/*.c lib/*.c -o toybox clean: rm toybox diff --git a/lib/functions.c b/lib/functions.c index 7ef3a70c..e01053ba 100644 --- a/lib/functions.c +++ b/lib/functions.c @@ -5,19 +5,59 @@ * succeed or kill the program with an error message, but never return failure. * They usually have the same arguments and return value as the function they * wrap. + * + * Copyright 2006 Rob Landley <rob@landley.net> */ #include "toys.h" +void verror_msg(char *msg, int err, va_list va) +{ + fprintf(stderr, "%s: ", toys.which->name); + vfprintf(stderr, msg, va); + if (err) fprintf(stderr, ": %s", strerror(err)); + putc('\n', stderr); +} + +void error_msg(char *msg, ...) +{ + va_list va; + + va_start(va, msg); + verror_msg(msg, 0, va); + va_end(va); +} + +void perror_msg(char *msg, ...) +{ + va_list va; + + va_start(va, msg); + verror_msg(msg, errno, va); + va_end(va); +} + // Die with an error message. void error_exit(char *msg, ...) { - va_list args; + va_list va; + + va_start(va, msg); + verror_msg(msg, 0, va); + va_end(va); + + exit(toys.exitval); +} + +// Die with an error message and strerror(errno) +void perror_exit(char *msg, ...) +{ + va_list va; + + va_start(va, msg); + verror_msg(msg, errno, va); + va_end(va); - va_start(args, msg); - fprintf(stderr, "%s: ", toys.which->name); - vfprintf(stderr, msg, args); - va_end(args); exit(toys.exitval); } @@ -87,7 +127,7 @@ char *xmsprintf(char *format, ...) // Die unless we can exec argv[] (or run builtin command). Note that anything // with a path isn't a builtin, so /bin/sh won't match the builtin sh. -void *xexec(char **argv) +void xexec(char **argv) { toy_exec(argv); execvp(argv[0], argv); @@ -118,6 +158,8 @@ char *xgetcwd(void) { char *buf = getcwd(NULL, 0); if (!buf) error_exit("xgetcwd"); + + return buf; } // Find this file in a colon-separated path. @@ -126,7 +168,7 @@ char *find_in_path(char *path, char *filename) { char *next, *res = NULL, *cwd = xgetcwd(); - while (next = index(path,':')) { + while ((next = index(path,':'))) { int len = next-path; if (len==1) res = xmsprintf("%s/%s", cwd, filename); @@ -144,3 +186,59 @@ char *find_in_path(char *path, char *filename) return res; } + +// Convert unsigned int to ascii, writing into supplied buffer. A truncated +// result contains the first few digits of the result ala strncpy, and is +// always null terminated (unless buflen is 0). +void utoa_to_buf(unsigned n, char *buf, unsigned buflen) +{ + int i, out = 0; + + if (buflen) { + for (i=1000000000; i; i/=10) { + int res = n/i; + + if ((res || out || i == 1) && --buflen>0) { + out++; + n -= res*i; + *buf++ = '0' + res; + } + } + *buf = 0; + } +} + +// Convert signed integer to ascii, using utoa_to_buf() +void itoa_to_buf(int n, char *buf, unsigned buflen) +{ + if (buflen && n<0) { + n = -n; + *buf++ = '-'; + buflen--; + } + utoa_to_buf((unsigned)n, buf, buflen); +} + +// This static buffer is used by both utoa() and itoa(), calling either one a +// second time will overwrite the previous results. +// +// The longest 32 bit integer is -2 billion plus a null terminator: 12 bytes. +// Note that int is always 32 bits on any remotely unix-like system, see +// http://www.unix.org/whitepapers/64bit.html for details. + +static char itoa_buf[12]; + +// Convert unsigned integer to ascii, returning a static buffer. +char *utoa(unsigned n) +{ + utoa_to_buf(n, itoa_buf, sizeof(itoa_buf)); + + return itoa_buf; +} + +char *itoa(int n) +{ + itoa_to_buf(n, itoa_buf, sizeof(itoa_buf)); + + return itoa_buf; +} diff --git a/lib/getmountlist.c b/lib/getmountlist.c index d2484937..8410a923 100644 --- a/lib/getmountlist.c +++ b/lib/getmountlist.c @@ -1,4 +1,8 @@ /* vi: set sw=4 ts=4 : */ +/* getmountlist.c - Get a linked list of mount points, with stat information. + * + * Copyright 2006 Rob Landley <rob@landley.net> + */ #include "toys.h" @@ -6,8 +10,9 @@ char *path_mounts = "/proc/mounts"; -// Get a list of mount points from /etc/mtab or /proc/mounts. This returns -// a reversed list, which is good for finding overmounts and such. +// Get a list of mount points from /etc/mtab or /proc/mounts, including +// statvfs() information. This returns a reversed list, which is good for +// finding overmounts and such. struct mtab_list *getmountlist(int die) { @@ -21,9 +26,13 @@ struct mtab_list *getmountlist(int die) if (die) error_exit("cannot open %s", path_mounts); } else { while (getmntent_r(fp, &me, evilbuf, sizeof(evilbuf))) { - mt = xmalloc(sizeof(struct mtab_list) + strlen(me.mnt_fsname) + + mt = xzalloc(sizeof(struct mtab_list) + strlen(me.mnt_fsname) + strlen(me.mnt_dir) + strlen(me.mnt_type) + 3); mt->next = mtlist; + // Get information about this filesystem. Yes, we need both. + stat(me.mnt_dir, &(mt->stat)); + statvfs(me.mnt_dir, &(mt->statvfs)); + // Remember information from /proc/mounts strcpy(mt->type, me.mnt_type); mt->dir = mt->type + strlen(mt->type) + 1; strcpy(mt->dir, me.mnt_dir); @@ -1,25 +1,44 @@ /* vi: set ts=4 :*/ +/* lib.h - header file for lib directory + * + * Copyright 2006 Rob Landley <rob@landley.net> + */ // functions.c +void verror_msg(char *msg, int err, va_list va); +void error_msg(char *msg, ...); +void perror_msg(char *msg, ...); void error_exit(char *msg, ...); +void perror_exit(char *msg, ...); void strlcpy(char *dest, char *src, size_t size); void *xmalloc(size_t size); void *xzalloc(size_t size); void xrealloc(void **ptr, size_t size); void *xstrndup(char *s, size_t n); char *xmsprintf(char *format, ...); -void *xexec(char **argv); +void xexec(char **argv); int xopen(char *path, int flags, int mode); FILE *xfopen(char *path, char *mode); char *xgetcwd(void); char *find_in_path(char *path, char *filename); +void utoa_to_buf(unsigned n, char *buf, unsigned buflen); +void itoa_to_buf(int n, char *buf, unsigned buflen); +char *utoa(unsigned n); +char *itoa(int n); // llist.c void llist_free(void *list, void (*freeit)(void *data)); +struct string_list { + struct string_list *next; + char *str; +}; + // getmountlist.c struct mtab_list { struct mtab_list *next; + struct stat stat; + struct statvfs statvfs; char *dir; char *device; char type[0]; @@ -58,7 +58,6 @@ void toy_init(struct toy_list *which, char *argv[]) toys.which = which; toys.argv = argv; - for (toys.argc = 0; argv[toys.argc]; toys.argc++); toys.exitval = 1; } @@ -6,13 +6,21 @@ * Licensed under GPL version 2, see file LICENSE in this tarball for details. */ +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> #include <limits.h> #include <stdarg.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/types.h> +#include <sys/wait.h> #include <unistd.h> #include "lib/lib.h" @@ -44,8 +52,8 @@ void toy_exec(char *argv[]); extern struct toy_context { struct toy_list *which; // Which entry in toy_list is this one? int exitval; // Value error_exit feeds to exit() - int argc; - char **argv; + int optflags; // Command line option flags + char **argv; // Command line arguments char buf[4096]; } toys; @@ -53,7 +61,10 @@ struct exit_data {;}; struct cd_data {;}; struct toybox_data {;}; struct toysh_data {;}; -struct df_data {;}; +struct df_data { + struct string_list *fstype; + long units; +}; union toy_union { struct exit_data exit; @@ -73,3 +84,5 @@ union toy_union { #define CFG_TOYSH_ENVVARS 0 // Environment variables #define CFG_TOYSH_LOCVARS 0 // Local, synthetic, fancy prompts, set, $? #define CFG_TOYSH_PIPES 0 // Pipes and redirects: | > < >> << && || & () ; + +#define CFG_DF_PEDANTIC 1 // Support -P and -k in df @@ -2,7 +2,7 @@ /* * df.c - report free disk space. * - * Implemented according to SUSv3: + * Implemented roughly according to SUSv3: * http://www.opengroup.org/onlinepubs/009695399/utilities/df.html * * usage: df [-k] [-P|-t] [file...] @@ -10,16 +10,110 @@ #include "toys.h" +static void show_mt(struct mtab_list *mt) +{ + int len; + long size, used, avail; + uint64_t block; + + // Return if it wasn't found (should never happen, but with /etc/mtab...) + if (!mt) return; + + // If we have -t, skip other filesystem types + if (toy.df.fstype) { + struct string_list *sl; + + for (sl = toy.df.fstype; sl; sl = sl->next) + if (!strcmp(mt->type, sl->str)) break; + if (!sl) return; + } + + // If we don't have -a, skip synthetic filesystems + if (!(toys.optflags & 1) && !mt->statvfs.f_blocks) return; + + // Figure out how much total/used/free space this filesystem has, + // forcing 64-bit math because filesystems are big now. + block = mt->statvfs.f_bsize ? : 1; + + size = (long)((block * mt->statvfs.f_blocks) / toy.df.units); + used = (long)((block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree)) + / toy.df.units); + avail = (long)((block + * (getuid() ? mt->statvfs.f_bavail : mt->statvfs.f_bfree)) + / toy.df.units); + + // Figure out appropriate spacing + len = 25 - strlen(mt->device); + if (len < 1) len = 1; + printf("%s% *ld % 10ld % 9ld % 3ld%% %s\n",mt->device, len, + size, used, avail, 100-(long)((100*(uint64_t)avail)/size), mt->dir); +} + int df_main(void) { - struct mtab_list *mt, *mtlist; + struct mtab_list *mt, *mt2, *mtlist; + char **argv; + + // get_optflags("Pkt:a",&(toy.df.fstype)); + argv = NULL; + + // Handle -P and -k + toy.df.units = 1024; + if (CFG_DF_PEDANTIC && (toys.optflags & 8)) { + // Units are 512 bytes if you select "pedantic" without "kilobytes". + if ((toys.optflags&3) == 1) toy.df.units = 512; + printf("Filesystem %ld-blocks Used Available Capacity Mounted on\n", + toy.df.units); + } else puts("Filesystem\t1K-blocks\tUsed Available Use% Mounted on"); - //int units = 512; mtlist = getmountlist(1); - // Zap overmounts - for (mt = mtlist; mt; mt = mt->next) { - printf("type=%s dir=%s device=%s\n",mt->type,mt->dir,mt->device); + + // If we have a list of filesystems on the command line, loop through them. + if (argv) { + char *next; + + for(next = *argv; *next; next++) { + struct stat st; + + // Stat it (complain if we can't). + if(!stat(next, &st)) { + perror_msg("`%s'", next); + toys.exitval = 1; + continue; + } + + // Find and display this filesystem. Use _last_ hit in case of + // -- bind mounts. + mt2 = NULL; + for (mt = mtlist; mt; mt = mt->next) + if (st.st_dev == mt->stat.st_dev) mt2 = mt; + show_mt(mt2); + } + } else { + // Get and loop through mount list. + + for (mt = mtlist; mt; mt = mt->next) { + struct mtab_list *mt2, *mt3; + + if (!mt->stat.st_dev) continue; + + // Filter out overmounts. + mt3 = mt; + for (mt2 = mt->next; mt2; mt2 = mt2->next) { + if (mt->stat.st_dev == mt2->stat.st_dev) { + // For --bind mounts, take last match + if (!strcmp(mt->device, mt2->device)) mt3 = mt2; + // Filter out overmounts + mt2->stat.st_dev = 0; + } + } + show_mt(mt3); + } } + if (CFG_TOYS_FREE) { + llist_free(mtlist, NULL); + free(argv); + } return 0; } diff --git a/toys/toysh.c b/toys/toysh.c index 1d792f1f..7ac430c9 100644 --- a/toys/toysh.c +++ b/toys/toysh.c @@ -181,14 +181,14 @@ static void handle(char *command) int cd_main(void) { - char *dest = toys.argc>1 ? toys.argv[1] : getenv("HOME"); + char *dest = toys.argv[1] ? toys.argv[1]: getenv("HOME"); if (chdir(dest)) error_exit("chdir %s",dest); return 0; } int exit_main(void) { - exit(toys.argc>1 ? atoi(toys.argv[1]) : 0); + exit(toys.argv[1] ? atoi(toys.argv[1]) : 0); } int toysh_main(void) |