From d5566b3bf443b19ec511d702b4f03e352afafc86 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 18 Apr 2015 20:28:15 -0500 Subject: Android getprop and setprop from Elliott Hughes. --- toys/android/getprop.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ toys/android/setprop.c | 52 +++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 toys/android/getprop.c create mode 100644 toys/android/setprop.c diff --git a/toys/android/getprop.c b/toys/android/getprop.c new file mode 100644 index 00000000..66530419 --- /dev/null +++ b/toys/android/getprop.c @@ -0,0 +1,98 @@ +/* getprop.c - Get an Android system property + * + * Copyright 2015 The Android Open Source Project + +USE_GETPROP(NEWTOY(getprop, ">2", TOYFLAG_USR|TOYFLAG_SBIN)) + +config GETPROP + bool "getprop" + default y + help + usage: getprop [NAME [DEFAULT]] + + Gets an Android system property, or lists them all. +*/ + +#define FOR_getprop +#include "toys.h" + +#if defined(__ANDROID__) + +#include + +GLOBALS( + size_t size; + size_t capacity; +) + +struct property_info { + char *name; + char *value; +}; + +static struct property_info **properties; + +static void add_property(const char *name, const char *value, void *unused) +{ + struct property_info *new = xmalloc(sizeof(struct property_info)); + + if (TT.size >= TT.capacity) { + TT.capacity += 32; + properties = xrealloc(properties, + TT.capacity * sizeof(struct property_info *)); + } + + // TODO: fix xstrdup signature so we can remove these bogus casts. + new->name = xstrdup((char *) name); + new->value = xstrdup((char *) value); + properties[TT.size++] = new; +} + +static void free_properties() +{ + size_t i; + + for (i = 0; i < TT.size; ++i) { + free(properties[i]->name); + free(properties[i]->value); + free(properties[i]); + } + free(properties); +} + +static int property_cmp(const void *a, const void *b) +{ + struct property_info *pa = *((struct property_info **)a); + struct property_info *pb = *((struct property_info **)b); + + return strcmp(pa->name, pb->name); +} + +void getprop_main(void) +{ + if (*toys.optargs) { + char value[PROPERTY_VALUE_MAX]; + const char *default_value = ""; + + if (toys.optargs[1]) default_value = toys.optargs[1]; + property_get(*toys.optargs, value, default_value); + puts(value); + } else { + size_t i; + + if (property_list(add_property, NULL)) + error_exit("property_list failed"); + qsort(properties, TT.size, sizeof(struct property_info *), property_cmp); + for (i = 0; i < TT.size; ++i) + printf("[%s]: [%s]\n", properties[i]->name, properties[i]->value); + if (CFG_TOYBOX_FREE) free_properties(); + } +} + +#else + +void getprop_main(void) +{ +} + +#endif diff --git a/toys/android/setprop.c b/toys/android/setprop.c new file mode 100644 index 00000000..ef24c9ad --- /dev/null +++ b/toys/android/setprop.c @@ -0,0 +1,52 @@ +/* setprop.c - Set an Android system property + * + * Copyright 2015 The Android Open Source Project + +USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN)) + +config SETPROP + bool "setprop" + default y + help + usage: setprop NAME VALUE + + Sets an Android system property. +*/ + +#define FOR_setprop +#include "toys.h" + +#if defined(__ANDROID__) +#include +#endif + +void setprop_main(void) +{ +#if defined(__ANDROID__) + char *name = toys.optargs[0], *value = toys.optargs[1]; + char *p; + size_t name_len = strlen(name), value_len = strlen(value); + + // property_set doesn't tell us why it failed, and actually can't + // recognize most failures (because it doesn't wait for init), so + // we duplicate all of init's checks here to help the user. + + if (name_len >= PROP_NAME_MAX) + error_exit("name '%s' too long; try '%.*s'", + name, PROP_NAME_MAX - 1, name); + if (value_len >= PROP_VALUE_MAX) + error_exit("value '%s' too long; try '%.*s'", + value, PROP_VALUE_MAX - 1, value); + + if (*name == '.' || name[name_len - 1] == '.') + error_exit("property names must not start or end with '.'"); + if (strstr(name, "..")) + error_exit("'..' is not allowed in a property name"); + for (p = name; *p; ++p) + if (!isalnum(*p) && !strchr("_.-", *p)) + error_exit("invalid character '%c' in name '%s'", *p, name); + + if (property_set(name, value)) + error_msg("failed to set property '%s' to '%s'", name, value); +#endif +} -- cgit v1.2.3 From 957c3f7eaa4b56d6470ce8ef382b132c1aae9ca0 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 19 Apr 2015 00:15:46 -0500 Subject: Roadmap update, mostly from enh with a few other pending bits mixed in. --- www/roadmap.html | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/www/roadmap.html b/www/roadmap.html index 26146e42..bba08b1b 100755 --- a/www/roadmap.html +++ b/www/roadmap.html @@ -231,13 +231,14 @@ git repository.

Toolbox commands:

-

According to system/core/toolbox/Android.mk the toolbox directory builds -the following commands:

+

According to +system/core/toolbox/Android.mk the toolbox directory builds the +following commands:

-dd du df getevent getprop iftop ioctl ionice load_policy log ls -lsof mount nandread newfs_msdos ps prlimit renice restorecon -sendevent setprop start stop top uptime watchprops +dd du df getevent iftop ioctl ionice log ls +lsof mount nandread newfs_msdos ps prlimit renice +sendevent start stop top uptime watchprops

Other Android core commands

@@ -269,14 +270,15 @@ bespoke code to install itself.

For reference, combining everything listed above, we get:

-dd du df getevent getprop gpttool iftop init ioctl ionice +dd du df getevent gpttool iftop init ioctl ionice log logcat logwrapper ls lsof mkbootimg mount nandread -newfs_msdos ps prlimit reboot renice restorecon run-as -sendevent setprop start stop top uptime watchprops +newfs_msdos ps prlimit reboot renice run-as +sendevent start stop top uptime watchprops

We may eventually implement all of that, but for toybox 1.0 we need to -focus a bit. For our first pass, let's ignore selinux, +focus a bit. For our first pass, let's ignore selinux [note: the android +guys submitted selinux code to us and we merged it], and grab just logcat and logwrapper from the "core" commands (since the rest have some full/standard version providing that functionality, which we can implement a shim interface for later).

@@ -284,9 +286,9 @@ functionality, which we can implement a shim interface for later).

This means toybox should implement (or finish implementing):

-dd du df getevent getprop iftop ioctl ionice log logcat logwrapper ls lsof +dd du df getevent iftop ioctl ionice log logcat logwrapper ls lsof mount nandread newfs_msdos ps prlimit renice schedtop sendevent -setprop smd start stop top uptime watchprops +smd start stop top uptime watchprops
@@ -305,7 +307,7 @@ arch base64 users dir vdir unexpand shred join csplit hostid nproc runcon sha224 sha256 sha384 sha512 sha3 mkfs.vfat fsck.vfat dosfslabel uname stdbuf pinky diff3 sdiff zcmp zdiff zegrep zfgrep zless zmore - +

In addition, they'd like to use several commands currently in pending:

@@ -315,6 +317,10 @@ tar diff printf wget rsync fdisk vi less tr test stty fold expr dd +

Also, tizen uses a different Linux Security Module called SMACK, so +many of the SELinux options ala ls -Z need smack alternatives in an +if/else setup.

+

klibc:

@@ -378,7 +384,7 @@ from it into a /proc file, something the kernel is capable of doing itself.
attempted to remove that capability from the kernel, current kernel/power/hibernate.c still parses "resume=" on the command line). And yet various distros seem to -make use of klibc for this> +make use of klibc for this. Given the history of swsusp/hibernate (and TuxOnIce and kexec jump) I've lost track -- cgit v1.2.3 From 3cf9b08cc9ebeddc449638608f7a28c4c4ba20f9 Mon Sep 17 00:00:00 2001 From: Isaac Dunham Date: Sat, 18 Apr 2015 18:25:06 +0000 Subject: mdev: implement hotplug support. Use DEVPATH, DEVNAME, MAJOR, MINOR, and SUBSYSTEM instead of checking the current path and reading .../dev. While we're here, probe for partitions in block devices. This uses a very lame check for ACTION (which can be add, remove, or change): if it is "remove", then unlink the device. --- toys/pending/mdev.c | 74 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/toys/pending/mdev.c b/toys/pending/mdev.c index 2d98c257..0c496336 100644 --- a/toys/pending/mdev.c +++ b/toys/pending/mdev.c @@ -31,34 +31,53 @@ config MDEV_CONF #include "toys.h" -// todo, open() block devices to trigger partition scanning. - // mknod in /dev based on a path like "/sys/block/hda/hda1" static void make_device(char *path) { - char *device_name, *s, *temp; + char *device_name = NULL, *s, *temp; int major, minor, type, len, fd; int mode = 0660; uid_t uid = 0; gid_t gid = 0; - // Try to read major/minor string - - temp = strrchr(path, '/'); - fd = open(path, O_RDONLY); - *temp=0; - temp = toybuf; - len = read(fd, temp, 64); - close(fd); - if (len<1) return; - temp[len] = 0; - - // Determine device name, type, major and minor - - device_name = strrchr(path, '/') + 1; - type = path[5]=='c' ? S_IFCHR : S_IFBLK; - major = minor = 0; - sscanf(temp, "%u:%u", &major, &minor); + if (path) { + // Try to read major/minor string + + temp = strrchr(path, '/'); + fd = open(path, O_RDONLY); + *temp=0; + temp = toybuf; + len = read(fd, temp, 64); + close(fd); + if (len<1) return; + temp[len] = 0; + + // Determine device type, major and minor + + type = path[5]=='c' ? S_IFCHR : S_IFBLK; + major = minor = 0; + sscanf(temp, "%u:%u", &major, &minor); + } else { + // if (!path), do hotplug + + if (!(temp = getenv("SUBSYSTEM"))) + return; + type = strcmp(temp, "block") ? S_IFCHR : S_IFBLK; + major = minor = 0; + if (!(temp = getenv("MAJOR"))) + return; + sscanf(temp, "%u", &major); + if (!(temp = getenv("MINOR"))) + return; + sscanf(temp, "%u", &minor); + path = getenv("DEVPATH"); + device_name = getenv("DEVNAME"); + if (!path) + return; + temp = toybuf; + } + if (!device_name) + device_name = strrchr(path, '/') + 1; // If we have a config file, look up permissions for this device @@ -167,9 +186,20 @@ found_device: } sprintf(temp, "/dev/%s", device_name); + + if (getenv("ACTION") && !strcmp(getenv("ACTION"), "remove")) { + unlink(temp); + return; + } + + if (strchr(device_name, '/')) + mkpathat(AT_FDCWD, temp, 0, 2); if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST) perror_exit("mknod %s failed", temp); + + if (type == S_IFBLK) close(open(temp, O_RDONLY)); // scan for partitions + if (CFG_MDEV_CONF) mode=chown(temp, uid, gid); } @@ -202,7 +232,7 @@ void mdev_main(void) if (toys.optflags) { dirtree_read("/sys/class", callback); dirtree_read("/sys/block", callback); + } else { // hotplug support + make_device(NULL); } - - // hotplug support goes here } -- cgit v1.2.3 From 5b493dc48db03c7e27c8ce002fe216bcd778fe92 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 19 Apr 2015 21:50:51 -0500 Subject: Cleanup getprop, add qstrcmp() to lib for qsort (because posix-2008 broke alphasort), add compile-time probe for config symbol TOYBOX_ON_ANDROID. --- lib/lib.c | 8 ++++++ lib/lib.h | 1 + scripts/genconfig.sh | 7 +++++ toys/android/getprop.c | 76 +++++++++----------------------------------------- 4 files changed, 29 insertions(+), 63 deletions(-) diff --git a/lib/lib.c b/lib/lib.c index 99d2ea60..1a60a7ff 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -887,3 +887,11 @@ int human_readable(char *buf, unsigned long long num) return end; } + +// The qsort man page says you can use alphasort, the posix committee +// disagreed, and doubled down: http://austingroupbugs.net/view.php?id=142 +// So just do our own. (The const is entirely to humor the stupid compiler.) +int qstrcmp(const void *a, const void *b) +{ + return strcmp(*(char **)a, *(char **)b); +} diff --git a/lib/lib.h b/lib/lib.h index 3cda7d9f..a4e5808d 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -176,6 +176,7 @@ void base64_init(char *p); int terminal_size(unsigned *x, unsigned *y); int yesno(char *prompt, int def); int human_readable(char *buf, unsigned long long num); +int qstrcmp(const void *a, const void *b); // net.c int xsocket(int domain, int type, int protocol); diff --git a/scripts/genconfig.sh b/scripts/genconfig.sh index ead5b8a2..b8dc3c79 100755 --- a/scripts/genconfig.sh +++ b/scripts/genconfig.sh @@ -65,6 +65,13 @@ EOF struct spwd *a = getspnam("root"); return 0; } EOF + + # Some commands are android-specific + probesymbol TOYBOX_ON_ANDROID -c << EOF + #ifndef __ANDROID__ + #error nope + #endif +EOF } genconfig() diff --git a/toys/android/getprop.c b/toys/android/getprop.c index 66530419..9d5398aa 100644 --- a/toys/android/getprop.c +++ b/toys/android/getprop.c @@ -7,6 +7,7 @@ USE_GETPROP(NEWTOY(getprop, ">2", TOYFLAG_USR|TOYFLAG_SBIN)) config GETPROP bool "getprop" default y + depends on TOYBOX_ON_ANDROID help usage: getprop [NAME [DEFAULT]] @@ -16,83 +17,32 @@ config GETPROP #define FOR_getprop #include "toys.h" -#if defined(__ANDROID__) - -#include +//#include GLOBALS( size_t size; - size_t capacity; + char **nv; // name/value pairs: even=name, odd=value ) -struct property_info { - char *name; - char *value; -}; - -static struct property_info **properties; - -static void add_property(const char *name, const char *value, void *unused) +static void add_property(char *name, char *value, void *unused) { - struct property_info *new = xmalloc(sizeof(struct property_info)); + if (!(TT.size&31)) TT.nv = xrealloc(TT.nv, (TT.size+32)*2*sizeof(char *)); - if (TT.size >= TT.capacity) { - TT.capacity += 32; - properties = xrealloc(properties, - TT.capacity * sizeof(struct property_info *)); - } - - // TODO: fix xstrdup signature so we can remove these bogus casts. - new->name = xstrdup((char *) name); - new->value = xstrdup((char *) value); - properties[TT.size++] = new; -} - -static void free_properties() -{ - size_t i; - - for (i = 0; i < TT.size; ++i) { - free(properties[i]->name); - free(properties[i]->value); - free(properties[i]); - } - free(properties); -} - -static int property_cmp(const void *a, const void *b) -{ - struct property_info *pa = *((struct property_info **)a); - struct property_info *pb = *((struct property_info **)b); - - return strcmp(pa->name, pb->name); + TT.nv[2*TT.size] = xstrdup(name); + TT.nv[1+2*TT.size++] = xstrdup(value); } void getprop_main(void) { if (*toys.optargs) { - char value[PROPERTY_VALUE_MAX]; - const char *default_value = ""; - - if (toys.optargs[1]) default_value = toys.optargs[1]; - property_get(*toys.optargs, value, default_value); - puts(value); + property_get(*toys.optargs, toybuf, toys.optargs[1] ? toys.optargs[1] : ""); + puts(toybuf); } else { size_t i; - if (property_list(add_property, NULL)) - error_exit("property_list failed"); - qsort(properties, TT.size, sizeof(struct property_info *), property_cmp); - for (i = 0; i < TT.size; ++i) - printf("[%s]: [%s]\n", properties[i]->name, properties[i]->value); - if (CFG_TOYBOX_FREE) free_properties(); + if (property_list((void *)add_property, 0)) perror_exit("property_list"); + qsort(TT.nv, TT.size, 2*sizeof(char *), alphasort); + for (i = 0; i Date: Mon, 20 Apr 2015 20:59:00 -0500 Subject: Switch setprop to use TOYBOX_ON_ANDROID and fix getprop include. (I commented out the android-only #include in getprop to do what compile testing I could, and then forgot to uncomment it.) --- toys/android/getprop.c | 2 +- toys/android/setprop.c | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/toys/android/getprop.c b/toys/android/getprop.c index 9d5398aa..400d80e7 100644 --- a/toys/android/getprop.c +++ b/toys/android/getprop.c @@ -17,7 +17,7 @@ config GETPROP #define FOR_getprop #include "toys.h" -//#include +#include GLOBALS( size_t size; diff --git a/toys/android/setprop.c b/toys/android/setprop.c index ef24c9ad..cbcd152b 100644 --- a/toys/android/setprop.c +++ b/toys/android/setprop.c @@ -7,6 +7,7 @@ USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN)) config SETPROP bool "setprop" default y + depends on TOYBOX_ON_ANDROID help usage: setprop NAME VALUE @@ -16,13 +17,10 @@ config SETPROP #define FOR_setprop #include "toys.h" -#if defined(__ANDROID__) #include -#endif void setprop_main(void) { -#if defined(__ANDROID__) char *name = toys.optargs[0], *value = toys.optargs[1]; char *p; size_t name_len = strlen(name), value_len = strlen(value); @@ -48,5 +46,4 @@ void setprop_main(void) if (property_set(name, value)) error_msg("failed to set property '%s' to '%s'", name, value); -#endif } -- cgit v1.2.3 From a829b89dbd324bcc005a5873fddf3faa81ea0536 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 21 Apr 2015 01:45:07 -0500 Subject: Bugfix from Hyejin Kim (count=1 shouldn't change name), plus a bounds check. Test is 'echo "AAA c 1 0 0 2 5 0 0 1" | makedevs' makes AAA not AAA0. --- toys/other/makedevs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toys/other/makedevs.c b/toys/other/makedevs.c index 0d20a57d..0f0a6615 100644 --- a/toys/other/makedevs.c +++ b/toys/other/makedevs.c @@ -84,8 +84,8 @@ void makedevs_main() while (*node == '/') node++; // using relative path for (i = 0; (!cnt && !i) || i < cnt; i++) { - if (cnt) { - snprintf(toybuf, sizeof(toybuf), "%s%u", node, st_val + i); + if (cnt>1) { + snprintf(toybuf, sizeof(toybuf), "%.999s%u", node, st_val + i); ptr = toybuf; } else ptr = node; -- cgit v1.2.3 From 9ac2d6546a2154a6797e12dfe86f36cc9420d6d4 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 24 Apr 2015 17:09:51 -0500 Subject: Too tired on the flight back from Japan to work on thinky stuff, so... --- toys/pending/hexedit.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 toys/pending/hexedit.c diff --git a/toys/pending/hexedit.c b/toys/pending/hexedit.c new file mode 100644 index 00000000..f4b16537 --- /dev/null +++ b/toys/pending/hexedit.c @@ -0,0 +1,193 @@ +/* hexedit.c - Hexadecimal file editor + * + * Copyright 2015 Rob Landley + * + * No standard + +USE_HEXEDIT(NEWTOY(hexedit, "<1>1", TOYFLAG_USR|TOYFLAG_BIN)) + +config HEXEDIT + bool "hexedit" + default n + help + usage: hexedit FILENAME + + Hexadecimal file editor. +*/ + +#define FOR_hexedit +#include "toys.h" + +GLOBALS( + char *data; + long long len, base; + int numlen; + unsigned height; +) + +static void sigttyreset(int i) +{ + set_terminal(1, 0, 0); + // how do I re-raise the signal so it dies with right signal info for wait()? + _exit(127); +} + +static void esc(char *s) +{ + printf("\033[%s", s); +} + +static void jump(x, y) +{ + char s[32]; + + sprintf(s, "%d;%dH", y+1, x+1); + esc(s); +} + +static void draw_line(long long yy) +{ + int x; + + yy = (TT.base+yy)*16; + + if (yySIZE_MAX) TT.len = SIZE_MAX; + // count file length hex digits, rounded up to multiple of 4 + for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++); + TT.numlen += (4-TT.numlen)&3; + + TT.data = mmap(0, TT.len, PROT_READ, MAP_SHARED, fd, 0); + + draw_page(); + + y = x = 0; + for (;;) { + pos = 16*(TT.base+y)+x; + if (pos>=TT.len) { + pos = TT.len-1; + x = (TT.len-1)%15; + } + esc("7m"); + highlight(TT.data[pos], x, y); + fflush(0); + key = scan_key(toybuf, keys, 1); + if (key==-1 || key==4 || key==27) break; + esc("0m"); + highlight(TT.data[pos], x, y); + +//jump(73,0); +//printf("%d[%c]", key, (key > 255) ? 'X' : key); + + if (key==KEY_UP) { + if (--y<0) { + if (TT.base) { + TT.base--; + esc("1T"); + jump(0, 0); + draw_line(0); + } + y = 0; + } + } else if (key==KEY_DOWN) { + if (y == TT.height-1 && pos+32=TT.height) y--; + } else if (key==KEY_RIGHT) { + if (x<15 && pos+1=TT.len) TT.base=(TT.len-1)/16; + draw_page(); + } else if (key==KEY_HOME) { + TT.base = 0; + draw_page(); + } else if (key==KEY_END) { + TT.base=(TT.len-1)/16; + draw_page(); + } + } + munmap(TT.data, TT.len); + close(fd); + set_terminal(1, 0, 0); + esc("?25h"); + esc("0m"); + jump(0, 999); + xputc('\n'); + +// DEBUG: dump unknown escape sequence +for (;;) { + key = scan_key(toybuf, keys, 0); + if (key >= 0) printf("%d(%c) ", key, key); + else { + printf("%d\n", key); + break; + } +} +xputc('\n'); +} -- cgit v1.2.3 From 53b0cb856deafa015626f21b5a2f972cddc015bd Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 25 Apr 2015 15:52:59 -0500 Subject: Fix display and cursor control (to respect bottom boundary). No actual editing yet. --- toys/pending/hexedit.c | 69 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/toys/pending/hexedit.c b/toys/pending/hexedit.c index f4b16537..727203c4 100644 --- a/toys/pending/hexedit.c +++ b/toys/pending/hexedit.c @@ -25,13 +25,6 @@ GLOBALS( unsigned height; ) -static void sigttyreset(int i) -{ - set_terminal(1, 0, 0); - // how do I re-raise the signal so it dies with right signal info for wait()? - _exit(127); -} - static void esc(char *s) { printf("\033[%s", s); @@ -45,6 +38,21 @@ static void jump(x, y) esc(s); } +static void fix_terminal(void) +{ + set_terminal(1, 0, 0); + esc("?25h"); + esc("0m"); + jump(0, 999); +} + +static void sigttyreset(int i) +{ + fix_terminal(); + // how do I re-raise the signal so it dies with right signal info for wait()? + _exit(127); +} + static void draw_line(long long yy) { int x; @@ -58,7 +66,23 @@ static void draw_line(long long yy) else printf(" "); } printf(" "); - for (x=0; x<16; x++) printf("X"); + for (x=0; x<16; x++) { + char broiled = TT.data[yy+x]; + + if (broiled<32 || broiled>=127) { + if (broiled>127) { + esc("2m"); + broiled &= 127; + } + if (broiled<32 || broiled==127) { + esc("7m"); + if (broiled==127) broiled = 32; + else broiled += 64; + } + printf("%c", broiled); + esc("0m"); + } else printf("%c", broiled); + } } esc("K"); } @@ -100,6 +124,7 @@ void hexedit_main(void) TT.height = 25; terminal_size(0, &TT.height); + if (TT.height) TT.height--; sigatexit(sigttyreset); esc("0m"); esc("?25l"); @@ -127,18 +152,17 @@ void hexedit_main(void) highlight(TT.data[pos], x, y); fflush(0); key = scan_key(toybuf, keys, 1); - if (key==-1 || key==4 || key==27) break; + if (key==-1 || key==4 || key==27 || key=='q') break; esc("0m"); highlight(TT.data[pos], x, y); -//jump(73,0); -//printf("%d[%c]", key, (key > 255) ? 'X' : key); - if (key==KEY_UP) { if (--y<0) { if (TT.base) { TT.base--; esc("1T"); + jump(0, TT.height); + esc("K"); jump(0, 0); draw_line(0); } @@ -163,31 +187,20 @@ void hexedit_main(void) } else if (key==KEY_PGDN) { TT.base += TT.height; if ((TT.base*16)>=TT.len) TT.base=(TT.len-1)/16; + while ((TT.base+y)*16>=TT.len) y--; + if (16*(TT.base+y)+x>=TT.len) x = (TT.len-1)&15; draw_page(); } else if (key==KEY_HOME) { TT.base = 0; + x = 0; draw_page(); } else if (key==KEY_END) { TT.base=(TT.len-1)/16; + x = (TT.len-1)&15; draw_page(); } } munmap(TT.data, TT.len); close(fd); - set_terminal(1, 0, 0); - esc("?25h"); - esc("0m"); - jump(0, 999); - xputc('\n'); - -// DEBUG: dump unknown escape sequence -for (;;) { - key = scan_key(toybuf, keys, 0); - if (key >= 0) printf("%d(%c) ", key, key); - else { - printf("%d\n", key); - break; - } -} -xputc('\n'); + fix_terminal(); } -- cgit v1.2.3 From ed753aaa5481e487a23c9e0e6a855c09612eb7ce Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 27 Apr 2015 11:08:40 -0500 Subject: Teach hexedit to actually edit. Add -r option for read only mode. --- toys/pending/hexedit.c | 112 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 34 deletions(-) diff --git a/toys/pending/hexedit.c b/toys/pending/hexedit.c index 727203c4..668e51c4 100644 --- a/toys/pending/hexedit.c +++ b/toys/pending/hexedit.c @@ -4,7 +4,7 @@ * * No standard -USE_HEXEDIT(NEWTOY(hexedit, "<1>1", TOYFLAG_USR|TOYFLAG_BIN)) +USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN)) config HEXEDIT bool "hexedit" @@ -13,6 +13,8 @@ config HEXEDIT usage: hexedit FILENAME Hexadecimal file editor. + + -r Read only (display but don't edit) */ #define FOR_hexedit @@ -30,7 +32,7 @@ static void esc(char *s) printf("\033[%s", s); } -static void jump(x, y) +static void jump(int x, int y) { char s[32]; @@ -53,6 +55,24 @@ static void sigttyreset(int i) _exit(127); } +// Render all characters printable, using color to distinguish. +static void draw_char(char broiled) +{ + if (broiled<32 || broiled>=127) { + if (broiled>127) { + esc("2m"); + broiled &= 127; + } + if (broiled<32 || broiled==127) { + esc("7m"); + if (broiled==127) broiled = 32; + else broiled += 64; + } + printf("%c", broiled); + esc("0m"); + } else printf("%c", broiled); +} + static void draw_line(long long yy) { int x; @@ -66,34 +86,12 @@ static void draw_line(long long yy) else printf(" "); } printf(" "); - for (x=0; x<16; x++) { - char broiled = TT.data[yy+x]; - - if (broiled<32 || broiled>=127) { - if (broiled>127) { - esc("2m"); - broiled &= 127; - } - if (broiled<32 || broiled==127) { - esc("7m"); - if (broiled==127) broiled = 32; - else broiled += 64; - } - printf("%c", broiled); - esc("0m"); - } else printf("%c", broiled); - } + for (x=0; x<16; x++) draw_char(TT.data[yy+x]); } esc("K"); } -static void highlight(char c, unsigned x, unsigned y) -{ - jump(2+TT.numlen+3*x, y); - printf("%02X", c); -} - -void draw_page(void) +static void draw_page(void) { int y; @@ -104,6 +102,26 @@ void draw_page(void) } } +// side: 0 = editing left, 1 = editing right, 2 = clear, 3 = read only +static void highlight(int xx, int yy, int side) +{ + char cc = TT.data[16*(TT.base+yy)+xx]; + int i; + + // Display cursor + jump(2+TT.numlen+3*xx, yy); + esc("0m"); + if (side!=2) esc("7m"); + if (side>1) printf("%02X", cc); + else for (i=0; i<2;) { + if (side==i) esc("32m"); + printf("%X", (cc>>(4*(1&++i)))&15); + } + esc("0m"); + jump(TT.numlen+17*3+xx, yy); + draw_char(cc); +} + #define KEY_UP 256 #define KEY_DOWN 257 #define KEY_RIGHT 258 @@ -120,7 +138,8 @@ void hexedit_main(void) char *keys[] = {"\033[A", "\033[B", "\033[C", "\033[D", "\033[5~", "\033[6~", "\033OH", "\033OF", "\033[2~", 0}; long long pos; - int x, y, key, fd = xopen(*toys.optargs, O_RDONLY); + int x, y, i, side = 0, key, ro = toys.optflags&FLAG_r, + fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR); TT.height = 25; terminal_size(0, &TT.height); @@ -137,25 +156,49 @@ void hexedit_main(void) for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++); TT.numlen += (4-TT.numlen)&3; - TT.data = mmap(0, TT.len, PROT_READ, MAP_SHARED, fd, 0); + TT.data = mmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0); draw_page(); y = x = 0; for (;;) { + // Get position within file, trimming if we overshot end. pos = 16*(TT.base+y)+x; if (pos>=TT.len) { pos = TT.len-1; x = (TT.len-1)%15; } - esc("7m"); - highlight(TT.data[pos], x, y); + + // Display cursor + highlight(x, y, ro ? 3 : side); fflush(0); - key = scan_key(toybuf, keys, 1); - if (key==-1 || key==4 || key==27 || key=='q') break; - esc("0m"); - highlight(TT.data[pos], x, y); + // Wait for next key + key = scan_key(toybuf, keys, 1); + // Exit for q, ctrl-c, ctrl-d, escape, or EOF + if (key==-1 || key==3 || key==4 || key==27 || key=='q') break; + highlight(x, y, 2); + + if (key>='a' && key<='f') key-=32; + if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) { + i = key - '0'; + if (i>9) i -= 7; + TT.data[pos] &= 15<<(4*side); + TT.data[pos] |= i<<(4*!side); + + highlight(x, y, ++side); + if (side==2) { + side = 0; + if (++pos255) side = 0; if (key==KEY_UP) { if (--y<0) { if (TT.base) { @@ -170,6 +213,7 @@ void hexedit_main(void) } } else if (key==KEY_DOWN) { if (y == TT.height-1 && pos+32 Date: Mon, 27 Apr 2015 11:13:19 -0500 Subject: Some infrastructure hexedit needs. (Poor man's curses.) --- lib/lib.c | 98 +++++++++++++++++++ lib/lib.h | 3 + lib/net.c | 5 + lib/password.c | 33 ------- toys/other/hexedit.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++ toys/pending/hexedit.c | 250 ------------------------------------------------- 6 files changed, 356 insertions(+), 283 deletions(-) create mode 100644 toys/other/hexedit.c delete mode 100644 toys/pending/hexedit.c diff --git a/lib/lib.c b/lib/lib.c index 1a60a7ff..ab773b5b 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -637,6 +637,40 @@ int terminal_size(unsigned *xx, unsigned *yy) return x || y; } +// Reset terminal to known state, saving copy of old state if old != NULL. +int set_terminal(int fd, int raw, struct termios *old) +{ + struct termios termio; + + // Fetch local copy of old terminfo, and copy struct contents to *old if set + if (!tcgetattr(fd, &termio) && old) *old = termio; + + // the following are the bits set for an xterm. Linux text mode TTYs by + // default add two additional bits that only matter for serial processing + // (turn serial line break into an interrupt, and XON/XOFF flow control) + + // Any key unblocks output, swap CR and NL on input + termio.c_iflag = IXANY|ICRNL|INLCR; + if (toys.which->flags & TOYFLAG_LOCALE) termio.c_iflag |= IUTF8; + + // Output appends CR to NL, does magic undocumented postprocessing + termio.c_oflag = ONLCR|OPOST; + + // Leave serial port speed alone + // termio.c_cflag = C_READ|CS8|EXTB; + + // Generate signals, input entire line at once, echo output + // erase, line kill, escape control characters with ^ + // erase line char at a time + // "extended" behavior: ctrl-V quotes next char, ctrl-R reprints unread chars, + // ctrl-W erases word + termio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN; + + if (raw) cfmakeraw(&termio); + + return tcsetattr(fd, TCSANOW, &termio); +} + int yesno(char *prompt, int def) { char buf; @@ -895,3 +929,67 @@ int qstrcmp(const void *a, const void *b) { return strcmp(*(char **)a, *(char **)b); } + +int xpoll(struct pollfd *fds, int nfds, int timeout) +{ + int i; + + for (;;) { + if (0>(i = poll(fds, nfds, timeout))) { + if (errno != EINTR && errno != ENOMEM) perror_exit("xpoll"); + else if (timeout>0) timeout--; + } else return i; + } +} + +// Scan stdin for a keypress, parsing known escape sequences +// seq is array of char * strings, ends with NULL ptr +// Returns: 0-255=literal, -1=EOF, -2=NONE, 256-...=index into seq +// scratch space is necessary because last char of !seq could start new seq +// Zero out first byte of scratch before first call to scan_key +// block=0 allows fetching multiple characters before updating display +int scan_key(char *scratch, char **seqs, int block) +{ + struct pollfd pfd; + int maybe, i, j; + char *test; + + for (;;) { + pfd.fd = 0; + pfd.events = POLLIN; + pfd.revents = 0; + + // check sequences + maybe = 0; + if (*scratch) { + for (i = maybe = 0; (test = seqs[i]); i++) { + for (j = 0; j<*scratch; j++) if (scratch[j+1] != test[j]) break; + if (j == *scratch) { + maybe = 1; + if (!test[j]) { + // We recognized current sequence: consume and return + *scratch = 0; + return 256+i; + } + } + } + // If current data can't be a known sequence, return next raw char + if (!maybe) break; + } + + // Need more data to decide + + // 30 miliseconds is about the gap between characters at 300 baud + if (maybe || !block) if (!xpoll(&pfd, 1, 30*maybe)) break; + + if (1 != read(0, scratch+1+*scratch, 1)) return -1; + ++*scratch; + } + + // Was not a sequence + if (!*scratch) return -2; + i = scratch[1]; + if (--*scratch) memmove(scratch+1, scratch+2, *scratch); + + return i; +} diff --git a/lib/lib.h b/lib/lib.h index a4e5808d..bdd78c9a 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -174,9 +174,12 @@ void replace_tempfile(int fdin, int fdout, char **tempname); void crc_init(unsigned int *crc_table, int little_endian); void base64_init(char *p); int terminal_size(unsigned *x, unsigned *y); +int set_terminal(int fd, int raw, struct termios *old); int yesno(char *prompt, int def); int human_readable(char *buf, unsigned long long num); int qstrcmp(const void *a, const void *b); +int xpoll(struct pollfd *fds, int nfds, int timeout); +int scan_key(char *scratch, char **seqs, int block); // net.c int xsocket(int domain, int type, int protocol); diff --git a/lib/net.c b/lib/net.c index c12eff43..5d3ea4a8 100644 --- a/lib/net.c +++ b/lib/net.c @@ -7,3 +7,8 @@ int xsocket(int domain, int type, int protocol) if (fd < 0) perror_exit("socket %x %x", type, protocol); return fd; } + +void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len) +{ + if (-1 == setsockopt(fd, level, opt, val, len)) perror_exit("setsockopt"); +} diff --git a/lib/password.c b/lib/password.c index b3cc199e..9654d42d 100644 --- a/lib/password.c +++ b/lib/password.c @@ -46,39 +46,6 @@ int get_salt(char *salt, char *algo) return -1; } -// Reset terminal to known state, returning old state if old != NULL. -int set_terminal(int fd, int raw, struct termios *old) -{ - struct termios termio; - - if (!tcgetattr(fd, &termio) && old) *old = termio; - - // the following are the bits set for an xterm. Linux text mode TTYs by - // default add two additional bits that only matter for serial processing - // (turn serial line break into an interrupt, and XON/XOFF flow control) - - // Any key unblocks output, swap CR and NL on input - termio.c_iflag = IXANY|ICRNL|INLCR; - if (toys.which->flags & TOYFLAG_LOCALE) termio.c_iflag |= IUTF8; - - // Output appends CR to NL, does magic undocumented postprocessing - termio.c_oflag = ONLCR|OPOST; - - // Leave serial port speed alone - // termio.c_cflag = C_READ|CS8|EXTB; - - // Generate signals, input entire line at once, echo output - // erase, line kill, escape control characters with ^ - // erase line char at a time - // "extended" behavior: ctrl-V quotes next char, ctrl-R reprints unread chars, - // ctrl-W erases word - termio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN; - - if (raw) cfmakeraw(&termio); - - return tcsetattr(fd, TCSANOW, &termio); -} - // Prompt with mesg, read password into buf, return 0 for success 1 for fail int read_password(char *buf, int buflen, char *mesg) { diff --git a/toys/other/hexedit.c b/toys/other/hexedit.c new file mode 100644 index 00000000..668e51c4 --- /dev/null +++ b/toys/other/hexedit.c @@ -0,0 +1,250 @@ +/* hexedit.c - Hexadecimal file editor + * + * Copyright 2015 Rob Landley + * + * No standard + +USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN)) + +config HEXEDIT + bool "hexedit" + default n + help + usage: hexedit FILENAME + + Hexadecimal file editor. + + -r Read only (display but don't edit) +*/ + +#define FOR_hexedit +#include "toys.h" + +GLOBALS( + char *data; + long long len, base; + int numlen; + unsigned height; +) + +static void esc(char *s) +{ + printf("\033[%s", s); +} + +static void jump(int x, int y) +{ + char s[32]; + + sprintf(s, "%d;%dH", y+1, x+1); + esc(s); +} + +static void fix_terminal(void) +{ + set_terminal(1, 0, 0); + esc("?25h"); + esc("0m"); + jump(0, 999); +} + +static void sigttyreset(int i) +{ + fix_terminal(); + // how do I re-raise the signal so it dies with right signal info for wait()? + _exit(127); +} + +// Render all characters printable, using color to distinguish. +static void draw_char(char broiled) +{ + if (broiled<32 || broiled>=127) { + if (broiled>127) { + esc("2m"); + broiled &= 127; + } + if (broiled<32 || broiled==127) { + esc("7m"); + if (broiled==127) broiled = 32; + else broiled += 64; + } + printf("%c", broiled); + esc("0m"); + } else printf("%c", broiled); +} + +static void draw_line(long long yy) +{ + int x; + + yy = (TT.base+yy)*16; + + if (yy1) printf("%02X", cc); + else for (i=0; i<2;) { + if (side==i) esc("32m"); + printf("%X", (cc>>(4*(1&++i)))&15); + } + esc("0m"); + jump(TT.numlen+17*3+xx, yy); + draw_char(cc); +} + +#define KEY_UP 256 +#define KEY_DOWN 257 +#define KEY_RIGHT 258 +#define KEY_LEFT 259 +#define KEY_PGUP 260 +#define KEY_PGDN 261 +#define KEY_HOME 262 +#define KEY_END 263 +#define KEY_INSERT 264 + +void hexedit_main(void) +{ + // up down right left pgup pgdn home end ins + char *keys[] = {"\033[A", "\033[B", "\033[C", "\033[D", "\033[5~", "\033[6~", + "\033OH", "\033OF", "\033[2~", 0}; + long long pos; + int x, y, i, side = 0, key, ro = toys.optflags&FLAG_r, + fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR); + + TT.height = 25; + terminal_size(0, &TT.height); + if (TT.height) TT.height--; + sigatexit(sigttyreset); + esc("0m"); + esc("?25l"); + fflush(0); + set_terminal(1, 1, 0); + + if ((TT.len = fdlength(fd))<0) error_exit("bad length"); + if (sizeof(long)==32 && TT.len>SIZE_MAX) TT.len = SIZE_MAX; + // count file length hex digits, rounded up to multiple of 4 + for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++); + TT.numlen += (4-TT.numlen)&3; + + TT.data = mmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0); + + draw_page(); + + y = x = 0; + for (;;) { + // Get position within file, trimming if we overshot end. + pos = 16*(TT.base+y)+x; + if (pos>=TT.len) { + pos = TT.len-1; + x = (TT.len-1)%15; + } + + // Display cursor + highlight(x, y, ro ? 3 : side); + fflush(0); + + // Wait for next key + key = scan_key(toybuf, keys, 1); + // Exit for q, ctrl-c, ctrl-d, escape, or EOF + if (key==-1 || key==3 || key==4 || key==27 || key=='q') break; + highlight(x, y, 2); + + if (key>='a' && key<='f') key-=32; + if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) { + i = key - '0'; + if (i>9) i -= 7; + TT.data[pos] &= 15<<(4*side); + TT.data[pos] |= i<<(4*!side); + + highlight(x, y, ++side); + if (side==2) { + side = 0; + if (++pos255) side = 0; + if (key==KEY_UP) { + if (--y<0) { + if (TT.base) { + TT.base--; + esc("1T"); + jump(0, TT.height); + esc("K"); + jump(0, 0); + draw_line(0); + } + y = 0; + } + } else if (key==KEY_DOWN) { + if (y == TT.height-1 && pos+32=TT.height) y--; + } else if (key==KEY_RIGHT) { + if (x<15 && pos+1=TT.len) TT.base=(TT.len-1)/16; + while ((TT.base+y)*16>=TT.len) y--; + if (16*(TT.base+y)+x>=TT.len) x = (TT.len-1)&15; + draw_page(); + } else if (key==KEY_HOME) { + TT.base = 0; + x = 0; + draw_page(); + } else if (key==KEY_END) { + TT.base=(TT.len-1)/16; + x = (TT.len-1)&15; + draw_page(); + } + } + munmap(TT.data, TT.len); + close(fd); + fix_terminal(); +} diff --git a/toys/pending/hexedit.c b/toys/pending/hexedit.c deleted file mode 100644 index 668e51c4..00000000 --- a/toys/pending/hexedit.c +++ /dev/null @@ -1,250 +0,0 @@ -/* hexedit.c - Hexadecimal file editor - * - * Copyright 2015 Rob Landley - * - * No standard - -USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN)) - -config HEXEDIT - bool "hexedit" - default n - help - usage: hexedit FILENAME - - Hexadecimal file editor. - - -r Read only (display but don't edit) -*/ - -#define FOR_hexedit -#include "toys.h" - -GLOBALS( - char *data; - long long len, base; - int numlen; - unsigned height; -) - -static void esc(char *s) -{ - printf("\033[%s", s); -} - -static void jump(int x, int y) -{ - char s[32]; - - sprintf(s, "%d;%dH", y+1, x+1); - esc(s); -} - -static void fix_terminal(void) -{ - set_terminal(1, 0, 0); - esc("?25h"); - esc("0m"); - jump(0, 999); -} - -static void sigttyreset(int i) -{ - fix_terminal(); - // how do I re-raise the signal so it dies with right signal info for wait()? - _exit(127); -} - -// Render all characters printable, using color to distinguish. -static void draw_char(char broiled) -{ - if (broiled<32 || broiled>=127) { - if (broiled>127) { - esc("2m"); - broiled &= 127; - } - if (broiled<32 || broiled==127) { - esc("7m"); - if (broiled==127) broiled = 32; - else broiled += 64; - } - printf("%c", broiled); - esc("0m"); - } else printf("%c", broiled); -} - -static void draw_line(long long yy) -{ - int x; - - yy = (TT.base+yy)*16; - - if (yy1) printf("%02X", cc); - else for (i=0; i<2;) { - if (side==i) esc("32m"); - printf("%X", (cc>>(4*(1&++i)))&15); - } - esc("0m"); - jump(TT.numlen+17*3+xx, yy); - draw_char(cc); -} - -#define KEY_UP 256 -#define KEY_DOWN 257 -#define KEY_RIGHT 258 -#define KEY_LEFT 259 -#define KEY_PGUP 260 -#define KEY_PGDN 261 -#define KEY_HOME 262 -#define KEY_END 263 -#define KEY_INSERT 264 - -void hexedit_main(void) -{ - // up down right left pgup pgdn home end ins - char *keys[] = {"\033[A", "\033[B", "\033[C", "\033[D", "\033[5~", "\033[6~", - "\033OH", "\033OF", "\033[2~", 0}; - long long pos; - int x, y, i, side = 0, key, ro = toys.optflags&FLAG_r, - fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR); - - TT.height = 25; - terminal_size(0, &TT.height); - if (TT.height) TT.height--; - sigatexit(sigttyreset); - esc("0m"); - esc("?25l"); - fflush(0); - set_terminal(1, 1, 0); - - if ((TT.len = fdlength(fd))<0) error_exit("bad length"); - if (sizeof(long)==32 && TT.len>SIZE_MAX) TT.len = SIZE_MAX; - // count file length hex digits, rounded up to multiple of 4 - for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++); - TT.numlen += (4-TT.numlen)&3; - - TT.data = mmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0); - - draw_page(); - - y = x = 0; - for (;;) { - // Get position within file, trimming if we overshot end. - pos = 16*(TT.base+y)+x; - if (pos>=TT.len) { - pos = TT.len-1; - x = (TT.len-1)%15; - } - - // Display cursor - highlight(x, y, ro ? 3 : side); - fflush(0); - - // Wait for next key - key = scan_key(toybuf, keys, 1); - // Exit for q, ctrl-c, ctrl-d, escape, or EOF - if (key==-1 || key==3 || key==4 || key==27 || key=='q') break; - highlight(x, y, 2); - - if (key>='a' && key<='f') key-=32; - if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) { - i = key - '0'; - if (i>9) i -= 7; - TT.data[pos] &= 15<<(4*side); - TT.data[pos] |= i<<(4*!side); - - highlight(x, y, ++side); - if (side==2) { - side = 0; - if (++pos255) side = 0; - if (key==KEY_UP) { - if (--y<0) { - if (TT.base) { - TT.base--; - esc("1T"); - jump(0, TT.height); - esc("K"); - jump(0, 0); - draw_line(0); - } - y = 0; - } - } else if (key==KEY_DOWN) { - if (y == TT.height-1 && pos+32=TT.height) y--; - } else if (key==KEY_RIGHT) { - if (x<15 && pos+1=TT.len) TT.base=(TT.len-1)/16; - while ((TT.base+y)*16>=TT.len) y--; - if (16*(TT.base+y)+x>=TT.len) x = (TT.len-1)&15; - draw_page(); - } else if (key==KEY_HOME) { - TT.base = 0; - x = 0; - draw_page(); - } else if (key==KEY_END) { - TT.base=(TT.len-1)/16; - x = (TT.len-1)&15; - draw_page(); - } - } - munmap(TT.data, TT.len); - close(fd); - fix_terminal(); -} -- cgit v1.2.3 From 4c182c325716776a3e40394b175de479738e31a6 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 27 Apr 2015 11:14:46 -0500 Subject: Promote hexedit to other. --- toys/other/hexedit.c | 250 ------------------------------------------------- toys/pending/hexedit.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+), 250 deletions(-) delete mode 100644 toys/other/hexedit.c create mode 100644 toys/pending/hexedit.c diff --git a/toys/other/hexedit.c b/toys/other/hexedit.c deleted file mode 100644 index 668e51c4..00000000 --- a/toys/other/hexedit.c +++ /dev/null @@ -1,250 +0,0 @@ -/* hexedit.c - Hexadecimal file editor - * - * Copyright 2015 Rob Landley - * - * No standard - -USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN)) - -config HEXEDIT - bool "hexedit" - default n - help - usage: hexedit FILENAME - - Hexadecimal file editor. - - -r Read only (display but don't edit) -*/ - -#define FOR_hexedit -#include "toys.h" - -GLOBALS( - char *data; - long long len, base; - int numlen; - unsigned height; -) - -static void esc(char *s) -{ - printf("\033[%s", s); -} - -static void jump(int x, int y) -{ - char s[32]; - - sprintf(s, "%d;%dH", y+1, x+1); - esc(s); -} - -static void fix_terminal(void) -{ - set_terminal(1, 0, 0); - esc("?25h"); - esc("0m"); - jump(0, 999); -} - -static void sigttyreset(int i) -{ - fix_terminal(); - // how do I re-raise the signal so it dies with right signal info for wait()? - _exit(127); -} - -// Render all characters printable, using color to distinguish. -static void draw_char(char broiled) -{ - if (broiled<32 || broiled>=127) { - if (broiled>127) { - esc("2m"); - broiled &= 127; - } - if (broiled<32 || broiled==127) { - esc("7m"); - if (broiled==127) broiled = 32; - else broiled += 64; - } - printf("%c", broiled); - esc("0m"); - } else printf("%c", broiled); -} - -static void draw_line(long long yy) -{ - int x; - - yy = (TT.base+yy)*16; - - if (yy1) printf("%02X", cc); - else for (i=0; i<2;) { - if (side==i) esc("32m"); - printf("%X", (cc>>(4*(1&++i)))&15); - } - esc("0m"); - jump(TT.numlen+17*3+xx, yy); - draw_char(cc); -} - -#define KEY_UP 256 -#define KEY_DOWN 257 -#define KEY_RIGHT 258 -#define KEY_LEFT 259 -#define KEY_PGUP 260 -#define KEY_PGDN 261 -#define KEY_HOME 262 -#define KEY_END 263 -#define KEY_INSERT 264 - -void hexedit_main(void) -{ - // up down right left pgup pgdn home end ins - char *keys[] = {"\033[A", "\033[B", "\033[C", "\033[D", "\033[5~", "\033[6~", - "\033OH", "\033OF", "\033[2~", 0}; - long long pos; - int x, y, i, side = 0, key, ro = toys.optflags&FLAG_r, - fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR); - - TT.height = 25; - terminal_size(0, &TT.height); - if (TT.height) TT.height--; - sigatexit(sigttyreset); - esc("0m"); - esc("?25l"); - fflush(0); - set_terminal(1, 1, 0); - - if ((TT.len = fdlength(fd))<0) error_exit("bad length"); - if (sizeof(long)==32 && TT.len>SIZE_MAX) TT.len = SIZE_MAX; - // count file length hex digits, rounded up to multiple of 4 - for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++); - TT.numlen += (4-TT.numlen)&3; - - TT.data = mmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0); - - draw_page(); - - y = x = 0; - for (;;) { - // Get position within file, trimming if we overshot end. - pos = 16*(TT.base+y)+x; - if (pos>=TT.len) { - pos = TT.len-1; - x = (TT.len-1)%15; - } - - // Display cursor - highlight(x, y, ro ? 3 : side); - fflush(0); - - // Wait for next key - key = scan_key(toybuf, keys, 1); - // Exit for q, ctrl-c, ctrl-d, escape, or EOF - if (key==-1 || key==3 || key==4 || key==27 || key=='q') break; - highlight(x, y, 2); - - if (key>='a' && key<='f') key-=32; - if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) { - i = key - '0'; - if (i>9) i -= 7; - TT.data[pos] &= 15<<(4*side); - TT.data[pos] |= i<<(4*!side); - - highlight(x, y, ++side); - if (side==2) { - side = 0; - if (++pos255) side = 0; - if (key==KEY_UP) { - if (--y<0) { - if (TT.base) { - TT.base--; - esc("1T"); - jump(0, TT.height); - esc("K"); - jump(0, 0); - draw_line(0); - } - y = 0; - } - } else if (key==KEY_DOWN) { - if (y == TT.height-1 && pos+32=TT.height) y--; - } else if (key==KEY_RIGHT) { - if (x<15 && pos+1=TT.len) TT.base=(TT.len-1)/16; - while ((TT.base+y)*16>=TT.len) y--; - if (16*(TT.base+y)+x>=TT.len) x = (TT.len-1)&15; - draw_page(); - } else if (key==KEY_HOME) { - TT.base = 0; - x = 0; - draw_page(); - } else if (key==KEY_END) { - TT.base=(TT.len-1)/16; - x = (TT.len-1)&15; - draw_page(); - } - } - munmap(TT.data, TT.len); - close(fd); - fix_terminal(); -} diff --git a/toys/pending/hexedit.c b/toys/pending/hexedit.c new file mode 100644 index 00000000..518755bb --- /dev/null +++ b/toys/pending/hexedit.c @@ -0,0 +1,250 @@ +/* hexedit.c - Hexadecimal file editor + * + * Copyright 2015 Rob Landley + * + * No standard + +USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN)) + +config HEXEDIT + bool "hexedit" + default y + help + usage: hexedit FILENAME + + Hexadecimal file editor. + + -r Read only (display but don't edit) +*/ + +#define FOR_hexedit +#include "toys.h" + +GLOBALS( + char *data; + long long len, base; + int numlen; + unsigned height; +) + +static void esc(char *s) +{ + printf("\033[%s", s); +} + +static void jump(int x, int y) +{ + char s[32]; + + sprintf(s, "%d;%dH", y+1, x+1); + esc(s); +} + +static void fix_terminal(void) +{ + set_terminal(1, 0, 0); + esc("?25h"); + esc("0m"); + jump(0, 999); +} + +static void sigttyreset(int i) +{ + fix_terminal(); + // how do I re-raise the signal so it dies with right signal info for wait()? + _exit(127); +} + +// Render all characters printable, using color to distinguish. +static void draw_char(char broiled) +{ + if (broiled<32 || broiled>=127) { + if (broiled>127) { + esc("2m"); + broiled &= 127; + } + if (broiled<32 || broiled==127) { + esc("7m"); + if (broiled==127) broiled = 32; + else broiled += 64; + } + printf("%c", broiled); + esc("0m"); + } else printf("%c", broiled); +} + +static void draw_line(long long yy) +{ + int x; + + yy = (TT.base+yy)*16; + + if (yy1) printf("%02X", cc); + else for (i=0; i<2;) { + if (side==i) esc("32m"); + printf("%X", (cc>>(4*(1&++i)))&15); + } + esc("0m"); + jump(TT.numlen+17*3+xx, yy); + draw_char(cc); +} + +#define KEY_UP 256 +#define KEY_DOWN 257 +#define KEY_RIGHT 258 +#define KEY_LEFT 259 +#define KEY_PGUP 260 +#define KEY_PGDN 261 +#define KEY_HOME 262 +#define KEY_END 263 +#define KEY_INSERT 264 + +void hexedit_main(void) +{ + // up down right left pgup pgdn home end ins + char *keys[] = {"\033[A", "\033[B", "\033[C", "\033[D", "\033[5~", "\033[6~", + "\033OH", "\033OF", "\033[2~", 0}; + long long pos; + int x, y, i, side = 0, key, ro = toys.optflags&FLAG_r, + fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR); + + TT.height = 25; + terminal_size(0, &TT.height); + if (TT.height) TT.height--; + sigatexit(sigttyreset); + esc("0m"); + esc("?25l"); + fflush(0); + set_terminal(1, 1, 0); + + if ((TT.len = fdlength(fd))<0) error_exit("bad length"); + if (sizeof(long)==32 && TT.len>SIZE_MAX) TT.len = SIZE_MAX; + // count file length hex digits, rounded up to multiple of 4 + for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++); + TT.numlen += (4-TT.numlen)&3; + + TT.data = mmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0); + + draw_page(); + + y = x = 0; + for (;;) { + // Get position within file, trimming if we overshot end. + pos = 16*(TT.base+y)+x; + if (pos>=TT.len) { + pos = TT.len-1; + x = (TT.len-1)%15; + } + + // Display cursor + highlight(x, y, ro ? 3 : side); + fflush(0); + + // Wait for next key + key = scan_key(toybuf, keys, 1); + // Exit for q, ctrl-c, ctrl-d, escape, or EOF + if (key==-1 || key==3 || key==4 || key==27 || key=='q') break; + highlight(x, y, 2); + + if (key>='a' && key<='f') key-=32; + if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) { + i = key - '0'; + if (i>9) i -= 7; + TT.data[pos] &= 15<<(4*side); + TT.data[pos] |= i<<(4*!side); + + highlight(x, y, ++side); + if (side==2) { + side = 0; + if (++pos255) side = 0; + if (key==KEY_UP) { + if (--y<0) { + if (TT.base) { + TT.base--; + esc("1T"); + jump(0, TT.height); + esc("K"); + jump(0, 0); + draw_line(0); + } + y = 0; + } + } else if (key==KEY_DOWN) { + if (y == TT.height-1 && pos+32=TT.height) y--; + } else if (key==KEY_RIGHT) { + if (x<15 && pos+1=TT.len) TT.base=(TT.len-1)/16; + while ((TT.base+y)*16>=TT.len) y--; + if (16*(TT.base+y)+x>=TT.len) x = (TT.len-1)&15; + draw_page(); + } else if (key==KEY_HOME) { + TT.base = 0; + x = 0; + draw_page(); + } else if (key==KEY_END) { + TT.base=(TT.len-1)/16; + x = (TT.len-1)&15; + draw_page(); + } + } + munmap(TT.data, TT.len); + close(fd); + fix_terminal(); +} -- cgit v1.2.3 From 2b8a6f636854e2b07c7ba9bedcbbd275e27b69bd Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 27 Apr 2015 18:56:11 -0500 Subject: Fix ls -s and -i indentation in -C and -x modes. (Spotted by Jan Cybulski.) --- toys/posix/ls.c | 60 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/toys/posix/ls.c b/toys/posix/ls.c index a9241379..3c37c7e0 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -128,6 +128,11 @@ static char *getgroupname(gid_t gid) return gr ? gr->gr_name : TT.gid_buf; } +static int numlen(long long ll) +{ + return snprintf(0, 0, "%llu", ll); +} + // Figure out size of printable entry fields for display indent/wrap static void entrylen(struct dirtree *dt, unsigned *len) @@ -139,21 +144,20 @@ static void entrylen(struct dirtree *dt, unsigned *len) if (endtype(st)) ++*len; if (flags & FLAG_m) ++*len; - if (flags & FLAG_i) *len += (len[1] = numlen(st->st_ino)); + len[1] = (flags & FLAG_i) ? numlen(st->st_ino) : 0; if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { unsigned fn = flags & FLAG_n; len[2] = numlen(st->st_nlink); - len[3] = fn ? snprintf(0, 0, "%u", (unsigned)st->st_uid) - : strwidth(getusername(st->st_uid)); - len[4] = fn ? snprintf(0, 0, "%u", (unsigned)st->st_gid) - : strwidth(getgroupname(st->st_gid)); + len[3] = fn ? numlen(st->st_uid) : strwidth(getusername(st->st_uid)); + len[4] = fn ? numlen(st->st_gid) : strwidth(getgroupname(st->st_gid)); if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) { // cheating slightly here: assuming minor is always 3 digits to avoid // tracking another column len[5] = numlen(major(st->st_rdev))+5; } else len[5] = numlen(st->st_size); } - if (flags & FLAG_s) *len += (len[6] = numlen(st->st_blocks)); + + len[6] = (flags & FLAG_s) ? numlen(st->st_blocks) : 0; } static int compare(void *a, void *b) @@ -259,7 +263,7 @@ static void listfiles(int dirfd, struct dirtree *indir) { struct dirtree *dt, **sort = 0; unsigned long dtlen = 0, ul = 0; - unsigned width, flags = toys.optflags, totals[7], len[7], + unsigned width, flags = toys.optflags, totals[7], len[7], totpad = 0, *colsizes = (unsigned *)(toybuf+260), columns = (sizeof(toybuf)-260)/4; memset(totals, 0, sizeof(totals)); @@ -303,7 +307,20 @@ static void listfiles(int dirfd, struct dirtree *indir) free(path); } - if (!(flags & FLAG_f)) qsort(sort, dtlen, sizeof(void *), (void *)compare); + if (!(flags & FLAG_f)) { + unsigned long long blocks = 0; + + qsort(sort, dtlen, sizeof(void *), (void *)compare); + for (ul = 0; ultotals[width]) totals[width] = len[width]; + totpad = totals[1]+!!totals[1]+totals[6]+!!totals[6]; + blocks += sort[ul]->st.st_blocks; + } + if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s) && indir->parent) + xprintf("total %llu\n", blocks); + } // Find largest entry in each field for display alignment if (flags & (FLAG_C|FLAG_x)) { @@ -320,29 +337,18 @@ static void listfiles(int dirfd, struct dirtree *indir) memset(colsizes, 0, columns*sizeof(unsigned)); for (ul=0; ul colsizes[c]) { - totlen += *len-colsizes[c]; + totlen += (*len)-colsizes[c]; colsizes[c] = *len; if (totlen > TT.screen_width) break; } } - // If it fit, stop here + // If everything fit, stop here if (ul == dtlen) break; } - } else if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s)) { - unsigned long blocks = 0; - - for (ul = 0; ul totals[width]) totals[width] = len[width]; - blocks += sort[ul]->st.st_blocks; - } - - if (indir->parent) xprintf("total %lu\n", blocks); } // Loop through again to produce output. @@ -375,8 +381,10 @@ static void listfiles(int dirfd, struct dirtree *indir) } width += *len; - if (flags & FLAG_i) xprintf("%*lu ", len[1], (unsigned long)st->st_ino); - if (flags & FLAG_s) xprintf("%*lu ", len[6], (unsigned long)st->st_blocks); + if (flags & FLAG_i) + xprintf("%*lu ", totals[1], (unsigned long)st->st_ino); + if (flags & FLAG_s) + xprintf("%*lu ", totals[6], (unsigned long)st->st_blocks); if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { struct tm *tm; @@ -441,7 +449,7 @@ static void listfiles(int dirfd, struct dirtree *indir) // Pad columns if (flags & (FLAG_C|FLAG_x)) { - curcol = colsizes[curcol] - *len; + curcol = colsizes[curcol]-(*len)-totpad; if (curcol < 255) xprintf("%s", toybuf+255-curcol); } } -- cgit v1.2.3 From 89701da1fef87dad77927d30194ab28f19d26366 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 28 Apr 2015 11:45:13 -0500 Subject: Add prefix support Hyejin Kim asked about. --- toys/other/truncate.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/toys/other/truncate.c b/toys/other/truncate.c index d09818f3..2b3d4795 100644 --- a/toys/other/truncate.c +++ b/toys/other/truncate.c @@ -2,37 +2,61 @@ * * Copyright 2011 Rob Landley -USE_TRUNCATE(NEWTOY(truncate, "<1s#|c", TOYFLAG_BIN)) +USE_TRUNCATE(NEWTOY(truncate, "<1s:|c", TOYFLAG_BIN)) config TRUNCATE bool "truncate" default y help - usage: truncate [-c] -s file... + usage: truncate [-c] -s SIZE file... Set length of file(s), extending sparsely if necessary. -c Don't create file if it doesn't exist. - -s New size + -s New size (with optional prefix and suffix) + + SIZE prefix: + add, - subtract, < shrink to, > expand to, + / block size rounding down, % block size rounding up + SIZE suffix: k=1024, m=1024^2, g=1024^3, t=1024^4, p=1024^5, e=1024^6 */ #define FOR_truncate #include "toys.h" GLOBALS( + char *s; + long size; + int type; ) static void do_truncate(int fd, char *name) { + long long size; + if (fd<0) return; - if (ftruncate(fd, TT.size)) perror_msg("'%s' to '%ld'", name, TT.size); + + if (TT.type == -1) size = TT.size; + else { + size = fdlength(fd); + if (TT.type<2) size += TT.size*(1-(2*TT.type)); + else if (TT.type<4) { + if ((TT.type==3) ? size > TT.size : size < TT.size) size = TT.size; + } else { + size = (size+(TT.type-4)*(TT.size-1))/TT.size; + size *= TT.size; + } + } + if (ftruncate(fd, size)) perror_msg("'%s' to '%lld'", name, size); } void truncate_main(void) { int cr = !(toys.optflags&1); + if (-1 != (TT.type = stridx("+-<>/%", *TT.s))) TT.s++; + TT.size = atolx(TT.s); + // Create files with mask rwrwrw. // Nonexistent files are only an error if we're supposed to create them. loopfiles_rw(toys.optargs, O_WRONLY|O_CLOEXEC|(cr ? O_CREAT : 0), 0666, cr, -- cgit v1.2.3 From 789665dc51c85f6fabfaf6f70f12d54b9df117df Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 28 Apr 2015 12:18:17 -0500 Subject: Fix truncate prefix bug and add truncate test suite entry. --- tests/truncate.test | 28 ++++++++++++++++++++++++++++ toys/other/truncate.c | 5 +++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100755 tests/truncate.test diff --git a/tests/truncate.test b/tests/truncate.test new file mode 100755 index 00000000..ee2b2bb8 --- /dev/null +++ b/tests/truncate.test @@ -0,0 +1,28 @@ +#!/bin/bash + +[ -f testing.sh ] && . testing.sh + +#testing "name" "command" "result" "infile" "stdin" + +SIZE='&& stat -c %s freep' +testing "truncate 0" "truncate -s 0 freep $SIZE" "0\n" "" "" +testing "truncate 12345" "truncate -s 12345 freep $SIZE" "12345\n" "" "" +testing "truncate 1m" "truncate -s 1m freep $SIZE" "1048576\n" "" "" +testing "truncate is sparse" "truncate -s 1g freep && stat -c %b freep" \ + "0\n" "" "" +testing "truncate +" "truncate -s 1k freep && truncate -s +1k freep $SIZE" \ + "2048\n" "" "" +testing "truncate -" "truncate -s 4k freep && truncate -s -1k freep $SIZE" \ + "3072\n" "" "" +testing "truncate < hit" \ + "truncate -s 5k freep && truncate -s \<4k freep $SIZE" "4096\n" "" "" +testing "truncate < miss" \ + "truncate -s 4k freep && truncate -s \<6k freep $SIZE" "4096\n" "" "" +testing "truncate > hit" \ + "truncate -s 3k freep && truncate -s \>4k freep $SIZE" "4096\n" "" "" +testing "truncate > miss" \ + "truncate -s 4k freep && truncate -s \>2k freep $SIZE" "4096\n" "" "" +testing "truncate /" "truncate -s 7k freep && truncate -s /3k freep $SIZE" \ + "6144\n" "" "" +testing "truncate %" "truncate -s 7k freep && truncate -s %3k freep $SIZE" \ + "9216\n" "" "" diff --git a/toys/other/truncate.c b/toys/other/truncate.c index 2b3d4795..bfe1f10c 100644 --- a/toys/other/truncate.c +++ b/toys/other/truncate.c @@ -16,7 +16,7 @@ config TRUNCATE -s New size (with optional prefix and suffix) SIZE prefix: + add, - subtract, < shrink to, > expand to, - / block size rounding down, % block size rounding up + / multiple rounding down, % multiple rounding up SIZE suffix: k=1024, m=1024^2, g=1024^3, t=1024^4, p=1024^5, e=1024^6 */ @@ -41,7 +41,8 @@ static void do_truncate(int fd, char *name) size = fdlength(fd); if (TT.type<2) size += TT.size*(1-(2*TT.type)); else if (TT.type<4) { - if ((TT.type==3) ? size > TT.size : size < TT.size) size = TT.size; + if ((TT.type==2) ? (size <= TT.size) : (size >= TT.size)) return; + size = TT.size; } else { size = (size+(TT.type-4)*(TT.size-1))/TT.size; size *= TT.size; -- cgit v1.2.3 From e94931034578707958fecb7f34dcd3a0a175eaf7 Mon Sep 17 00:00:00 2001 From: Jan Cybulski Date: Mon, 20 Oct 2014 15:26:12 +0200 Subject: ls: Add -Z (Smack) option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Option triggers printing security context, for smack that is file's access smack label. Change-Id: I9054d9bcfe4d149e8fbfa0831b6ab50165d2bd91 Signed-off-by: Jan Cybulski Signed-off-by: José Bollo --- toys/posix/ls.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/toys/posix/ls.c b/toys/posix/ls.c index 3c37c7e0..892e8267 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -5,7 +5,7 @@ * * See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html -USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"goACFHLRSacdfiklmnpqrstux1[-1Cglmnox][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE)) +USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"goACFHLR"USE_LS_SMACK("Z")"Sacdfiklmnpqrstux1[-1Cglmnox][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE)) config LS bool "ls" @@ -32,6 +32,15 @@ config LS sorting (default is alphabetical): -f unsorted -r reverse -t timestamp -S size +config LS_SMACK + bool + default y + depends on LS && TOYBOX_SMACK + help + usage: ls [-Z] + + -Z security context + config LS_COLOR bool "ls --color" default y @@ -158,6 +167,14 @@ static void entrylen(struct dirtree *dt, unsigned *len) } len[6] = (flags & FLAG_s) ? numlen(st->st_blocks) : 0; + + if (CFG_LS_SMACK && (flags & FLAG_Z)) { + char *zpath = dirtree_path(dt, 0); + ssize_t zlen = lgetxattr(zpath, XATTR_NAME_SMACK, 0, 0); + free(zpath); + len[7] = (zlen <= 0) || (zlen > SMACK_LABEL_LEN) ? 0 : (int)zlen; + } else + len[7] = 0; } static int compare(void *a, void *b) @@ -263,7 +280,7 @@ static void listfiles(int dirfd, struct dirtree *indir) { struct dirtree *dt, **sort = 0; unsigned long dtlen = 0, ul = 0; - unsigned width, flags = toys.optflags, totals[7], len[7], totpad = 0, + unsigned width, flags = toys.optflags, totals[8], len[8], totpad = 0, *colsizes = (unsigned *)(toybuf+260), columns = (sizeof(toybuf)-260)/4; memset(totals, 0, sizeof(totals)); @@ -313,7 +330,7 @@ static void listfiles(int dirfd, struct dirtree *indir) qsort(sort, dtlen, sizeof(void *), (void *)compare); for (ul = 0; ultotals[width]) totals[width] = len[width]; totpad = totals[1]+!!totals[1]+totals[6]+!!totals[6]; blocks += sort[ul]->st.st_blocks; @@ -410,6 +427,18 @@ static void listfiles(int dirfd, struct dirtree *indir) printf("%s% *ld %s%s%s%s", perm, totals[2]+1, (long)st->st_nlink, usr, upad, grp, grpad); + if (CFG_LS_SMACK) { + if (flags & FLAG_Z) { + char zbuf[SMACK_LABEL_LEN + 1]; + char *zpath = dirtree_path(sort[next], 0); + ssize_t zlen = getxattr(zpath, XATTR_NAME_SMACK, zbuf, sizeof(zbuf)); + free(zpath); + if ((zlen <= 0) || (zlen > SMACK_LABEL_LEN)) zbuf[0] = '?', zlen = 1; + zbuf[zlen] = '\0'; + xprintf(" %s%s", zbuf, toybuf+256-(totals[7]-(int)zlen)); + } + } + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) printf("% *d,% 4d", totals[5]-4, major(st->st_rdev),minor(st->st_rdev)); else printf("% *"PRId64, totals[5]+1, (int64_t)st->st_size); @@ -417,6 +446,16 @@ static void listfiles(int dirfd, struct dirtree *indir) tm = localtime(&(st->st_mtime)); strftime(thyme, sizeof(thyme), "%F %H:%M", tm); xprintf(" %s ", thyme); + } else if (CFG_LS_SMACK) { + if (flags & FLAG_Z) { + char zbuf[SMACK_LABEL_LEN + 1]; + char *zpath = dirtree_path(sort[next], 0); + ssize_t zlen = getxattr(zpath, XATTR_NAME_SMACK, zbuf, sizeof(zbuf)); + free(zpath); + if ((zlen <= 0) || (zlen > SMACK_LABEL_LEN)) zbuf[0] = '?', zlen = 1; + zbuf[zlen] = '\0'; + xprintf("%s%s ", toybuf+256-(totals[7]-(int)(zlen-1)), zbuf); + } } if (flags & FLAG_color) { -- cgit v1.2.3 From 9c3d1657f1a3561910ceb87c1ea21d349fbfaaed Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 30 Apr 2015 14:01:35 -0500 Subject: Remove redundant numlen. --- lib/lib.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/lib.c b/lib/lib.c index ab773b5b..2f7d28f4 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -280,16 +280,6 @@ long atolx_range(char *numstr, long low, long high) return val; } -int numlen(long l) -{ - int len = 0; - while (l) { - l /= 10; - len++; - } - return len; -} - int stridx(char *haystack, char needle) { char *off; -- cgit v1.2.3 From 491e3e3f1c654f689de0f8cbd3b05559fd65c568 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 30 Apr 2015 14:02:34 -0500 Subject: Wild guess at cleaning up smack support. Don't have a test environment yet. --- toys/posix/ls.c | 59 ++++++++++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/toys/posix/ls.c b/toys/posix/ls.c index 892e8267..f7cc52db 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -5,7 +5,7 @@ * * See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html -USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"goACFHLR"USE_LS_SMACK("Z")"Sacdfiklmnpqrstux1[-1Cglmnox][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE)) +USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")USE_LS_SMACK("Z")"goACFHLRSacdfiklmnpqrstux1[-1Cglmnox][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE)) config LS bool "ls" @@ -33,7 +33,7 @@ config LS -f unsorted -r reverse -t timestamp -S size config LS_SMACK - bool + bool default y depends on LS && TOYBOX_SMACK help @@ -142,6 +142,27 @@ static int numlen(long long ll) return snprintf(0, 0, "%llu", ll); } +// measure/print smack attributes +// lr = 0 just measure, 1 left justified, 2 right justified +static unsigned zmack(struct dirtree *dt, int pad, int lr) +{ + char buf[SMACK_LABEL_LEN+1]; + int fd = openat(dirtree_parentfd(dt), dt->name, O_PATH|O_NOFOLLOW); + ssize_t len = 1; + + strcpy(buf, "?"); + if (fd != -1) { + len = fgetxattr(fd, XATTR_NAME_SMACK, lr?buf:0, lr?SMACK_LABEL_LEN:0); + close(fd); + + if (len<1 || len>SMACK_LABEL_LEN) len = 0; + else buf[len] = 0; + } + if (lr) printf(" %*s "+(lr==2), pad*((2*(lr==1))-1), buf); + + return len; +} + // Figure out size of printable entry fields for display indent/wrap static void entrylen(struct dirtree *dt, unsigned *len) @@ -168,13 +189,7 @@ static void entrylen(struct dirtree *dt, unsigned *len) len[6] = (flags & FLAG_s) ? numlen(st->st_blocks) : 0; - if (CFG_LS_SMACK && (flags & FLAG_Z)) { - char *zpath = dirtree_path(dt, 0); - ssize_t zlen = lgetxattr(zpath, XATTR_NAME_SMACK, 0, 0); - free(zpath); - len[7] = (zlen <= 0) || (zlen > SMACK_LABEL_LEN) ? 0 : (int)zlen; - } else - len[7] = 0; + if (CFG_LS_SMACK && (flags & FLAG_Z)) len[7] = zmack(dt, 0, 0); } static int compare(void *a, void *b) @@ -332,7 +347,7 @@ static void listfiles(int dirfd, struct dirtree *indir) entrylen(sort[ul], len); for (width = 0; width<8; width++) if (len[width]>totals[width]) totals[width] = len[width]; - totpad = totals[1]+!!totals[1]+totals[6]+!!totals[6]; + totpad = totals[1]+!!totals[1]+totals[6]+!!totals[6]+totals[7]+!!totals[7]; blocks += sort[ul]->st.st_blocks; } if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s) && indir->parent) @@ -427,17 +442,7 @@ static void listfiles(int dirfd, struct dirtree *indir) printf("%s% *ld %s%s%s%s", perm, totals[2]+1, (long)st->st_nlink, usr, upad, grp, grpad); - if (CFG_LS_SMACK) { - if (flags & FLAG_Z) { - char zbuf[SMACK_LABEL_LEN + 1]; - char *zpath = dirtree_path(sort[next], 0); - ssize_t zlen = getxattr(zpath, XATTR_NAME_SMACK, zbuf, sizeof(zbuf)); - free(zpath); - if ((zlen <= 0) || (zlen > SMACK_LABEL_LEN)) zbuf[0] = '?', zlen = 1; - zbuf[zlen] = '\0'; - xprintf(" %s%s", zbuf, toybuf+256-(totals[7]-(int)zlen)); - } - } + if (CFG_LS_SMACK && (flags & FLAG_Z)) zmack(sort[next], totals[7], 1); if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) printf("% *d,% 4d", totals[5]-4, major(st->st_rdev),minor(st->st_rdev)); @@ -446,17 +451,7 @@ static void listfiles(int dirfd, struct dirtree *indir) tm = localtime(&(st->st_mtime)); strftime(thyme, sizeof(thyme), "%F %H:%M", tm); xprintf(" %s ", thyme); - } else if (CFG_LS_SMACK) { - if (flags & FLAG_Z) { - char zbuf[SMACK_LABEL_LEN + 1]; - char *zpath = dirtree_path(sort[next], 0); - ssize_t zlen = getxattr(zpath, XATTR_NAME_SMACK, zbuf, sizeof(zbuf)); - free(zpath); - if ((zlen <= 0) || (zlen > SMACK_LABEL_LEN)) zbuf[0] = '?', zlen = 1; - zbuf[zlen] = '\0'; - xprintf("%s%s ", toybuf+256-(totals[7]-(int)(zlen-1)), zbuf); - } - } + } else if (CFG_LS_SMACK && (flags & FLAG_Z)) zmack(sort[next], totals[7],2); if (flags & FLAG_color) { color = color_from_mode(st->st_mode); -- cgit v1.2.3 From cb7ed52786ffab798455c88fbd73bc32276bcfed Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 30 Apr 2015 14:18:47 -0500 Subject: And remove the header part too. --- lib/lib.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/lib.h b/lib/lib.h index bdd78c9a..dc5edd33 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -156,7 +156,6 @@ long estrtol(char *str, char **end, int base); long xstrtol(char *str, char **end, int base); long atolx(char *c); long atolx_range(char *numstr, long low, long high); -int numlen(long l); int stridx(char *haystack, char needle); int unescape(char c); int strstart(char **a, char *b); -- cgit v1.2.3 From e7c09548b9c6188857260064c8ceba03d850c4b7 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 30 Apr 2015 15:11:34 -0500 Subject: Add default sigpipe handler for android (as suggested by Elliott Hughes). --- main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/main.c b/main.c index 57022442..2fd22d4b 100644 --- a/main.c +++ b/main.c @@ -183,8 +183,17 @@ void toybox_main(void) xputc('\n'); } +static void shutup_sigpipe(int i) +{ + // exit success from sigpipe to mollify overzealous crash reporting. + _exit(0); +} + int main(int argc, char *argv[]) { + if (CFG_TOYBOX_ON_ANDROID) signal(SIGPIPE, shutup_sigpipe); + else signal(SIGPIPE, SIG_IGN); + if (CFG_TOYBOX) { // Trim path off of command name *argv = basename(*argv); -- cgit v1.2.3 From 5e18bae30a80d6149e47d9adb1acb3a64bac7c08 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 30 Apr 2015 16:51:50 -0500 Subject: More ls cleanups from squinting at Jose's most recent smack patch. Behavior change in flags: allow -long to work together, and -l1 work like -l not -1. I didn't make ls -gCl remember the g, though. (Because -Cg and -gC take the last one: I'll preserve explicit state but not implicit state. And if -1Cl and -lC1 aren't going to behave the same, it wasn't consistent anyway.) --- toys/posix/ls.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/toys/posix/ls.c b/toys/posix/ls.c index f7cc52db..9c4d6d3b 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -5,7 +5,7 @@ * * See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html -USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")USE_LS_SMACK("Z")"goACFHLRSacdfiklmnpqrstux1[-1Cglmnox][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE)) +USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")USE_LS_SMACK("Z")"goACFHLRSacdfiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE)) config LS bool "ls" @@ -142,9 +142,8 @@ static int numlen(long long ll) return snprintf(0, 0, "%llu", ll); } -// measure/print smack attributes -// lr = 0 just measure, 1 left justified, 2 right justified -static unsigned zmack(struct dirtree *dt, int pad, int lr) +// measure/print smack attributes. (If pad=0, just measure.) +static unsigned zmack(struct dirtree *dt, int pad) { char buf[SMACK_LABEL_LEN+1]; int fd = openat(dirtree_parentfd(dt), dt->name, O_PATH|O_NOFOLLOW); @@ -152,13 +151,13 @@ static unsigned zmack(struct dirtree *dt, int pad, int lr) strcpy(buf, "?"); if (fd != -1) { - len = fgetxattr(fd, XATTR_NAME_SMACK, lr?buf:0, lr?SMACK_LABEL_LEN:0); + len = fgetxattr(fd, XATTR_NAME_SMACK, pad?buf:0, pad?SMACK_LABEL_LEN:0); close(fd); if (len<1 || len>SMACK_LABEL_LEN) len = 0; else buf[len] = 0; } - if (lr) printf(" %*s "+(lr==2), pad*((2*(lr==1))-1), buf); + if (pad) printf(" %*s "+(pad>0), pad, buf); return len; } @@ -189,7 +188,7 @@ static void entrylen(struct dirtree *dt, unsigned *len) len[6] = (flags & FLAG_s) ? numlen(st->st_blocks) : 0; - if (CFG_LS_SMACK && (flags & FLAG_Z)) len[7] = zmack(dt, 0, 0); + if (CFG_LS_SMACK && (flags & FLAG_Z)) len[7] = zmack(dt, 0); } static int compare(void *a, void *b) @@ -293,8 +292,8 @@ int color_from_mode(mode_t mode) static void listfiles(int dirfd, struct dirtree *indir) { - struct dirtree *dt, **sort = 0; - unsigned long dtlen = 0, ul = 0; + struct dirtree *dt, **sort; + unsigned long dtlen, ul = 0; unsigned width, flags = toys.optflags, totals[8], len[8], totpad = 0, *colsizes = (unsigned *)(toybuf+260), columns = (sizeof(toybuf)-260)/4; @@ -316,17 +315,12 @@ static void listfiles(int dirfd, struct dirtree *indir) } // Copy linked list to array and sort it. Directories go in array because - // we visit them in sorted order. - - for (;;) { - for (dt = indir->child; dt; dt = dt->next) { + // we visit them in sorted order too. (The nested loops let us measure and + // fill with the same inner loop.) + for (sort = 0;;sort = xmalloc(dtlen * sizeof(void *))) { + for (dtlen = 0, dt = indir->child; dt; dt = dt->next, dtlen++) if (sort) sort[dtlen] = dt; - dtlen++; - } if (sort) break; - sort = xmalloc(dtlen * sizeof(void *)); - dtlen = 0; - continue; } // Label directory if not top of tree, or if -R @@ -339,6 +333,7 @@ static void listfiles(int dirfd, struct dirtree *indir) free(path); } + // Measure each entry to work out whitespace padding and total blocks if (!(flags & FLAG_f)) { unsigned long long blocks = 0; @@ -347,9 +342,9 @@ static void listfiles(int dirfd, struct dirtree *indir) entrylen(sort[ul], len); for (width = 0; width<8; width++) if (len[width]>totals[width]) totals[width] = len[width]; - totpad = totals[1]+!!totals[1]+totals[6]+!!totals[6]+totals[7]+!!totals[7]; blocks += sort[ul]->st.st_blocks; } + totpad = totals[1]+!!totals[1]+totals[6]+!!totals[6]+totals[7]+!!totals[7]; if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s) && indir->parent) xprintf("total %llu\n", blocks); } @@ -442,16 +437,16 @@ static void listfiles(int dirfd, struct dirtree *indir) printf("%s% *ld %s%s%s%s", perm, totals[2]+1, (long)st->st_nlink, usr, upad, grp, grpad); - if (CFG_LS_SMACK && (flags & FLAG_Z)) zmack(sort[next], totals[7], 1); + if (CFG_LS_SMACK && (flags & FLAG_Z)) zmack(sort[next], -(int)totals[7]); if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) printf("% *d,% 4d", totals[5]-4, major(st->st_rdev),minor(st->st_rdev)); - else printf("% *"PRId64, totals[5]+1, (int64_t)st->st_size); + else printf("% *lld", totals[5]+1, (long long)st->st_size); tm = localtime(&(st->st_mtime)); strftime(thyme, sizeof(thyme), "%F %H:%M", tm); xprintf(" %s ", thyme); - } else if (CFG_LS_SMACK && (flags & FLAG_Z)) zmack(sort[next], totals[7],2); + } else if (CFG_LS_SMACK && (flags & FLAG_Z)) zmack(sort[next], totals[7]); if (flags & FLAG_color) { color = color_from_mode(st->st_mode); -- cgit v1.2.3 From 06d378325b9e7b6fd06fe45b284e189ac440345b Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 1 May 2015 14:40:49 -0500 Subject: Portability bits for the recent ls smack changes. --- lib/portability.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/portability.h b/lib/portability.h index 740a4ee5..b25048fe 100644 --- a/lib/portability.h +++ b/lib/portability.h @@ -226,6 +226,10 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream); #define O_CLOEXEC 02000000 #endif +#ifndef O_PATH +#define O_PATH 010000000 +#endif + #if defined(__SIZEOF_DOUBLE__) && defined(__SIZEOF_LONG__) \ && __SIZEOF_DOUBLE__ <= __SIZEOF_LONG__ typedef double FLOAT; @@ -257,5 +261,7 @@ int getcon(void* con); #define smack_set_label_for_self(...) (-1) #define XATTR_NAME_SMACK "" #define SMACK_LABEL_LEN (1) /* for just ? */ + +ssize_t fgetxattr (int fd, char *name, void *value, size_t size); #endif -- cgit v1.2.3 From 38a5493031bca46263038964a8f5b188d7e9304e Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Sat, 2 May 2015 17:41:27 -0500 Subject: dmesg: add -t suppress timestamp flag --- toys/lsb/dmesg.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/toys/lsb/dmesg.c b/toys/lsb/dmesg.c index c8876757..50da8a8a 100644 --- a/toys/lsb/dmesg.c +++ b/toys/lsb/dmesg.c @@ -5,13 +5,13 @@ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html // We care that FLAG_c is 1, so keep c at the end. -USE_DMESG(NEWTOY(dmesg, "rs#<1n#c", TOYFLAG_BIN)) +USE_DMESG(NEWTOY(dmesg, "trs#<1n#c", TOYFLAG_BIN)) config DMESG bool "dmesg" default y help - usage: dmesg [-n LEVEL] [-s SIZE] | -c + usage: dmesg [-n LEVEL] [-s SIZE] [-r|-t] | -c Print or control the kernel ring buffer. @@ -19,6 +19,7 @@ config DMESG -n Set kernel logging LEVEL (1-9) -r Raw output (with ) -s Show the last SIZE many bytes + -t Don't print kernel's timestamps */ #define FOR_dmesg @@ -32,6 +33,9 @@ GLOBALS( void dmesg_main(void) { + if ((toys.optflags & FLAG_r) && (toys.optflags & FLAG_t)) { + error_exit("dmesg: -r and -t are mutually exclusive options"); + } // For -n just tell kernel to which messages to keep. if (toys.optflags & FLAG_n) { if (klogctl(8, NULL, TT.level)) perror_exit("klogctl"); @@ -47,12 +51,20 @@ void dmesg_main(void) if (size < 0) error_exit("klogctl"); data[size] = 0; - // Filter out level markers. + // Filter out level markers and optionally time markers if (!(toys.optflags & FLAG_r)) while ((from - data) < size) { - if ((from == data || from[-1] == '\n') && *from == '<') { - int i = stridx(from, '>'); + if (from == data || from[-1] == '\n') { + if (*from == '<') { + int i = stridx(from, '>'); + + if (i>0) from += i+1; + } + if ((*from == '[') && (toys.optflags & FLAG_t)) { + int i = stridx(from, ']'); - if (i>0) from += i+1; + if (i>0) from += i+1; + if (*from == ' ') ++from; + } } *(to++) = *(from++); } else to = data+size; -- cgit v1.2.3 From 5640acb50da707b404e00e9a20ba3fb3ec334a91 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 3 May 2015 12:41:05 -0500 Subject: If a shortopt is configured out right before a bare longopt, the option parsing infrastructure segfaults because there's no next shortopt but the list isn't empty. (There was a test for this, but we're simultaneously traversing two lists and it was testing the wrong one.) --- scripts/mkflags.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/mkflags.c b/scripts/mkflags.c index 228cd2f8..d87087bc 100644 --- a/scripts/mkflags.c +++ b/scripts/mkflags.c @@ -122,10 +122,14 @@ int main(int argc, char *argv[]) char *gaps, *mgaps, c; unsigned bit; - *command = 0; + *command = *flags = *allflags = 0; bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n", command, flags, allflags); + if (getenv("DEBUG")) + fprintf(stderr, "command=%s, flags=%s, allflags=%s\n", + command, flags, allflags); + if (!*command) break; if (bit != 3) { fprintf(stderr, "\nError in %s (duplicate command?)\n", command); @@ -182,8 +186,7 @@ int main(int argc, char *argv[]) if (flist) flist = flist->next; } } else if (aflist->command) { - if (flist && (!aflist->command || *aflist->command == *flist->command)) - { + if (flist && (!flist->command || *aflist->command == *flist->command)) { if (aflist->command) sprintf(out, "#define FLAG_%c (1<<%d)\n", *aflist->command, bit); flist = flist->next; -- cgit v1.2.3 From fcd2729305888d0d8e4af2e6d158b9bbb97541af Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 3 May 2015 15:13:41 -0500 Subject: Minor dmesg cleanup. --- toys/lsb/dmesg.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/toys/lsb/dmesg.c b/toys/lsb/dmesg.c index 50da8a8a..aac638d0 100644 --- a/toys/lsb/dmesg.c +++ b/toys/lsb/dmesg.c @@ -5,13 +5,13 @@ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html // We care that FLAG_c is 1, so keep c at the end. -USE_DMESG(NEWTOY(dmesg, "trs#<1n#c", TOYFLAG_BIN)) +USE_DMESG(NEWTOY(dmesg, "trs#<1n#c[!tr]", TOYFLAG_BIN)) config DMESG bool "dmesg" default y help - usage: dmesg [-n LEVEL] [-s SIZE] [-r|-t] | -c + usage: dmesg [-c] [-r|-t] [-n LEVEL] [-s SIZE] Print or control the kernel ring buffer. @@ -33,9 +33,6 @@ GLOBALS( void dmesg_main(void) { - if ((toys.optflags & FLAG_r) && (toys.optflags & FLAG_t)) { - error_exit("dmesg: -r and -t are mutually exclusive options"); - } // For -n just tell kernel to which messages to keep. if (toys.optflags & FLAG_n) { if (klogctl(8, NULL, TT.level)) perror_exit("klogctl"); @@ -54,17 +51,11 @@ void dmesg_main(void) // Filter out level markers and optionally time markers if (!(toys.optflags & FLAG_r)) while ((from - data) < size) { if (from == data || from[-1] == '\n') { - if (*from == '<') { - int i = stridx(from, '>'); - - if (i>0) from += i+1; - } - if ((*from == '[') && (toys.optflags & FLAG_t)) { - int i = stridx(from, ']'); + char *to; - if (i>0) from += i+1; - if (*from == ' ') ++from; - } + if (*from == '<' && (to = strchr(from, '>'))) from = ++to; + if ((toys.optflags&FLAG_t) && *from == '[' && (to = strchr(from, ']'))) + from = to+1+(to[1]==' '); } *(to++) = *(from++); } else to = data+size; -- cgit v1.2.3 From 2a7727dec265fa96e8522b0a557b72320d2889a7 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Sun, 3 May 2015 15:31:41 -0500 Subject: Fix getprop sorting and error reporting. Use qstrcmp instead of alphasort (which expects struct dirent arguments). Don't use perror_exit because property_list doesn't set errno. --- toys/android/getprop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toys/android/getprop.c b/toys/android/getprop.c index 400d80e7..09bb0f0b 100644 --- a/toys/android/getprop.c +++ b/toys/android/getprop.c @@ -40,8 +40,8 @@ void getprop_main(void) } else { size_t i; - if (property_list((void *)add_property, 0)) perror_exit("property_list"); - qsort(TT.nv, TT.size, 2*sizeof(char *), alphasort); + if (property_list((void *)add_property, 0)) error_exit("property_list"); + qsort(TT.nv, TT.size, 2*sizeof(char *), qstrcmp); for (i = 0; i Date: Sun, 3 May 2015 15:53:37 -0500 Subject: dhcpd writes leases on "dhcpd.leases" file. but, dumpleases read from "udhcpd.leases". --- toys/pending/dumpleases.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toys/pending/dumpleases.c b/toys/pending/dumpleases.c index fec39559..86cb4e76 100644 --- a/toys/pending/dumpleases.c +++ b/toys/pending/dumpleases.c @@ -41,7 +41,7 @@ void dumpleases_main(void) int64_t written_time , current_time, exp; int i, fd; - if(!(toys.optflags & FLAG_f)) TT.file = "/var/lib/misc/udhcpd.leases"; //DEF_LEASE_FILE + if(!(toys.optflags & FLAG_f)) TT.file = "/var/lib/misc/dhcpd.leases"; //DEF_LEASE_FILE fd = xopen(TT.file, O_RDONLY); xprintf("Mac Address IP Address Host Name Expires %s\n", (toys.optflags & FLAG_a) ? "at" : "in"); xread(fd, &written_time, sizeof(written_time)); -- cgit v1.2.3 From 9398f05d34453e9306f7a91993ee4c8fcf1102ec Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 3 May 2015 16:20:27 -0500 Subject: Move a prototype to the start of portability.h (suggested by Elliott Hughes) --- lib/portability.h | 3 +++ toys.h | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/portability.h b/lib/portability.h index b25048fe..7bab646d 100644 --- a/lib/portability.h +++ b/lib/portability.h @@ -28,6 +28,9 @@ #include +// Types various replacement prototypes need +#include + // Various constants old build environments might not have even if kernel does #ifndef AT_FDCWD diff --git a/toys.h b/toys.h index aa4381c5..4b2d3736 100644 --- a/toys.h +++ b/toys.h @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3