From b5fc51198bf451885e6411bae9b25890a5b6fbe2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 7 Feb 2013 16:06:54 +0100 Subject: vasprintf: do not use xmalloc, it will deadlock on OOM Signed-off-by: Denys Vlasenko --- libbb/platform.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libbb/platform.c b/libbb/platform.c index 2bf34f5bc..d241d25a7 100644 --- a/libbb/platform.c +++ b/libbb/platform.c @@ -28,14 +28,16 @@ int FAST_FUNC vasprintf(char **string_ptr, const char *format, va_list p) r = vsnprintf(buf, 128, format, p); va_end(p); + /* Note: can't use xstrdup/xmalloc, they call vasprintf (us) on failure! */ + if (r < 128) { va_end(p2); - *string_ptr = xstrdup(buf); + *string_ptr = strdup(buf); return r; } - *string_ptr = xmalloc(r+1); - r = vsnprintf(*string_ptr, r+1, format, p2); + *string_ptr = malloc(r+1); + r = (*string_ptr ? vsnprintf(*string_ptr, r+1, format, p2) : -1); va_end(p2); return r; -- cgit v1.2.3-55-g6feb From 272d85cc8554299502d802b3db7317a7381e8bd7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 10 Feb 2013 23:03:38 +0100 Subject: vasprintf: return -1 on strdup failure Signed-off-by: Denys Vlasenko --- libbb/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/platform.c b/libbb/platform.c index d241d25a7..19734517b 100644 --- a/libbb/platform.c +++ b/libbb/platform.c @@ -33,7 +33,7 @@ int FAST_FUNC vasprintf(char **string_ptr, const char *format, va_list p) if (r < 128) { va_end(p2); *string_ptr = strdup(buf); - return r; + return (*string_ptr ? r : -1); } *string_ptr = malloc(r+1); -- cgit v1.2.3-55-g6feb From 1bd5ca2f530f11e27a1ae13bba592d9f725ce341 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sat, 9 Feb 2013 21:12:25 +0200 Subject: fdisk_sun: fix corrupted partition data with blank disk After creating Sun disk label for the first time for a blank disk, the partition table appears corrupted because current_label_type will never get set to a proper type. Fix this by calling check_sun_label() after BusyBox has created the label. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- util-linux/fdisk_sun.c | 1 + 1 file changed, 1 insertion(+) diff --git a/util-linux/fdisk_sun.c b/util-linux/fdisk_sun.c index e7fcc067c..d11c54012 100644 --- a/util-linux/fdisk_sun.c +++ b/util-linux/fdisk_sun.c @@ -348,6 +348,7 @@ create_sunlabel(void) set_all_unchanged(); set_changed(0); + check_sun_label(); get_boot(CREATE_EMPTY_SUN); } -- cgit v1.2.3-55-g6feb From cf5731bcbd3b65c5efb9a8b24ed6b95a0a239e67 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sat, 9 Feb 2013 21:12:26 +0200 Subject: fdisk_sun: fix partition alignment When the display unit is sectors, the partition alignment will convert the partition start to a wrong unit (it should always be in sectors). Fix this. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- util-linux/fdisk_sun.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/util-linux/fdisk_sun.c b/util-linux/fdisk_sun.c index d11c54012..e32740dea 100644 --- a/util-linux/fdisk_sun.c +++ b/util-linux/fdisk_sun.c @@ -498,11 +498,14 @@ add_sun_partition(int n, int sys) else first = read_int(scround(start), scround(stop)+1, scround(stop), 0, mesg); - if (display_in_cyl_units) + if (display_in_cyl_units) { first *= units_per_sector; - else + } else { /* Starting sector has to be properly aligned */ - first = (first + g_heads * g_sectors - 1) / (g_heads * g_sectors); + first = (first + g_heads * g_sectors - 1) / + (g_heads * g_sectors); + first *= g_heads * g_sectors; + } if (n == 2 && first != 0) printf("\ It is highly recommended that the third partition covers the whole disk\n\ -- cgit v1.2.3-55-g6feb From 10f5f9b10d5bb18aa612e8f340d8454421015b00 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 20 Feb 2013 15:57:39 +0100 Subject: rpm: make -ql display more compatible; improve help text Signed-off-by: Denys Vlasenko --- archival/rpm.c | 68 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/archival/rpm.c b/archival/rpm.c index 6757a6ceb..793701652 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -14,10 +14,10 @@ //usage: "\nCommands:" //usage: "\n -i Install package" //usage: "\n -qp Query package" -//usage: "\n -i Show information" -//usage: "\n -l List contents" -//usage: "\n -d List documents" -//usage: "\n -c List config files" +//usage: "\n -qpi Show information" +//usage: "\n -qpl List contents" +//usage: "\n -qpd List documents" +//usage: "\n -qpc List config files" #include "libbb.h" #include "bb_archive.h" @@ -96,8 +96,8 @@ static void loop_through_files(int filetag, void (*fileaction)(char *filename, i int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rpm_main(int argc, char **argv) { - int opt = 0, func = 0, rpm_fd, offset; - const int pagesize = getpagesize(); + int opt, func = 0; + const unsigned pagesize = getpagesize(); while ((opt = getopt(argc, argv, "iqpldc")) != -1) { switch (opt) { @@ -134,6 +134,8 @@ int rpm_main(int argc, char **argv) } while (*argv) { + int rpm_fd; + unsigned offset; const char *source_rpm; rpm_fd = xopen(*argv++, O_RDONLY); @@ -141,8 +143,8 @@ int rpm_main(int argc, char **argv) if (!mytags) bb_error_msg_and_die("error reading rpm header"); offset = xlseek(rpm_fd, 0, SEEK_CUR); - /* Mimimum is one page */ - map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); + /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ + map = mmap(0, (offset + pagesize) & (-(int)pagesize), PROT_READ, MAP_PRIVATE, rpm_fd, 0); source_rpm = rpm_getstr(TAG_SOURCERPM, 0); @@ -166,21 +168,29 @@ int rpm_main(int argc, char **argv) char bdatestring[50]; const char *p; - p = rpm_getstr(TAG_PREFIXS, 0); - if (!p) p = "(not relocateable)"; - printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p); - p = rpm_getstr(TAG_VENDOR, 0); - if (!p) p = "(none)"; - printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p); + printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0)); + /* TODO compat: add "Epoch" here */ + printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0)); + printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0)); + /* add "Architecture" */ + printf("%-12s: %s\n", "Install Date", "(not installed)"); + printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0)); + printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); + printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0)); + /* add "Signature" */ + printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); bdate_time = rpm_getint(TAG_BUILDTIME, 0); bdate_ptm = localtime(&bdate_time); strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); - printf("Release : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring); - printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0)); - printf("Group : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), source_rpm); - printf("Size : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0)); - printf("URL : %s\n", rpm_getstr(TAG_URL, 0)); - printf("Summary : %s\n", rpm_getstr(TAG_SUMMARY, 0)); + printf("%-12s: %s\n", "Build Date" , bdatestring); + printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0)); + p = rpm_getstr(TAG_PREFIXS, 0); + printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); + /* add "Packager" */ + p = rpm_getstr(TAG_VENDOR, 0); + printf("%-12s: %s\n", "Vendor" , p ? p : "(none)"); + printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0)); + printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0)); printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); } if (func & rpm_query_list) { @@ -206,6 +216,7 @@ int rpm_main(int argc, char **argv) } } free(mytags); + close(rpm_fd); } return 0; } @@ -322,7 +333,7 @@ static char *rpm_getstr(int tag, int itemindex) static int rpm_getint(int tag, int itemindex) { rpm_index **found; - int *tmpint; /* NB: using int8_t* would be easier to code */ + char *tmpint; /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... * it's ok to ignore it because tag won't be used as a pointer */ @@ -330,24 +341,17 @@ static int rpm_getint(int tag, int itemindex) if (!found || itemindex >= found[0]->count) return -1; - tmpint = (int *) ((char *) map + found[0]->offset); - + tmpint = (char *) map + found[0]->offset; if (found[0]->type == RPM_INT32_TYPE) { - tmpint = (int *) ((char *) tmpint + itemindex*4); - /*return ntohl(*tmpint);*/ - /* int can be != int32_t */ + tmpint += itemindex*4; return ntohl(*(int32_t*)tmpint); } if (found[0]->type == RPM_INT16_TYPE) { - tmpint = (int *) ((char *) tmpint + itemindex*2); - /* ??? read int, and THEN ntohs() it?? */ - /*return ntohs(*tmpint);*/ + tmpint += itemindex*2; return ntohs(*(int16_t*)tmpint); } if (found[0]->type == RPM_INT8_TYPE) { - tmpint = (int *) ((char *) tmpint + itemindex); - /* ??? why we don't read byte here??? */ - /*return ntohs(*tmpint);*/ + tmpint += itemindex; return *(int8_t*)tmpint; } return -1; -- cgit v1.2.3-55-g6feb From 2aec773688fd64857e9446838187170760acddd4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 20 Feb 2013 15:58:42 +0100 Subject: rpm: use "create+rename" method of replacing existing files Users were reporting getting errors like "ls: error while loading shared libraries: libc.so.6: ELF load command past end of file" while rpm was unpacking glibc tarball. Signed-off-by: Denys Vlasenko --- archival/libarchive/data_extract_all.c | 15 ++++++++++++++- archival/rpm.c | 4 ++-- include/bb_archive.h | 3 +++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index 3f67b835f..45776dcbe 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c @@ -106,15 +106,28 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ + char *dst_name; int flags = O_WRONLY | O_CREAT | O_EXCL; if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) flags = O_WRONLY | O_CREAT | O_TRUNC; - dst_fd = xopen3(file_header->name, + dst_name = file_header->name; +#ifdef ARCHIVE_REPLACE_VIA_RENAME + if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) + /* rpm-style temp file name */ + dst_name = xasprintf("%s;%x", dst_name, (int)getpid()); +#endif + dst_fd = xopen3(dst_name, flags, file_header->mode ); bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); close(dst_fd); +#ifdef ARCHIVE_REPLACE_VIA_RENAME + if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { + xrename(dst_name, file_header->name); + free(dst_name); + } +#endif break; } case S_IFDIR: diff --git a/archival/rpm.c b/archival/rpm.c index 793701652..6b227d537 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -242,8 +242,8 @@ static void extract_cpio(int fd, const char *source_rpm) /* compat: overwrite existing files. * try "rpm -i foo.src.rpm" few times in a row - * standard rpm will not complain. - * (TODO? real rpm creates "file;1234" and then renames it) */ - | ARCHIVE_UNLINK_OLD; + */ + | ARCHIVE_REPLACE_VIA_RENAME; archive_handle->src_fd = fd; /*archive_handle->offset = 0; - init_handle() did it */ diff --git a/include/bb_archive.h b/include/bb_archive.h index a7a2a1135..b82cfd83c 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -122,6 +122,9 @@ typedef struct archive_handle_t { #define ARCHIVE_NUMERIC_OWNER (1 << 7) #define ARCHIVE_O_TRUNC (1 << 8) #define ARCHIVE_REMEMBER_NAMES (1 << 9) +#if ENABLE_RPM +#define ARCHIVE_REPLACE_VIA_RENAME (1 << 10) +#endif /* POSIX tar Header Block, from POSIX 1003.1-1990 */ -- cgit v1.2.3-55-g6feb From d4d4f3528e0f7cb489ac05e57cc0d13b4c52e436 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 20 Feb 2013 16:01:10 +0100 Subject: rpm: stop using statics; move main() to the end of the source file Signed-off-by: Denys Vlasenko --- archival/rpm.c | 287 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 141 insertions(+), 146 deletions(-) diff --git a/archival/rpm.c b/archival/rpm.c index 6b227d537..b506f1779 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -79,147 +79,13 @@ typedef struct { uint32_t count; /* 4 byte count */ } rpm_index; -static void *map; -static rpm_index **mytags; -static int tagcount; - -static void extract_cpio(int fd, const char *source_rpm); -static rpm_index **rpm_gettags(int fd, int *num_tags); -static int bsearch_rpmtag(const void *key, const void *item); -static char *rpm_getstr(int tag, int itemindex); -static int rpm_getint(int tag, int itemindex); -static int rpm_getcount(int tag); -static void fileaction_dobackup(char *filename, int fileref); -static void fileaction_setowngrp(char *filename, int fileref); -static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref)); - -int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int rpm_main(int argc, char **argv) -{ - int opt, func = 0; - const unsigned pagesize = getpagesize(); - - while ((opt = getopt(argc, argv, "iqpldc")) != -1) { - switch (opt) { - case 'i': /* First arg: Install mode, with q: Information */ - if (!func) func = rpm_install; - else func |= rpm_query_info; - break; - case 'q': /* First arg: Query mode */ - if (func) bb_show_usage(); - func = rpm_query; - break; - case 'p': /* Query a package */ - func |= rpm_query_package; - break; - case 'l': /* List files in a package */ - func |= rpm_query_list; - break; - case 'd': /* List doc files in a package (implies list) */ - func |= rpm_query_list; - func |= rpm_query_list_doc; - break; - case 'c': /* List config files in a package (implies list) */ - func |= rpm_query_list; - func |= rpm_query_list_config; - break; - default: - bb_show_usage(); - } - } - argv += optind; - //argc -= optind; - if (!argv[0]) { - bb_show_usage(); - } - - while (*argv) { - int rpm_fd; - unsigned offset; - const char *source_rpm; - - rpm_fd = xopen(*argv++, O_RDONLY); - mytags = rpm_gettags(rpm_fd, &tagcount); - if (!mytags) - bb_error_msg_and_die("error reading rpm header"); - offset = xlseek(rpm_fd, 0, SEEK_CUR); - /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ - map = mmap(0, (offset + pagesize) & (-(int)pagesize), PROT_READ, MAP_PRIVATE, rpm_fd, 0); - - source_rpm = rpm_getstr(TAG_SOURCERPM, 0); - - if (func & rpm_install) { - /* Backup any config files */ - loop_through_files(TAG_BASENAMES, fileaction_dobackup); - /* Extact the archive */ - extract_cpio(rpm_fd, source_rpm); - /* Set the correct file uid/gid's */ - loop_through_files(TAG_BASENAMES, fileaction_setowngrp); - } - else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { - if (!(func & (rpm_query_info|rpm_query_list))) { - /* If just a straight query, just give package name */ - printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); - } - if (func & rpm_query_info) { - /* Do the nice printout */ - time_t bdate_time; - struct tm *bdate_ptm; - char bdatestring[50]; - const char *p; - - printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0)); - /* TODO compat: add "Epoch" here */ - printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0)); - printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0)); - /* add "Architecture" */ - printf("%-12s: %s\n", "Install Date", "(not installed)"); - printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0)); - printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); - printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0)); - /* add "Signature" */ - printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); - bdate_time = rpm_getint(TAG_BUILDTIME, 0); - bdate_ptm = localtime(&bdate_time); - strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); - printf("%-12s: %s\n", "Build Date" , bdatestring); - printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0)); - p = rpm_getstr(TAG_PREFIXS, 0); - printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); - /* add "Packager" */ - p = rpm_getstr(TAG_VENDOR, 0); - printf("%-12s: %s\n", "Vendor" , p ? p : "(none)"); - printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0)); - printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0)); - printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); - } - if (func & rpm_query_list) { - int count, it, flags; - count = rpm_getcount(TAG_BASENAMES); - for (it = 0; it < count; it++) { - flags = rpm_getint(TAG_FILEFLAGS, it); - switch (func & (rpm_query_list_doc|rpm_query_list_config)) { - case rpm_query_list_doc: - if (!(flags & RPMFILE_DOC)) continue; - break; - case rpm_query_list_config: - if (!(flags & RPMFILE_CONFIG)) continue; - break; - case rpm_query_list_doc|rpm_query_list_config: - if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue; - break; - } - printf("%s%s\n", - rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)), - rpm_getstr(TAG_BASENAMES, it)); - } - } - } - free(mytags); - close(rpm_fd); - } - return 0; -} +struct globals { + void *map; + rpm_index **mytags; + int tagcount; +} FIX_ALIASING; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) static void extract_cpio(int fd, const char *source_rpm) { @@ -305,7 +171,7 @@ static int bsearch_rpmtag(const void *key, const void *item) static int rpm_getcount(int tag) { rpm_index **found; - found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found) return 0; return found[0]->count; @@ -314,7 +180,7 @@ static int rpm_getcount(int tag) static char *rpm_getstr(int tag, int itemindex) { rpm_index **found; - found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found || itemindex >= found[0]->count) return NULL; if (found[0]->type == RPM_STRING_TYPE @@ -322,7 +188,7 @@ static char *rpm_getstr(int tag, int itemindex) || found[0]->type == RPM_STRING_ARRAY_TYPE ) { int n; - char *tmpstr = (char *) map + found[0]->offset; + char *tmpstr = (char *) G.map + found[0]->offset; for (n = 0; n < itemindex; n++) tmpstr = tmpstr + strlen(tmpstr) + 1; return tmpstr; @@ -337,11 +203,11 @@ static int rpm_getint(int tag, int itemindex) /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... * it's ok to ignore it because tag won't be used as a pointer */ - found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found || itemindex >= found[0]->count) return -1; - tmpint = (char *) map + found[0]->offset; + tmpint = (char *) G.map + found[0]->offset; if (found[0]->type == RPM_INT32_TYPE) { tmpint += itemindex*4; return ntohl(*(int32_t*)tmpint); @@ -396,3 +262,132 @@ static void loop_through_files(int filetag, void (*fileaction)(char *filename, i free(filename); } } + +int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rpm_main(int argc, char **argv) +{ + int opt, func = 0; + const unsigned pagesize = getpagesize(); + + while ((opt = getopt(argc, argv, "iqpldc")) != -1) { + switch (opt) { + case 'i': /* First arg: Install mode, with q: Information */ + if (!func) func = rpm_install; + else func |= rpm_query_info; + break; + case 'q': /* First arg: Query mode */ + if (func) bb_show_usage(); + func = rpm_query; + break; + case 'p': /* Query a package */ + func |= rpm_query_package; + break; + case 'l': /* List files in a package */ + func |= rpm_query_list; + break; + case 'd': /* List doc files in a package (implies list) */ + func |= rpm_query_list; + func |= rpm_query_list_doc; + break; + case 'c': /* List config files in a package (implies list) */ + func |= rpm_query_list; + func |= rpm_query_list_config; + break; + default: + bb_show_usage(); + } + } + argv += optind; + //argc -= optind; + if (!argv[0]) { + bb_show_usage(); + } + + while (*argv) { + int rpm_fd; + unsigned offset; + const char *source_rpm; + + rpm_fd = xopen(*argv++, O_RDONLY); + G.mytags = rpm_gettags(rpm_fd, &G.tagcount); + if (!G.mytags) + bb_error_msg_and_die("error reading rpm header"); + offset = xlseek(rpm_fd, 0, SEEK_CUR); + /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ + G.map = mmap(0, (offset + pagesize) & (-(int)pagesize), PROT_READ, MAP_PRIVATE, rpm_fd, 0); +//FIXME: error check? + + source_rpm = rpm_getstr(TAG_SOURCERPM, 0); + + if (func & rpm_install) { + /* Backup any config files */ + loop_through_files(TAG_BASENAMES, fileaction_dobackup); + /* Extact the archive */ + extract_cpio(rpm_fd, source_rpm); + /* Set the correct file uid/gid's */ + loop_through_files(TAG_BASENAMES, fileaction_setowngrp); + } + else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { + if (!(func & (rpm_query_info|rpm_query_list))) { + /* If just a straight query, just give package name */ + printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); + } + if (func & rpm_query_info) { + /* Do the nice printout */ + time_t bdate_time; + struct tm *bdate_ptm; + char bdatestring[50]; + const char *p; + + printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0)); + /* TODO compat: add "Epoch" here */ + printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0)); + printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0)); + /* add "Architecture" */ + printf("%-12s: %s\n", "Install Date", "(not installed)"); + printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0)); + printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); + printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0)); + /* add "Signature" */ + printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); + bdate_time = rpm_getint(TAG_BUILDTIME, 0); + bdate_ptm = localtime(&bdate_time); + strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); + printf("%-12s: %s\n", "Build Date" , bdatestring); + printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0)); + p = rpm_getstr(TAG_PREFIXS, 0); + printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); + /* add "Packager" */ + p = rpm_getstr(TAG_VENDOR, 0); + printf("%-12s: %s\n", "Vendor" , p ? p : "(none)"); + printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0)); + printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0)); + printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); + } + if (func & rpm_query_list) { + int count, it, flags; + count = rpm_getcount(TAG_BASENAMES); + for (it = 0; it < count; it++) { + flags = rpm_getint(TAG_FILEFLAGS, it); + switch (func & (rpm_query_list_doc|rpm_query_list_config)) { + case rpm_query_list_doc: + if (!(flags & RPMFILE_DOC)) continue; + break; + case rpm_query_list_config: + if (!(flags & RPMFILE_CONFIG)) continue; + break; + case rpm_query_list_doc|rpm_query_list_config: + if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue; + break; + } + printf("%s%s\n", + rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)), + rpm_getstr(TAG_BASENAMES, it)); + } + } + } + free(G.mytags); + close(rpm_fd); + } + return 0; +} -- cgit v1.2.3-55-g6feb From 8e6a1ea8250137d1dd9b0a37b7a1d6d596a91099 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 20 Feb 2013 16:01:48 +0100 Subject: rpm: unmap rpm file before working with next one Signed-off-by: Denys Vlasenko --- archival/rpm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/archival/rpm.c b/archival/rpm.c index b506f1779..86ba4dca4 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -305,16 +305,17 @@ int rpm_main(int argc, char **argv) while (*argv) { int rpm_fd; - unsigned offset; + unsigned mapsize; const char *source_rpm; rpm_fd = xopen(*argv++, O_RDONLY); G.mytags = rpm_gettags(rpm_fd, &G.tagcount); if (!G.mytags) bb_error_msg_and_die("error reading rpm header"); - offset = xlseek(rpm_fd, 0, SEEK_CUR); + mapsize = xlseek(rpm_fd, 0, SEEK_CUR); + mapsize = (mapsize + pagesize) & -(int)pagesize; /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ - G.map = mmap(0, (offset + pagesize) & (-(int)pagesize), PROT_READ, MAP_PRIVATE, rpm_fd, 0); + G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); //FIXME: error check? source_rpm = rpm_getstr(TAG_SOURCERPM, 0); @@ -386,6 +387,7 @@ int rpm_main(int argc, char **argv) } } } + munmap(G.map, mapsize); free(G.mytags); close(rpm_fd); } -- cgit v1.2.3-55-g6feb From af0255f49681bcc78830a56af885e891eca210f4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Feb 2013 01:24:32 +0100 Subject: head,tail: use common suffix struct. simplify help text. function old new delta head_tail_suffixes - 32 +32 head_main 415 406 -9 packed_usage 29252 29234 -18 tail_suffixes 32 - -32 head_suffixes 32 - -32 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 0/2 up/down: 32/-91) Total: -59 bytes text data bss dec hex filename 890474 497 7584 898555 db5fb busybox_old 890415 497 7584 898496 db5c0 busybox_unstripped Signed-off-by: Denys Vlasenko --- coreutils/Kbuild.src | 2 -- coreutils/head.c | 27 +++++++++++++-------------- coreutils/head_tail.c | 14 ++++++++++++++ coreutils/head_tail.h | 6 ++++++ coreutils/tail.c | 18 +++++++----------- 5 files changed, 40 insertions(+), 27 deletions(-) create mode 100644 coreutils/head_tail.c create mode 100644 coreutils/head_tail.h diff --git a/coreutils/Kbuild.src b/coreutils/Kbuild.src index b715b9c47..ec4ef7df2 100644 --- a/coreutils/Kbuild.src +++ b/coreutils/Kbuild.src @@ -35,7 +35,6 @@ lib-$(CONFIG_EXPAND) += expand.o lib-$(CONFIG_FALSE) += false.o lib-$(CONFIG_FOLD) += fold.o lib-$(CONFIG_FSYNC) += fsync.o -lib-$(CONFIG_HEAD) += head.o lib-$(CONFIG_INSTALL) += install.o #lib-$(CONFIG_LENGTH) += length.o lib-$(CONFIG_LN) += ln.o @@ -71,7 +70,6 @@ lib-$(CONFIG_STTY) += stty.o lib-$(CONFIG_SUM) += sum.o lib-$(CONFIG_SYNC) += sync.o lib-$(CONFIG_TAC) += tac.o -lib-$(CONFIG_TAIL) += tail.o lib-$(CONFIG_TEE) += tee.o lib-$(CONFIG_TRUE) += true.o lib-$(CONFIG_TTY) += tty.o diff --git a/coreutils/head.c b/coreutils/head.c index ec4512765..598fccb64 100644 --- a/coreutils/head.c +++ b/coreutils/head.c @@ -11,6 +11,9 @@ /* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */ +//kbuild:lib-$(CONFIG_HEAD) += head.o +//kbuild:lib-$(CONFIG_HEAD) += head_tail.o + //usage:#define head_trivial_usage //usage: "[OPTIONS] [FILE]..." //usage:#define head_full_usage "\n\n" @@ -31,6 +34,7 @@ //usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" #include "libbb.h" +#include "head_tail.h" /* This is a NOEXEC applet. Be very careful! */ @@ -41,20 +45,12 @@ static const char head_opts[] ALIGN1 = #endif ; -static const struct suffix_mult head_suffixes[] = { - { "b", 512 }, - { "k", 1024 }, - { "m", 1024*1024 }, - { "", 0 } -}; - #define header_fmt_str "\n==> %s <==\n" int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int head_main(int argc, char **argv) { unsigned long count = 10; - unsigned long i; #if ENABLE_FEATURE_FANCY_HEAD int count_bytes = 0; int header_threshhold = 1; @@ -63,7 +59,6 @@ int head_main(int argc, char **argv) const char *fmt; char *p; int opt; - int c; int retval = EXIT_SUCCESS; #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD @@ -97,7 +92,7 @@ int head_main(int argc, char **argv) #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD GET_COUNT: #endif - count = xatoul_sfx(p, head_suffixes); + count = xatoul_sfx(p, head_tail_suffixes); break; default: bb_show_usage(); @@ -127,6 +122,8 @@ int head_main(int argc, char **argv) do { fp = fopen_or_warn_stdin(*argv); if (fp) { + unsigned long i; + if (fp == stdin) { *argv = (char *) bb_msg_standard_input; } @@ -134,17 +131,19 @@ int head_main(int argc, char **argv) printf(fmt, *argv); } i = count; - while (i && ((c = getc(fp)) != EOF)) { - if (count_bytes || (c == '\n')) { + while (i) { + int c = getc(fp); + if (c == EOF) + break; + if (count_bytes || (c == '\n')) --i; - } putchar(c); } + die_if_ferror_stdout(); if (fclose_if_not_stdin(fp)) { bb_simple_perror_msg(*argv); retval = EXIT_FAILURE; } - die_if_ferror_stdout(); } else { retval = EXIT_FAILURE; } diff --git a/coreutils/head_tail.c b/coreutils/head_tail.c new file mode 100644 index 000000000..1658c0d1b --- /dev/null +++ b/coreutils/head_tail.c @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2013 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "head_tail.h" + +const struct suffix_mult head_tail_suffixes[] = { + { "b", 512 }, + { "k", 1024 }, + { "m", 1024*1024 }, + { "", 0 } +}; diff --git a/coreutils/head_tail.h b/coreutils/head_tail.h new file mode 100644 index 000000000..df19e41e0 --- /dev/null +++ b/coreutils/head_tail.h @@ -0,0 +1,6 @@ +/* + * Copyright (C) 2013 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +extern const struct suffix_mult head_tail_suffixes[]; diff --git a/coreutils/tail.c b/coreutils/tail.c index b376ec863..87251da83 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c @@ -24,6 +24,9 @@ * 7) lseek attempted when count==0 even if arg was +0 (from top) */ +//kbuild:lib-$(CONFIG_TAIL) += tail.o +//kbuild:lib-$(CONFIG_TAIL) += head_tail.o + //usage:#define tail_trivial_usage //usage: "[OPTIONS] [FILE]..." //usage:#define tail_full_usage "\n\n" @@ -34,14 +37,13 @@ //usage: "\n -s SECONDS Wait SECONDS between reads with -f" //usage: ) //usage: "\n -n N[kbm] Print last N lines" +//usage: "\n -n +N[kbm] Skip N lines and print the rest" //usage: IF_FEATURE_FANCY_TAIL( -//usage: "\n -c N[kbm] Print last N bytes" +//usage: "\n -c [+]N[kbm] Print last N bytes" //usage: "\n -q Never print headers" //usage: "\n -v Always print headers" //usage: "\n" //usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." -//usage: "\nIf N starts with a '+', output begins with the Nth item from the start" -//usage: "\nof each file, not from the end." //usage: ) //usage: //usage:#define tail_example_usage @@ -49,13 +51,7 @@ //usage: "nameserver 10.0.0.1\n" #include "libbb.h" - -static const struct suffix_mult tail_suffixes[] = { - { "b", 512 }, - { "k", 1024 }, - { "m", 1024*1024 }, - { "", 0 } -}; +#include "head_tail.h" struct globals { bool from_top; @@ -102,7 +98,7 @@ static unsigned eat_num(const char *p) p++; G.from_top = 1; } - return xatou_sfx(p, tail_suffixes); + return xatou_sfx(p, head_tail_suffixes); } int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -- cgit v1.2.3-55-g6feb From 40c6da433f0900d451e46da86422d89f3878d40c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Feb 2013 01:26:09 +0100 Subject: head: support -n -NUM and -c -NUM function old new delta head_main 406 832 +426 packed_usage 29234 29252 +18 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 444/0) Total: 444 bytes Signed-off-by: Denys Vlasenko --- coreutils/head.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 128 insertions(+), 22 deletions(-) diff --git a/coreutils/head.c b/coreutils/head.c index 598fccb64..291e1ce37 100644 --- a/coreutils/head.c +++ b/coreutils/head.c @@ -21,7 +21,8 @@ //usage: "With more than one FILE, precede each with a filename header.\n" //usage: "\n -n N[kbm] Print first N lines" //usage: IF_FEATURE_FANCY_HEAD( -//usage: "\n -c N[kbm] Print first N bytes" +//usage: "\n -n -N[kbm] Print all except N last lines" +//usage: "\n -c [-]N[kbm] Print first N bytes" //usage: "\n -q Never print headers" //usage: "\n -v Always print headers" //usage: ) @@ -38,6 +39,110 @@ /* This is a NOEXEC applet. Be very careful! */ +#if !ENABLE_FEATURE_FANCY_HEAD +# define print_first_N(fp,count,bytes) print_first_N(fp,count) +#endif +static void +print_first_N(FILE *fp, unsigned long count, bool count_bytes) +{ +#if !ENABLE_FEATURE_FANCY_HEAD + const int count_bytes = 0; +#endif + while (count) { + int c = getc(fp); + if (c == EOF) + break; + if (count_bytes || (c == '\n')) + --count; + putchar(c); + } +} + +#if ENABLE_FEATURE_FANCY_HEAD +static void +print_except_N_last_bytes(FILE *fp, unsigned count) +{ + unsigned char *circle = xmalloc(++count); + unsigned head = 0; + for(;;) { + int c; + c = getc(fp); + if (c == EOF) + goto ret; + circle[head++] = c; + if (head == count) + break; + } + for (;;) { + int c; + if (head == count) + head = 0; + putchar(circle[head]); + c = getc(fp); + if (c == EOF) + goto ret; + circle[head] = c; + head++; + } + ret: + free(circle); +} + +static void +print_except_N_last_lines(FILE *fp, unsigned count) +{ + char **circle = xzalloc((++count) * sizeof(circle[0])); + unsigned head = 0; + for(;;) { + char *c; + c = xmalloc_fgets(fp); + if (!c) + goto ret; + circle[head++] = c; + if (head == count) + break; + } + for (;;) { + char *c; + if (head == count) + head = 0; + fputs(circle[head], stdout); + c = xmalloc_fgets(fp); + if (!c) + goto ret; + free(circle[head]); + circle[head++] = c; + } + ret: + head = 0; + for(;;) { + free(circle[head++]); + if (head == count) + break; + } + free(circle); +} +#else +/* Must never be called */ +void print_except_N_last_bytes(FILE *fp, unsigned count); +void print_except_N_last_lines(FILE *fp, unsigned count); +#endif + +#if !ENABLE_FEATURE_FANCY_HEAD +# define eat_num(negative_N,p) eat_num(p) +#endif +static unsigned long +eat_num(bool *negative_N, const char *p) +{ +#if ENABLE_FEATURE_FANCY_HEAD + if (*p == '-') { + *negative_N = 1; + p++; + } +#endif + return xatoul_sfx(p, head_tail_suffixes); +} + static const char head_opts[] ALIGN1 = "n:" #if ENABLE_FEATURE_FANCY_HEAD @@ -52,8 +157,13 @@ int head_main(int argc, char **argv) { unsigned long count = 10; #if ENABLE_FEATURE_FANCY_HEAD - int count_bytes = 0; int header_threshhold = 1; + bool count_bytes = 0; + bool negative_N = 0; +#else +# define header_threshhold 1 +# define count_bytes 0 +# define negative_N 0 #endif FILE *fp; const char *fmt; @@ -68,7 +178,7 @@ int head_main(int argc, char **argv) ) { --argc; ++argv; - p = (*argv) + 1; + p = argv[0] + 1; goto GET_COUNT; } #endif @@ -92,7 +202,7 @@ int head_main(int argc, char **argv) #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD GET_COUNT: #endif - count = xatoul_sfx(p, head_tail_suffixes); + count = eat_num(&negative_N, p); break; default: bb_show_usage(); @@ -105,39 +215,35 @@ int head_main(int argc, char **argv) *--argv = (char*)"-"; fmt = header_fmt_str + 1; -#if ENABLE_FEATURE_FANCY_HEAD if (argc <= header_threshhold) { +#if ENABLE_FEATURE_FANCY_HEAD header_threshhold = 0; - } #else - if (argc <= 1) { fmt += 11; /* "" */ - } - /* Now define some things here to avoid #ifdefs in the code below. - * These should optimize out of the if conditions below. */ -#define header_threshhold 1 -#define count_bytes 0 #endif + } + if (negative_N) { + if (count >= INT_MAX / sizeof(char*)) + bb_error_msg("count is too big: %lu", count); + } do { fp = fopen_or_warn_stdin(*argv); if (fp) { - unsigned long i; - if (fp == stdin) { *argv = (char *) bb_msg_standard_input; } if (header_threshhold) { printf(fmt, *argv); } - i = count; - while (i) { - int c = getc(fp); - if (c == EOF) - break; - if (count_bytes || (c == '\n')) - --i; - putchar(c); + if (negative_N) { + if (count_bytes) { + print_except_N_last_bytes(fp, count); + } else { + print_except_N_last_lines(fp, count); + } + } else { + print_first_N(fp, count, count_bytes); } die_if_ferror_stdout(); if (fclose_if_not_stdin(fp)) { -- cgit v1.2.3-55-g6feb From 3305c008ed6084f58b59dde5198ae92e3a458e46 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Feb 2013 07:24:44 +0100 Subject: tail: make help text for -n +N syntax more correct Signed-off-by: Denys Vlasenko --- coreutils/tail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/tail.c b/coreutils/tail.c index 87251da83..19fd8f695 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c @@ -37,7 +37,7 @@ //usage: "\n -s SECONDS Wait SECONDS between reads with -f" //usage: ) //usage: "\n -n N[kbm] Print last N lines" -//usage: "\n -n +N[kbm] Skip N lines and print the rest" +//usage: "\n -n +N[kbm] Start on Nth line and print the rest" //usage: IF_FEATURE_FANCY_TAIL( //usage: "\n -c [+]N[kbm] Print last N bytes" //usage: "\n -q Never print headers" -- cgit v1.2.3-55-g6feb From 1961aea305e258ba7ab3910d084451220f55ed44 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 26 Feb 2013 00:36:53 +0100 Subject: move endofname() to libbb Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + libbb/endofname.c | 26 ++++++++++++++++++++++++++ shell/ash.c | 24 +++--------------------- shell/math.c | 12 ------------ shell/math.h | 5 ----- 5 files changed, 30 insertions(+), 38 deletions(-) create mode 100644 libbb/endofname.c diff --git a/include/libbb.h b/include/libbb.h index e52006020..79a37a759 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -386,6 +386,7 @@ char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC; const char *bb_basename(const char *name) FAST_FUNC; /* NB: can violate const-ness (similarly to strchr) */ char *last_char_is(const char *s, int c) FAST_FUNC; +const char* endofname(const char *name) FAST_FUNC; void ndelay_on(int fd) FAST_FUNC; void ndelay_off(int fd) FAST_FUNC; diff --git a/libbb/endofname.c b/libbb/endofname.c new file mode 100644 index 000000000..305f0932b --- /dev/null +++ b/libbb/endofname.c @@ -0,0 +1,26 @@ +/* + * Utility routines. + * + * Copyright (C) 2013 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += endofname.o + +#include "libbb.h" + +#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) +#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) + +const char* FAST_FUNC +endofname(const char *name) +{ + if (!is_name(*name)) + return name; + while (*++name) { + if (!is_in_name(*name)) + break; + } + return name; +} diff --git a/shell/ash.c b/shell/ash.c index 31fbc550a..0b5111a39 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -385,6 +385,9 @@ static void trace_vprintf(const char *fmt, va_list va); /* ============ Utility functions */ #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) +#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) +#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) + static int isdigit_str9(const char *str) { int maxlen = 9 + 1; /* max 9 digits: 999999999 */ @@ -2008,27 +2011,6 @@ getoptsreset(const char *value) } #endif -/* math.h has these, otherwise define our private copies */ -#if !ENABLE_SH_MATH_SUPPORT -#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) -#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) -/* - * Return the pointer to the first char which is not part of a legal variable name - * (a letter or underscore followed by letters, underscores, and digits). - */ -static const char* -endofname(const char *name) -{ - if (!is_name(*name)) - return name; - while (*++name) { - if (!is_in_name(*name)) - break; - } - return name; -} -#endif - /* * Compares two strings up to the first = or '\0'. The first * string must be terminated by '='; the second may be terminated by diff --git a/shell/math.c b/shell/math.c index 15c003965..3da151137 100644 --- a/shell/math.c +++ b/shell/math.c @@ -494,18 +494,6 @@ static const char op_tokens[] ALIGN1 = { }; #define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7]) -const char* FAST_FUNC -endofname(const char *name) -{ - if (!is_name(*name)) - return name; - while (*++name) { - if (!is_in_name(*name)) - break; - } - return name; -} - static arith_t FAST_FUNC evaluate_string(arith_state_t *math_state, const char *expr) { diff --git a/shell/math.h b/shell/math.h index 2d305eb12..864bee691 100644 --- a/shell/math.h +++ b/shell/math.h @@ -73,11 +73,6 @@ typedef long arith_t; #define strto_arith_t strtoul #endif -/* ash's and hush's endofname is the same, so... */ -# define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) -# define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) -const char* FAST_FUNC endofname(const char *name); - typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name); typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); -- cgit v1.2.3-55-g6feb From 40b97fb31ec7c24db706b47182f400f2a13dbbfc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 26 Feb 2013 00:40:46 +0100 Subject: mdev: add environment variable match function old new delta make_device 1998 2189 +191 clean_up_cur_rule 61 96 +35 dirAction 75 87 +12 mdev_main 838 849 +11 packed_usage 29272 29273 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/0 up/down: 250/0) Total: 250 bytes Signed-off-by: Denys Vlasenko --- docs/mdev.txt | 4 +-- util-linux/mdev.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/docs/mdev.txt b/docs/mdev.txt index 61f93c9df..b24025f7b 100644 --- a/docs/mdev.txt +++ b/docs/mdev.txt @@ -51,9 +51,9 @@ device nodes if your system needs something more than the default root/root 660 permissions. The file has the format: - [-] : + [-][envmatch] : or - @ : + [envmatch]@ : or $envvar= : diff --git a/util-linux/mdev.c b/util-linux/mdev.c index c592ef687..775e5c241 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -80,7 +80,7 @@ //usage: IF_FEATURE_MDEV_CONF( //usage: "\n" //usage: "It uses /etc/mdev.conf with lines\n" -//usage: " [-]DEVNAME UID:GID PERM" +//usage: " [-][ENV=regex;]...DEVNAME UID:GID PERM" //usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]") //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") //usage: "\n" @@ -233,6 +233,12 @@ static const char keywords[] ALIGN1 = "add\0remove\0change\0"; enum { OP_add, OP_remove }; +struct envmatch { + struct envmatch *next; + char *envname; + regex_t match; +}; + struct rule { bool keep_matching; bool regex_compiled; @@ -243,6 +249,7 @@ struct rule { char *ren_mov; IF_FEATURE_MDEV_EXEC(char *r_cmd;) regex_t match; + struct envmatch *envmatch; }; struct globals { @@ -288,14 +295,48 @@ static void make_default_cur_rule(void) static void clean_up_cur_rule(void) { + struct envmatch *e; + free(G.cur_rule.envvar); + free(G.cur_rule.ren_mov); if (G.cur_rule.regex_compiled) regfree(&G.cur_rule.match); - free(G.cur_rule.ren_mov); IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) + e = G.cur_rule.envmatch; + while (e) { + free(e->envname); + regfree(&e->match); + e = e->next; + } make_default_cur_rule(); } +static char *parse_envmatch_pfx(char *val) +{ + struct envmatch **nextp = &G.cur_rule.envmatch; + + for (;;) { + struct envmatch *e; + char *semicolon; + char *eq = strchr(val, '='); + if (!eq /* || eq == val? */) + return val; + if (endofname(val) != eq) + return val; + semicolon = strchr(eq, ';'); + if (!semicolon) + return val; + /* ENVVAR=regex;... */ + *nextp = e = xzalloc(sizeof(*e)); + nextp = &e->next; + e->envname = xstrndup(val, eq - val); + *semicolon = '\0'; + xregcomp(&e->match, eq + 1, REG_EXTENDED); + *semicolon = ';'; + val = semicolon + 1; + } +} + static void parse_next_rule(void) { /* Note: on entry, G.cur_rule is set to default */ @@ -314,6 +355,7 @@ static void parse_next_rule(void) val = tokens[0]; G.cur_rule.keep_matching = ('-' == val[0]); val += G.cur_rule.keep_matching; /* swallow leading dash */ + val = parse_envmatch_pfx(val); if (val[0] == '@') { /* @major,minor[-minor2] */ /* (useful when name is ambiguous: @@ -328,8 +370,10 @@ static void parse_next_rule(void) if (sc == 2) G.cur_rule.min1 = G.cur_rule.min0; } else { + char *eq = strchr(val, '='); if (val[0] == '$') { - char *eq = strchr(++val, '='); + /* $ENVVAR=regex ... */ + val++; if (!eq) { bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); goto next_rule; @@ -423,6 +467,21 @@ static const struct rule *next_rule(void) return rule; } +static int env_matches(struct envmatch *e) +{ + while (e) { + int r; + char *val = getenv(e->envname); + if (!val) + return 0; + r = regexec(&e->match, val, /*size*/ 0, /*range[]*/ NULL, /*eflags*/ 0); + if (r != 0) /* no match */ + return 0; + e = e->next; + } + return 1; +} + #else # define next_rule() (&G.cur_rule) @@ -537,6 +596,8 @@ static void make_device(char *device_name, char *path, int operation) rule = next_rule(); #if ENABLE_FEATURE_MDEV_CONF + if (!env_matches(rule->envmatch)) + continue; if (rule->maj >= 0) { /* @maj,min rule */ if (major != rule->maj) continue; @@ -749,8 +810,10 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, if (1 == depth) { free(G.subsystem); G.subsystem = strrchr(fileName, '/'); - if (G.subsystem) + if (G.subsystem) { G.subsystem = xstrdup(G.subsystem + 1); + xsetenv("SUBSYSTEM", G.subsystem); + } } return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); @@ -843,8 +906,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) xchdir("/dev"); if (argv[1] && strcmp(argv[1], "-s") == 0) { - /* Scan: - * mdev -s + /* + * Scan: mdev -s */ struct stat st; @@ -856,6 +919,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) G.root_major = major(st.st_dev); G.root_minor = minor(st.st_dev); + putenv((char*)"ACTION=add"); + /* ACTION_FOLLOWLINKS is needed since in newer kernels * /sys/block/loop* (for example) are symlinks to dirs, * not real directories. -- cgit v1.2.3-55-g6feb From 39b8fb41c50e6ee0aaca81cde2a4dec98d45ef9a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 27 Feb 2013 01:01:43 -0500 Subject: udhcpc: support resolv.conf symlinks Often it is desirable to have /etc/ be on read-only storage (well, the whole rootfs) but have things like /etc/resolv.conf be symlinks to a writable location. Tweak the simple script to support that. Signed-off-by: Mike Frysinger --- examples/udhcp/simple.script | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index 40ee73822..d42f2d3d5 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script @@ -34,13 +34,17 @@ case "$1" in fi echo "Recreating $RESOLV_CONF" - echo -n > $RESOLV_CONF-$$ - [ -n "$domain" ] && echo "search $domain" >> $RESOLV_CONF-$$ + # If the file is a symlink somewhere (like /etc/resolv.conf + # pointing to /run/resolv.conf), make sure things work. + realconf=$(realpath "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") + tmpfile="$realconf-$$" + > "$tmpfile" + [ -n "$domain" ] && echo "search $domain" >> "$tmpfile" for i in $dns ; do echo " Adding DNS server $i" - echo "nameserver $i" >> $RESOLV_CONF-$$ + echo "nameserver $i" >> "$tmpfile" done - mv $RESOLV_CONF-$$ $RESOLV_CONF + mv "$tmpfile" "$realconf" ;; esac -- cgit v1.2.3-55-g6feb From 9fed24c031a885264a9249eed3b6c654c32ce139 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 27 Feb 2013 01:05:34 -0500 Subject: udhcpc: tweak math shell style with the metric var Some shells (like dash) are lame and omit the POSIX increment/decrement feature (because it is listed as optional). Tweak the shell script to work in all POSIX variants. Signed-off-by: Mike Frysinger --- examples/udhcp/simple.script | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index d42f2d3d5..0397e506c 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script @@ -29,7 +29,8 @@ case "$1" in metric=0 for i in $router ; do echo "Adding router $i" - route add default gw $i dev $interface metric $((metric++)) + route add default gw $i dev $interface metric $metric + : $(( metric += 1 )) done fi -- cgit v1.2.3-55-g6feb From 5bce135e36800a34a273376d5ea1f052ed2d4212 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 27 Feb 2013 10:51:41 +0100 Subject: mdev: improve $SEQ handling; improve debug logging Sequential run of concurrent mdev's was too simplistic: they waited for /dev/mdev.seq to match. This could sometimes cause cumulative loss of time on the order of a second. Added SIGCHLD signaling from exiting mdev to all other mdev's. Added debugging required to see that code actually works as intended. Example of /dev/mdev.log (with "woken up" elevated from dbg lvl 3 to 2): mdev[1023]: first seq written ^^^^ seq, not pid mdev[1023]: 35.022395 ACTION:add SUBSYSTEM:module DEVNAME:(null) DEVPATH:/module/lib80211 mdev[1023]: rule matched, line -1 ^^^^^^^ means "default rule" mdev[1023]: 35.022676 exiting ^^^^^^^^^ second,usec timestamp mdev[1024]: 35.069691 ACTION:add SUBSYSTEM:vc DEVNAME:vcs9 DEVPATH:/devices/virtual/vc/vcs9 mdev[1024]: dev 7,9 mdev[1025]: 35.069889 waiting for '1024' mdev[1026]: 35.069946 waiting for '1024' mdev[1027]: 35.070151 waiting for '1024' mdev[1024]: rule matched, line -1 mdev[1024]: mknod vcs9 (7,9) 20660 0:0 mdev[1024]: 35.070346 exiting mdev[1025]: woken up mdev[1026]: woken up mdev[1025]: 35.071213 ACTION:add SUBSYSTEM:vc DEVNAME:vcsa9 DEVPATH:/devices/virtual/vc/vcsa9 ^^^^^^^^^ took only a millisecond to start running after prev mdev exited mdev[1025]: dev 7,137 mdev[1027]: woken up mdev[1025]: rule matched, line -1 mdev[1025]: mknod vcsa9 (7,137) 20660 0:0 mdev[1025]: 35.072109 exiting function old new delta mdev_main 849 1372 +523 curtime - 59 +59 dirAction 87 134 +47 static.ts - 8 +8 keywords 19 12 -7 make_device 2189 2119 -70 Signed-off-by: Denys Vlasenko --- examples/mdev_fat.conf | 7 +- util-linux/mdev.c | 265 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 181 insertions(+), 91 deletions(-) diff --git a/examples/mdev_fat.conf b/examples/mdev_fat.conf index ceba3a797..bceddb2d7 100644 --- a/examples/mdev_fat.conf +++ b/examples/mdev_fat.conf @@ -7,9 +7,9 @@ # instead of the default 0:0 660. # # Syntax: -# [-]devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] -# [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] -# [-]@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] +# [-][ENVVAR=regex;]...devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] +# [-][ENVVAR=regex;]...@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] +# [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] # # [-]: do not stop on this match, continue reading mdev.conf # =: move, >: move and create a symlink @@ -53,6 +53,7 @@ sr[0-9]* root:cdrom 660 @ln -sf $MDEV cdrom fd[0-9]* root:floppy 660 # net devices +SUBSYSTEM=net;.* root:root 600 @nameif tun[0-9]* root:root 600 =net/ tap[0-9]* root:root 600 =net/ diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 775e5c241..c5c0d613c 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -230,7 +230,26 @@ * SUBSYSTEM=block */ -static const char keywords[] ALIGN1 = "add\0remove\0change\0"; +#define DEBUG_LVL 2 + +#if DEBUG_LVL >= 1 +# define dbg1(...) do { if (G.verbose) bb_error_msg(__VA_ARGS__); } while(0) +#else +# define dbg1(...) ((void)0) +#endif +#if DEBUG_LVL >= 2 +# define dbg2(...) do { if (G.verbose >= 2) bb_error_msg(__VA_ARGS__); } while(0) +#else +# define dbg2(...) ((void)0) +#endif +#if DEBUG_LVL >= 3 +# define dbg3(...) do { if (G.verbose >= 3) bb_error_msg(__VA_ARGS__); } while(0) +#else +# define dbg3(...) ((void)0) +#endif + + +static const char keywords[] ALIGN1 = "add\0remove\0"; // "change\0" enum { OP_add, OP_remove }; struct envmatch { @@ -256,6 +275,7 @@ struct globals { int root_major, root_minor; smallint verbose; char *subsystem; + char *subsys_env; /* for putenv("SUBSYSTEM=subsystem") */ #if ENABLE_FEATURE_MDEV_CONF const char *filename; parser_t *parser; @@ -263,6 +283,7 @@ struct globals { unsigned rule_idx; #endif struct rule cur_rule; + char timestr[sizeof("60.123456")]; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { \ @@ -277,13 +298,6 @@ struct globals { /* We use additional 64+ bytes in make_device() */ #define SCRATCH_SIZE 80 -#if 0 -# define dbg(...) bb_error_msg(__VA_ARGS__) -#else -# define dbg(...) ((void)0) -#endif - - #if ENABLE_FEATURE_MDEV_CONF static void make_default_cur_rule(void) @@ -349,7 +363,7 @@ static void parse_next_rule(void) break; /* Fields: [-]regex uid:gid mode [alias] [cmd] */ - dbg("token1:'%s'", tokens[1]); + dbg3("token1:'%s'", tokens[1]); /* 1st field */ val = tokens[0]; @@ -417,7 +431,7 @@ static void parse_next_rule(void) clean_up_cur_rule(); } /* while (config_read) */ - dbg("config_close(G.parser)"); + dbg3("config_close(G.parser)"); config_close(G.parser); G.parser = NULL; @@ -434,7 +448,7 @@ static const struct rule *next_rule(void) /* Open conf file if we didn't do it yet */ if (!G.parser && G.filename) { - dbg("config_open('%s')", G.filename); + dbg3("config_open('%s')", G.filename); G.parser = config_open2(G.filename, fopen_for_read); G.filename = NULL; } @@ -443,7 +457,7 @@ static const struct rule *next_rule(void) /* mdev -s */ /* Do we have rule parsed already? */ if (G.rule_vec[G.rule_idx]) { - dbg("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); + dbg3("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); return G.rule_vec[G.rule_idx++]; } make_default_cur_rule(); @@ -460,7 +474,7 @@ static const struct rule *next_rule(void) rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule)); G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx); G.rule_vec[G.rule_idx++] = rule; - dbg("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); + dbg3("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); } } @@ -538,9 +552,6 @@ static void make_device(char *device_name, char *path, int operation) { int major, minor, type, len; - if (G.verbose) - bb_error_msg("device: %s, %s", device_name, path); - /* Try to read major/minor string. Note that the kernel puts \n after * the data, so we don't need to worry about null terminating the string * because sscanf() will stop at the first nondigit, which \n is. @@ -559,8 +570,7 @@ static void make_device(char *device_name, char *path, int operation) /* no "dev" file, but we can still run scripts * based on device name */ } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) { - if (G.verbose) - bb_error_msg("maj,min: %u,%u", major, minor); + dbg1("dev %u,%u", major, minor); } else { major = -1; } @@ -570,7 +580,8 @@ static void make_device(char *device_name, char *path, int operation) /* Determine device name, type, major and minor */ if (!device_name) device_name = (char*) bb_basename(path); - /* http://kernel.org/doc/pending/hotplug.txt says that only + /* + * http://kernel.org/doc/pending/hotplug.txt says that only * "/sys/block/..." is for block devices. "/sys/bus" etc is not. * But since 2.6.25 block devices are also in /sys/class/block. * We use strstr("/block/") to forestall future surprises. @@ -608,7 +619,7 @@ static void make_device(char *device_name, char *path, int operation) } if (rule->envvar) { /* $envvar=regex rule */ str_to_match = getenv(rule->envvar); - dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); + dbg3("getenv('%s'):'%s'", rule->envvar, str_to_match); if (!str_to_match) continue; } @@ -616,7 +627,7 @@ static void make_device(char *device_name, char *path, int operation) if (rule->regex_compiled) { int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); - dbg("regex_match for '%s':%d", str_to_match, regex_match); + dbg3("regex_match for '%s':%d", str_to_match, regex_match); //bb_error_msg("matches:"); //for (int i = 0; i < ARRAY_SIZE(off); i++) { // if (off[i].rm_so < 0) continue; @@ -636,7 +647,7 @@ static void make_device(char *device_name, char *path, int operation) /* else: it's final implicit "match-all" rule */ rule_matches: #endif - dbg("rule matched"); + dbg2("rule matched, line %d", G.parser ? G.parser->lineno : -1); /* Build alias name */ alias = NULL; @@ -680,34 +691,30 @@ static void make_device(char *device_name, char *path, int operation) } } } - dbg("alias:'%s'", alias); + dbg3("alias:'%s'", alias); command = NULL; IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;) if (command) { - const char *s = "$@*"; - const char *s2 = strchr(s, command[0]); - /* Are we running this command now? - * Run $cmd on delete, @cmd on create, *cmd on both + * Run @cmd on create, $cmd on delete, *cmd on any */ - if (s2 - s != (operation == OP_remove) || *s2 == '*') { - /* We are here if: '*', - * or: '@' and delete = 0, - * or: '$' and delete = 1 - */ + if ((command[0] == '@' && operation == OP_add) + || (command[0] == '$' && operation == OP_remove) + || (command[0] == '*') + ) { command++; } else { command = NULL; } } - dbg("command:'%s'", command); + dbg3("command:'%s'", command); /* "Execute" the line we found */ node_name = device_name; if (ENABLE_FEATURE_MDEV_RENAME && alias) { node_name = alias = build_alias(alias, device_name); - dbg("alias2:'%s'", alias); + dbg3("alias2:'%s'", alias); } if (operation == OP_add && major >= 0) { @@ -717,13 +724,20 @@ static void make_device(char *device_name, char *path, int operation) mkdir_recursive(node_name); *slash = '/'; } - if (G.verbose) - bb_error_msg("mknod: %s (%d,%d) %o", node_name, major, minor, rule->mode | type); + if (ENABLE_FEATURE_MDEV_CONF) { + dbg1("mknod %s (%d,%d) %o" + " %u:%u", + node_name, major, minor, rule->mode | type, + rule->ugid.uid, rule->ugid.gid + ); + } else { + dbg1("mknod %s (%d,%d) %o", + node_name, major, minor, rule->mode | type + ); + } if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) bb_perror_msg("can't create '%s'", node_name); if (ENABLE_FEATURE_MDEV_CONF) { - if (G.verbose) - bb_error_msg("chmod: %o chown: %u:%u", rule->mode, rule->ugid.uid, rule->ugid.gid); chmod(node_name, rule->mode); chown(node_name, rule->ugid.uid, rule->ugid.gid); } @@ -734,8 +748,7 @@ static void make_device(char *device_name, char *path, int operation) //TODO: on devtmpfs, device_name already exists and symlink() fails. //End result is that instead of symlink, we have two nodes. //What should be done? - if (G.verbose) - bb_error_msg("symlink: %s", device_name); + dbg1("symlink: %s", device_name); symlink(node_name, device_name); } } @@ -744,27 +757,21 @@ static void make_device(char *device_name, char *path, int operation) if (ENABLE_FEATURE_MDEV_EXEC && command) { /* setenv will leak memory, use putenv/unsetenv/free */ char *s = xasprintf("%s=%s", "MDEV", node_name); - char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); putenv(s); - putenv(s1); - if (G.verbose) - bb_error_msg("running: %s", command); + dbg1("running: %s", command); if (system(command) == -1) bb_perror_msg("can't run '%s'", command); - bb_unsetenv_and_free(s1); bb_unsetenv_and_free(s); } if (operation == OP_remove && major >= -1) { if (ENABLE_FEATURE_MDEV_RENAME && alias) { if (aliaslink == '>') { - if (G.verbose) - bb_error_msg("unlink: %s", device_name); + dbg1("unlink: %s", device_name); unlink(device_name); } } - if (G.verbose) - bb_error_msg("unlink: %s", node_name); + dbg1("unlink: %s", node_name); unlink(node_name); } @@ -809,10 +816,15 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, * under /sys/class/ */ if (1 == depth) { free(G.subsystem); + if (G.subsys_env) { + bb_unsetenv_and_free(G.subsys_env); + G.subsys_env = NULL; + } G.subsystem = strrchr(fileName, '/'); if (G.subsystem) { G.subsystem = xstrdup(G.subsystem + 1); - xsetenv("SUBSYSTEM", G.subsystem); + G.subsys_env = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); + putenv(G.subsys_env); } } @@ -885,6 +897,100 @@ static void load_firmware(const char *firmware, const char *sysfs_path) } } +static char *curtime(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + sprintf(G.timestr, "%u.%06u", (unsigned)tv.tv_sec % 60, (unsigned)tv.tv_usec); + return G.timestr; +} + +static void open_mdev_log(const char *seq, unsigned my_pid) +{ + int logfd = open("mdev.log", O_WRONLY | O_APPEND); + if (logfd >= 0) { + xmove_fd(logfd, STDERR_FILENO); + G.verbose = 2; + applet_name = xasprintf("%s[%s]", applet_name, seq ? seq : utoa(my_pid)); + } +} + +/* If it exists, does /dev/mdev.seq match $SEQNUM? + * If it does not match, earlier mdev is running + * in parallel, and we need to wait. + * Active mdev pokes us with SIGCHLD to check the new file. + */ +static int +wait_for_seqfile(const char *seq) +{ + /* We time out after 2 sec */ + static const struct timespec ts = { 0, 32*1000*1000 }; + int timeout = 2000 / 32; + int seq_fd = -1; + int do_once = 1; + sigset_t set_CHLD; + + sigemptyset(&set_CHLD); + sigaddset(&set_CHLD, SIGCHLD); + sigprocmask(SIG_BLOCK, &set_CHLD, NULL); + + for (;;) { + int seqlen; + char seqbuf[sizeof(int)*3 + 2]; + + if (seq_fd < 0) { + seq_fd = open("mdev.seq", O_RDWR); + if (seq_fd < 0) + break; + } + seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); + if (seqlen < 0) { + close(seq_fd); + seq_fd = -1; + break; + } + seqbuf[seqlen] = '\0'; + if (seqbuf[0] == '\n') { + /* seed file: write out seq ASAP */ + xwrite_str(seq_fd, seq); + xlseek(seq_fd, 0, SEEK_SET); + dbg2("first seq written"); + break; + } + if (strcmp(seq, seqbuf) == 0) { + /* correct idx */ + break; + } + if (do_once) { + dbg2("%s waiting for '%s'", curtime(), seqbuf); + do_once = 0; + } + if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { + dbg3("woken up"); + continue; /* don't decrement timeout! */ + } + if (--timeout == 0) { + dbg1("%s waiting for '%s'", "timed out", seqbuf); + break; + } + } + sigprocmask(SIG_UNBLOCK, &set_CHLD, NULL); + return seq_fd; +} + +static void signal_mdevs(unsigned my_pid) +{ + procps_status_t* p = NULL; + while ((p = procps_scan(p, PSSCAN_ARGV0)) != NULL) { + if (p->pid != my_pid + && p->argv0 + && strcmp(bb_basename(p->argv0), "mdev") == 0 + ) { + kill(p->pid, SIGCHLD); + } + } +} + int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mdev_main(int argc UNUSED_PARAM, char **argv) { @@ -946,11 +1052,13 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) char *action; char *env_devname; char *env_devpath; + unsigned my_pid; + int seq_fd; smalluint op; /* Hotplug: * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev - * ACTION can be "add" or "remove" + * ACTION can be "add", "remove", "change" * DEVPATH is like "/block/sda" or "/class/input/mice" */ action = getenv("ACTION"); @@ -961,41 +1069,20 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) if (!action || !env_devpath /*|| !G.subsystem*/) bb_show_usage(); fw = getenv("FIRMWARE"); - /* If it exists, does /dev/mdev.seq match $SEQNUM? - * If it does not match, earlier mdev is running - * in parallel, and we need to wait */ seq = getenv("SEQNUM"); - if (seq) { - int timeout = 2000 / 32; /* 2000 msec */ - do { - int seqlen; - char seqbuf[sizeof(int)*3 + 2]; - - seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf) - 1); - if (seqlen < 0) { - seq = NULL; - break; - } - seqbuf[seqlen] = '\0'; - if (seqbuf[0] == '\n' /* seed file? */ - || strcmp(seq, seqbuf) == 0 /* correct idx? */ - ) { - break; - } - usleep(32*1000); - } while (--timeout); - } - { - int logfd = open("mdev.log", O_WRONLY | O_APPEND); - if (logfd >= 0) { - xmove_fd(logfd, STDERR_FILENO); - G.verbose = 1; - if (seq) - applet_name = xasprintf("%s[%s]", applet_name, seq); - bb_error_msg("action: %s", action); - } - } + my_pid = getpid(); + open_mdev_log(seq, my_pid); + + seq_fd = seq ? wait_for_seqfile(seq) : -1; + + dbg1("%s " + "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" + "%s%s", + curtime(), + action, G.subsystem, env_devname, env_devpath, + fw ? " FW:" : "", fw ? fw : "" + ); snprintf(temp, PATH_MAX, "/sys%s", env_devpath); if (op == OP_remove) { @@ -1005,16 +1092,18 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) if (!fw) make_device(env_devname, temp, op); } - else if (op == OP_add) { + else { make_device(env_devname, temp, op); if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { - if (fw) + if (op == OP_add && fw) load_firmware(fw, temp); } } - if (seq) { - xopen_xwrite_close("mdev.seq", utoa(xatou(seq) + 1)); + dbg1("%s exiting", curtime()); + if (seq_fd >= 0) { + xwrite_str(seq_fd, utoa(xatou(seq) + 1)); + signal_mdevs(my_pid); } } -- cgit v1.2.3-55-g6feb From e3e321682cd1e9861ba7680e61ab6dadaf1e2e32 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 27 Feb 2013 15:49:38 +0100 Subject: Fix move_to_unaligned16 Signed-off-by: Denys Vlasenko --- include/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/platform.h b/include/platform.h index 128230658..f4deb30c0 100644 --- a/include/platform.h +++ b/include/platform.h @@ -228,7 +228,7 @@ typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; # define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) # define move_to_unaligned16(u16p, v) do { \ uint16_t __t = (v); \ - memcpy((u16p), &__t, 4); \ + memcpy((u16p), &__t, 2); \ } while (0) # define move_to_unaligned32(u32p, v) do { \ uint32_t __t = (v); \ -- cgit v1.2.3-55-g6feb From 04f296b28a4927efffced38170d92134982566a6 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:23:05 +0100 Subject: xz: omit explicit \0 from HEADER_MAGIC Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/xz_stream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/libarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h index 36f2a7cbf..2ffaa34ea 100644 --- a/archival/libarchive/unxz/xz_stream.h +++ b/archival/libarchive/unxz/xz_stream.h @@ -25,7 +25,7 @@ #define STREAM_HEADER_SIZE 12 -#define HEADER_MAGIC "\3757zXZ\0" +#define HEADER_MAGIC "\3757zXZ" #define HEADER_MAGIC_SIZE 6 #define FOOTER_MAGIC "YZ" -- cgit v1.2.3-55-g6feb From 3a7b2417f9f599a8450c27f84d3330382a2c1b0a Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:26:03 +0100 Subject: xz: update README Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/archival/libarchive/unxz/README b/archival/libarchive/unxz/README index c5972f6b8..9bc1ea0f1 100644 --- a/archival/libarchive/unxz/README +++ b/archival/libarchive/unxz/README @@ -55,7 +55,7 @@ Compiler requirements code is modified not to support large files, which needs some more care than just using 32-bit integer instead of 64-bit). - If you use GCC, try to use a recent version. For example, on x86, + If you use GCC, try to use a recent version. For example, on x86-32, xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when compiled with GCC 4.3.3. @@ -93,7 +93,7 @@ BCJ filter support them always #defined doesn't hurt either. #define Instruction set BCJ filter endianness - XZ_DEC_X86 x86 or x86-64 Little endian only + XZ_DEC_X86 x86-32 or x86-64 Little endian only XZ_DEC_POWERPC PowerPC Big endian only XZ_DEC_IA64 Itanium (IA-64) Big or little endian XZ_DEC_ARM ARM Little endian only -- cgit v1.2.3-55-g6feb From 9056fcecbfe5f16749ddd61f4ddb7dd4905a7ee8 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:28:33 +0100 Subject: xz: avoid "NOTE:" in xz.h Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/xz.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/archival/libarchive/unxz/xz.h b/archival/libarchive/unxz/xz.h index c6c071c4a..6842ed726 100644 --- a/archival/libarchive/unxz/xz.h +++ b/archival/libarchive/unxz/xz.h @@ -70,7 +70,7 @@ enum xz_mode { * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding * is still possible in multi-call mode by simply * calling xz_dec_run() again. - * NOTE: This return value is used only if + * Note that this return value is used only if * XZ_DEC_ANY_CHECK was defined at build time, * which is not used in the kernel. Unsupported * check types return XZ_OPTIONS_ERROR if @@ -105,7 +105,7 @@ enum xz_mode { * stream that is truncated or otherwise corrupt. * * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer - * is too small, or the compressed input is corrupt in a way that makes the + * is too small or the compressed input is corrupt in a way that makes the * decoder produce more output than the caller expected. When it is * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR * is used instead of XZ_BUF_ERROR. @@ -207,8 +207,8 @@ XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( * The possible return values depend on build options and operation mode. * See enum xz_ret for details. * - * NOTE: If an error occurs in single-call mode (return value is not - * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the + * Note that if an error occurs in single-call mode (return value is not + * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the * contents of the output buffer from b->out[b->out_pos] onward are * undefined. This is true even after XZ_BUF_ERROR, because with some filter * chains, there may be a second pass over the output buffer, and this pass -- cgit v1.2.3-55-g6feb From 18714d8460f800476011d83bb956f4457f332acf Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:32:03 +0100 Subject: xz: add a comment about using uint32_t as vli_type Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/xz_stream.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/archival/libarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h index 2ffaa34ea..66cb5a705 100644 --- a/archival/libarchive/unxz/xz_stream.h +++ b/archival/libarchive/unxz/xz_stream.h @@ -32,8 +32,13 @@ #define FOOTER_MAGIC_SIZE 2 /* - * Variable-length integer can hold a 63-bit unsigned integer, or a special - * value to indicate that the value is unknown. + * Variable-length integer can hold a 63-bit unsigned integer or a special + * value indicating that the value is unknown. + * + * Experimental: vli_type can be defined to uint32_t to save a few bytes + * in code size (no effect on speed). Doing so limits the uncompressed and + * compressed size of the file to less than 256 MiB and may also weaken + * error detection slightly. */ typedef uint64_t vli_type; -- cgit v1.2.3-55-g6feb From b967e42b772841fad6c0d4678811efcad218cadd Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:34:06 +0100 Subject: xz: make bcj_x86_test_msbyte() an inline function Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/xz_dec_bcj.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/archival/libarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c index 09162b51f..a01a4cdcf 100644 --- a/archival/libarchive/unxz/xz_dec_bcj.c +++ b/archival/libarchive/unxz/xz_dec_bcj.c @@ -77,10 +77,13 @@ struct xz_dec_bcj { #ifdef XZ_DEC_X86 /* - * This is macro used to test the most significant byte of a memory address + * This is used to test the most significant byte of a memory address * in an x86 instruction. */ -#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF) +static inline int bcj_x86_test_msbyte(uint8_t b) +{ + return b == 0x00 || b == 0xFF; +} static noinline_for_stack size_t XZ_FUNC bcj_x86( struct xz_dec_bcj *s, uint8_t *buf, size_t size) -- cgit v1.2.3-55-g6feb From aada3126a795d9ff406aa3029aee44019d7c0450 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:36:17 +0100 Subject: xz: remove an empty line from xz_dec_lzma2.c Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/xz_dec_lzma2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/archival/libarchive/unxz/xz_dec_lzma2.c b/archival/libarchive/unxz/xz_dec_lzma2.c index da71cb4d4..b6d10af9d 100644 --- a/archival/libarchive/unxz/xz_dec_lzma2.c +++ b/archival/libarchive/unxz/xz_dec_lzma2.c @@ -407,7 +407,6 @@ static void XZ_FUNC dict_uncompressed( b->out_pos += copy_size; b->in_pos += copy_size; - } } -- cgit v1.2.3-55-g6feb From efb800439fd29382404fe8044774903b3b52db3f Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:37:18 +0100 Subject: cz: add C++ support to xz.h Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/xz.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/archival/libarchive/unxz/xz.h b/archival/libarchive/unxz/xz.h index 6842ed726..e0b22db56 100644 --- a/archival/libarchive/unxz/xz.h +++ b/archival/libarchive/unxz/xz.h @@ -19,6 +19,10 @@ # include #endif +#ifdef __cplusplus +extern "C" { +#endif + /* In Linux, this is used to make extern functions static when needed. */ #ifndef XZ_EXTERN # define XZ_EXTERN extern @@ -268,4 +272,9 @@ XZ_EXTERN void XZ_FUNC xz_crc32_init(void); XZ_EXTERN uint32_t XZ_FUNC xz_crc32( const uint8_t *buf, size_t size, uint32_t crc); #endif + +#ifdef __cplusplus +} +#endif + #endif -- cgit v1.2.3-55-g6feb From a1ae2b75a71b4b99948aa0f9a15cf1de52bb40d6 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:38:06 +0100 Subject: xz: fix decoding of LZMA2 streams having no uncompressed data. No .xz encoder creates files with empty LZMA2 streams, but such files would still be valid and decompressors must accept them. Note that empty .xz files are a different thing than empty LZMA2 streams. This bug didn't affect typical .xz files that had no uncompressed data. Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/xz_dec_lzma2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/archival/libarchive/unxz/xz_dec_lzma2.c b/archival/libarchive/unxz/xz_dec_lzma2.c index b6d10af9d..3c2dc88b7 100644 --- a/archival/libarchive/unxz/xz_dec_lzma2.c +++ b/archival/libarchive/unxz/xz_dec_lzma2.c @@ -971,6 +971,9 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( */ tmp = b->in[b->in_pos++]; + if (tmp == 0x00) + return XZ_STREAM_END; + if (tmp >= 0xE0 || tmp == 0x01) { s->lzma2.need_props = true; s->lzma2.need_dict_reset = false; @@ -1003,9 +1006,6 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( lzma_reset(s); } } else { - if (tmp == 0x00) - return XZ_STREAM_END; - if (tmp > 0x02) return XZ_DATA_ERROR; -- cgit v1.2.3-55-g6feb From c3045edec221876596fe910901191720d8f55986 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:39:56 +0100 Subject: xz: fix incorrect XZ_BUF_ERROR xz_dec_run() could incorrectly return XZ_BUF_ERROR if all of the following was true: - The caller knows how many bytes of output to expect and only provides that much output space. - When the last output bytes are decoded, the caller-provided input buffer ends right before the LZMA2 end of payload marker. So LZMA2 won't provide more output anymore, but it won't know it yet and thus won't return XZ_STREAM_END yet. - A BCJ filter is in use and it hasn't left any unfiltered bytes in the temp buffer. This can happen with any BCJ filter, but in practice it's more likely with filters other than the x86 BCJ. This fixes where Squashfs thinks that a valid file system is corrupt. Thanks to Jindrich Novy for telling me that such a bug report exists, Phillip Lougher for providing excellent debug info, and other people on #fedora-ppc. This also fixes a similar bug in single-call mode where the uncompressed size of a XZ Block using BCJ + LZMA2 was 0 bytes and caller provided no output space. Many empty .xz files don't contain any Blocks and thus don't trigger this bug. This also tweaks a closely related detail: xz_dec_bcj_run() could call xz_dec_lzma2_run() to decode into temp buffer when it was known to be useless. This was harmless although it wasted a minuscule number of CPU cycles. Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/xz_dec_bcj.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/archival/libarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c index a01a4cdcf..e0f913a94 100644 --- a/archival/libarchive/unxz/xz_dec_bcj.c +++ b/archival/libarchive/unxz/xz_dec_bcj.c @@ -446,8 +446,12 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, * next filter in the chain. Apply the BCJ filter on the new data * in the output buffer. If everything cannot be filtered, copy it * to temp and rewind the output buffer position accordingly. + * + * This needs to be always run when temp.size == 0 to handle a special + * case where the output buffer is full and the next filter has no + * more output coming but hasn't returned XZ_STREAM_END yet. */ - if (s->temp.size < b->out_size - b->out_pos) { + if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) { out_start = b->out_pos; memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); b->out_pos += s->temp.size; @@ -470,16 +474,25 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, s->temp.size = b->out_pos - out_start; b->out_pos -= s->temp.size; memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); + + /* + * If there wasn't enough input to the next filter to fill + * the output buffer with unfiltered data, there's no point + * to try decoding more data to temp. + */ + if (b->out_pos + s->temp.size < b->out_size) + return XZ_OK; } /* - * If we have unfiltered data in temp, try to fill by decoding more - * data from the next filter. Apply the BCJ filter on temp. Then we - * hopefully can fill the actual output buffer by copying filtered - * data from temp. A mix of filtered and unfiltered data may be left - * in temp; it will be taken care on the next call to this function. + * We have unfiltered data in temp. If the output buffer isn't full + * yet, try to fill the temp buffer by decoding more data from the + * next filter. Apply the BCJ filter on temp. Then we hopefully can + * fill the actual output buffer by copying filtered data from temp. + * A mix of filtered and unfiltered data may be left in temp; it will + * be taken care on the next call to this function. */ - if (s->temp.size > 0) { + if (b->out_pos < b->out_size) { /* Make b->out{,_pos,_size} temporarily point to s->temp. */ s->out = b->out; s->out_pos = b->out_pos; -- cgit v1.2.3-55-g6feb From 433757413f55986681f29ab1335e514e9f0c8423 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 16:41:36 +0100 Subject: xz: mention xzminidec.c in README Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/unxz/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/libarchive/unxz/README b/archival/libarchive/unxz/README index 9bc1ea0f1..a84912035 100644 --- a/archival/libarchive/unxz/README +++ b/archival/libarchive/unxz/README @@ -7,7 +7,7 @@ XZ Embedded XZ Embedded was written for use in the Linux kernel, but the code can be easily used in other environments too, including regular userspace - applications. + applications. See userspace/xzminidec.c for an example program. This README contains information that is useful only when the copy of XZ Embedded isn't part of the Linux kernel tree. You should also -- cgit v1.2.3-55-g6feb From 380c8a0763462692eef8d00df4872a561ff7aa7b Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 27 Feb 2013 17:26:40 +0100 Subject: xz: support concatenated .xz streams function old new delta xz_dec_reset - 77 +77 unpack_xz_stream 2402 2397 -5 Signed-off-by: Lasse Collin Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_unxz.c | 43 +++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index 79b48a152..e9ddd3709 100644 --- a/archival/libarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c @@ -40,6 +40,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) IF_DESKTOP(long long) int FAST_FUNC unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { + enum xz_ret xz_result; struct xz_buf iobuf; struct xz_dec *state; unsigned char *membuf; @@ -63,9 +64,8 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) /* Limit memory usage to about 64 MiB. */ state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); + xz_result = X_OK; while (1) { - enum xz_ret r; - if (iobuf.in_pos == iobuf.in_size) { int rd = safe_read(src_fd, membuf, BUFSIZ); if (rd < 0) { @@ -73,28 +73,57 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) total = -1; break; } + if (rd == 0 && xz_result == XZ_STREAM_END) + break; iobuf.in_size = rd; iobuf.in_pos = 0; } + if (xz_result == XZ_STREAM_END) { + /* + * Try to start decoding next concatenated stream. + * Stream padding must always be a multiple of four + * bytes to preserve four-byte alignment. To keep the + * code slightly smaller, we aren't as strict here as + * the .xz spec requires. We just skip all zero-bytes + * without checking the alignment and thus can accept + * files that aren't valid, e.g. the XZ utils test + * files bad-0pad-empty.xz and bad-0catpad-empty.xz. + */ + do { + if (membuf[iobuf.in_pos] != 0) { + xz_dec_reset(state); + goto do_run; + } + iobuf.in_pos++; + } while (iobuf.in_pos < iobuf.in_size); + } + do_run: // bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); - r = xz_dec_run(state, &iobuf); + xz_result = xz_dec_run(state, &iobuf); // bb_error_msg(" Date: Wed, 27 Feb 2013 18:30:05 +0100 Subject: lineedit: initialize delptr In vi mode, the 'p' and 'P' commands caused a segfault when nothing had been put in the buffer yet because the delptr was not initialized. Signed-off-by: Shawn J. Goff Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index dbe616466..52b49e8a9 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -187,6 +187,7 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics; cmdedit_termw = 80; \ IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \ IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ + IF_FEATURE_EDITING_VI(delptr = delbuf;) \ } while (0) static void deinit_S(void) -- cgit v1.2.3-55-g6feb From f59d563399be3d9af3e7b4673e13905d28f2339b Mon Sep 17 00:00:00 2001 From: Leonid Lisovskiy Date: Wed, 27 Feb 2013 18:32:58 +0100 Subject: xz: fix put_unaligned_{l,b}e32 Signed-off-by: Leonid Lisovskiy Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_unxz.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c index e9ddd3709..986b7b191 100644 --- a/archival/libarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c @@ -30,8 +30,8 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) /* We use arch-optimized unaligned accessors */ #define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) #define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) -#define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) -#define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) +#define put_unaligned_le32(val, buf) move_to_unaligned32(buf, SWAP_LE32(val)) +#define put_unaligned_be32(val, buf) move_to_unaligned32(buf, SWAP_BE32(val)) #include "unxz/xz_dec_bcj.c" #include "unxz/xz_dec_lzma2.c" -- cgit v1.2.3-55-g6feb From 0496e824a5b97edc9991f62c7c74f9b24b16edc7 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 28 Feb 2013 09:59:23 +0100 Subject: run-parts: add --exit-on-error | -e support The "big" run-parts supports a handy --exit-on-error to stop execution on errors, so lets support it as well. Upstream doesn't have a short option for it, but I've used '-e' for busybox. Signed-off-by: Peter Korsgaard Signed-off-by: Denys Vlasenko --- debianutils/run_parts.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index 005b30420..6be83edf9 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c @@ -27,10 +27,11 @@ * -a ARG argument. Pass ARG as an argument the program executed. It can * be repeated to pass multiple arguments. * -u MASK umask. Set the umask of the program executed to MASK. + * -e exit as soon as a script returns with a non-zero exit code */ //usage:#define run_parts_trivial_usage -//usage: "[-t"IF_FEATURE_RUN_PARTS_FANCY("l")"] [-a ARG]... [-u MASK] DIRECTORY" +//usage: "[-t"IF_FEATURE_RUN_PARTS_FANCY("l")"] [-a ARG]... [-u MASK] [-e] DIRECTORY" //usage:#define run_parts_full_usage "\n\n" //usage: "Run a bunch of scripts in DIRECTORY\n" //usage: "\n -t Dry run" @@ -39,6 +40,7 @@ //usage: ) //usage: "\n -a ARG Pass ARG as argument to programs" //usage: "\n -u MASK Set umask to MASK before running programs" +//usage: "\n -e Exit as soon as a script returns with a non-zero exit code" //usage: //usage:#define run_parts_example_usage //usage: "$ run-parts -a start /etc/init.d\n" @@ -74,7 +76,8 @@ enum { OPT_a = (1 << 1), OPT_u = (1 << 2), OPT_t = (1 << 3), - OPT_l = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_FANCY, + OPT_e = (1 << 4), + OPT_l = (1 << 5) * ENABLE_FEATURE_RUN_PARTS_FANCY, }; #if ENABLE_FEATURE_RUN_PARTS_FANCY @@ -127,6 +130,7 @@ static const char runparts_longopts[] ALIGN1 = "arg\0" Required_argument "a" "umask\0" Required_argument "u" "test\0" No_argument "t" + "exit-on-error\0" No_argument "e" #if ENABLE_FEATURE_RUN_PARTS_FANCY "list\0" No_argument "l" "reverse\0" No_argument "r" @@ -150,7 +154,7 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) #endif /* We require exactly one argument: the directory name */ opt_complementary = "=1:a::"; - getopt32(argv, "ra:u:t"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p); + getopt32(argv, "ra:u:te"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p); umask(xstrtou_range(umask_p, 8, 0, 07777)); @@ -193,6 +197,9 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) bb_perror_msg("can't execute '%s'", name); else /* ret > 0 */ bb_error_msg("%s exited with code %d", name, ret & 0xff); + + if (option_mask32 & OPT_e) + xfunc_die(); } return n; -- cgit v1.2.3-55-g6feb From 1e43a381b20f74ff3ff911daa28c9c9c799bcd82 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 10:22:49 +0100 Subject: run-parts: stop providing incompatible short options Signed-off-by: Denys Vlasenko --- debianutils/run_parts.c | 57 ++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index 6be83edf9..916aa90e0 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c @@ -21,26 +21,24 @@ * taken from debian-utils. I've only removed the long options and the * report mode. As the original run-parts support only long options, I've * broken compatibility because the BusyBox policy doesn't allow them. - * The supported options are: - * -t test. Print the name of the files to be executed, without - * execute them. - * -a ARG argument. Pass ARG as an argument the program executed. It can - * be repeated to pass multiple arguments. - * -u MASK umask. Set the umask of the program executed to MASK. - * -e exit as soon as a script returns with a non-zero exit code */ //usage:#define run_parts_trivial_usage -//usage: "[-t"IF_FEATURE_RUN_PARTS_FANCY("l")"] [-a ARG]... [-u MASK] [-e] DIRECTORY" +//usage: "[-a ARG]... [-u UMASK] " +//usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS("[--reverse] [--test] [-−exit−on−error] "IF_FEATURE_RUN_PARTS_FANCY("[--list] ")) +//usage: "DIRECTORY" //usage:#define run_parts_full_usage "\n\n" //usage: "Run a bunch of scripts in DIRECTORY\n" -//usage: "\n -t Dry run" +//usage: "\n -a ARG Pass ARG as argument to scripts" +//usage: "\n -u UMASK Set UMASK before running scripts" +//usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS( +//usage: "\n -−reverse Reverse execution order" +//usage: "\n --test Dry run" +//usage: "\n -−exit−on−error Exit if a script exits with non-zero" //usage: IF_FEATURE_RUN_PARTS_FANCY( -//usage: "\n -l Print names of matching files even if they are not executable" +//usage: "\n --list Print names of matching files even if they are not executable" +//usage: ) //usage: ) -//usage: "\n -a ARG Pass ARG as argument to programs" -//usage: "\n -u MASK Set umask to MASK before running programs" -//usage: "\n -e Exit as soon as a script returns with a non-zero exit code" //usage: //usage:#define run_parts_example_usage //usage: "$ run-parts -a start /etc/init.d\n" @@ -72,20 +70,15 @@ struct globals { enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 }; enum { - OPT_r = (1 << 0), - OPT_a = (1 << 1), - OPT_u = (1 << 2), - OPT_t = (1 << 3), - OPT_e = (1 << 4), - OPT_l = (1 << 5) * ENABLE_FEATURE_RUN_PARTS_FANCY, + OPT_a = (1 << 0), + OPT_u = (1 << 1), + OPT_r = (1 << 2) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, + OPT_t = (1 << 3) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, + OPT_e = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, + OPT_l = (1 << 5) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS + * ENABLE_FEATURE_RUN_PARTS_FANCY, }; -#if ENABLE_FEATURE_RUN_PARTS_FANCY -#define list_mode (option_mask32 & OPT_l) -#else -#define list_mode 0 -#endif - /* Is this a valid filename (upper/lower alpha, digits, * underscores, and hyphens only?) */ @@ -113,7 +106,7 @@ static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUS if (depth == 2 && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK)) || invalid_name(file) - || (!list_mode && access(file, X_OK) != 0)) + || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0)) ) { return SKIP; } @@ -129,12 +122,12 @@ static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUS static const char runparts_longopts[] ALIGN1 = "arg\0" Required_argument "a" "umask\0" Required_argument "u" - "test\0" No_argument "t" - "exit-on-error\0" No_argument "e" -#if ENABLE_FEATURE_RUN_PARTS_FANCY - "list\0" No_argument "l" - "reverse\0" No_argument "r" //TODO: "verbose\0" No_argument "v" + "reverse\0" No_argument "\xf0" + "test\0" No_argument "\xf1" + "exit-on-error\0" No_argument "\xf2" +#if ENABLE_FEATURE_RUN_PARTS_FANCY + "list\0" No_argument "\xf3" #endif ; #endif @@ -154,7 +147,7 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) #endif /* We require exactly one argument: the directory name */ opt_complementary = "=1:a::"; - getopt32(argv, "ra:u:te"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p); + getopt32(argv, "a:u:", &arg_list, &umask_p); umask(xstrtou_range(umask_p, 8, 0, 07777)); -- cgit v1.2.3-55-g6feb From bc0ffc0e971c61dc7f09aab2a35966f99cc606ba Mon Sep 17 00:00:00 2001 From: Thomas De Schampheleire Date: Thu, 28 Feb 2013 10:31:54 +0100 Subject: nameif: fix use-after-free in ENABLE_FEATURE_CLEAN_UP code Signed-off-by: Thomas De Schampheleire Signed-off-by: Denys Vlasenko --- networking/nameif.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/networking/nameif.c b/networking/nameif.c index 5d7e8f9a4..9a8846dc0 100644 --- a/networking/nameif.c +++ b/networking/nameif.c @@ -292,12 +292,11 @@ int nameif_main(int argc UNUSED_PARAM, char **argv) if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0) continue; /* if we came here, all selectors have matched */ - break; + goto found; } /* Nothing found for current interface */ - if (!ch) - continue; - + continue; + found: if (strcmp(ifr.ifr_name, ch->ifname) != 0) { strcpy(ifr.ifr_newname, ch->ifname); ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr, @@ -313,10 +312,14 @@ int nameif_main(int argc UNUSED_PARAM, char **argv) ch->next->prev = ch->prev; if (ENABLE_FEATURE_CLEAN_UP) delete_eth_table(ch); - } + } /* while */ + if (ENABLE_FEATURE_CLEAN_UP) { - for (ch = clist; ch; ch = ch->next) + ethtable_t *next; + for (ch = clist; ch; ch = next) { + next = ch->next; delete_eth_table(ch); + } config_close(parser); }; -- cgit v1.2.3-55-g6feb From a14f319805c288db25cc9feac3048d89f3d7b41a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 11:09:14 +0100 Subject: nc: don't redirect stderr to network in -e PROG mode This in incompatible with nc-1.10, but makes a lot of sense. Signed-off-by: Denys Vlasenko --- networking/nc.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/networking/nc.c b/networking/nc.c index 0c843a686..8cb4b306e 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -24,7 +24,7 @@ //config: Allow netcat to act as a server. //config: //config:config NC_EXTRA -//config: bool "Netcat extensions (-eiw and filename)" +//config: bool "Netcat extensions (-eiw and -f FILE)" //config: default y //config: depends on NC //config: help @@ -60,17 +60,18 @@ //usage:#define nc_full_usage "\n\n" //usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE") //usage: NC_OPTIONS_STR -//usage: IF_NC_EXTRA( -//usage: "\n -e PROG Run PROG after connect" //usage: IF_NC_SERVER( //usage: "\n -l Listen mode, for inbound connects" //usage: IF_NC_EXTRA( -//usage: "\n (use -l twice with -e for persistent server)") +//usage: "\n (use -ll with -e for persistent server)" +//usage: ) //usage: "\n -p PORT Local port" //usage: ) -//usage: "\n -w SEC Timeout for connect" +//usage: IF_NC_EXTRA( +//usage: "\n -w SEC Connect timeout" //usage: "\n -i SEC Delay interval for lines sent" //usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network" +//usage: "\n -e PROG Run PROG after connect" //usage: ) //usage: //usage:#define nc_notes_usage "" @@ -147,7 +148,7 @@ int nc_main(int argc, char **argv) *p++ = argv[optind++]; } ) - /* optind points to argv[arvc] (NULL) now. + /* optind points to argv[argc] (NULL) now. ** FIXME: we assume that getopt will not count options ** possibly present on "-e PROG ARGS" and will not ** include them into final value of optind @@ -226,10 +227,9 @@ int nc_main(int argc, char **argv) /* child, or main thread if only one -l */ xmove_fd(cfd, 0); xdup2(0, 1); - xdup2(0, 2); + /*xdup2(0, 2); - original nc 1.10 does this, we don't */ IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) - /* Don't print stuff or it will go over the wire... */ - _exit(127); + bb_perror_msg_and_die("can't execute '%s'", execparam[0]); } /* Select loop copying stdin to cfd, and cfd to stdout */ -- cgit v1.2.3-55-g6feb From de6f14800675cd0401106876da81da7618de71c6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 12:20:06 +0100 Subject: nc_bloaty: support -ll and -lk. Closes 2245 Signed-off-by: Denys Vlasenko --- networking/nc_bloaty.c | 58 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index 62a025116..00ba6f114 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c @@ -63,6 +63,12 @@ //usage: " -e PROG Run PROG after connect (must be last)" //usage: IF_NC_SERVER( //usage: "\n -l Listen mode, for inbound connects" +//usage: "\n -lk With -e, provides persistent server" +/* -ll does the same as -lk, but its our extension, while -k is BSD'd, + * presumably more widely known. Therefore we advertise it, not -ll. + * I would like to drop -ll support, but our "small" nc supports it, + * and Rob uses it. + */ //usage: ) //usage: "\n -p PORT Local port" //usage: "\n -s ADDR Local address" @@ -166,18 +172,14 @@ enum { OPT_v = (1 << 4), OPT_w = (1 << 5), OPT_l = (1 << 6) * ENABLE_NC_SERVER, - OPT_i = (1 << (6+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, - OPT_o = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, - OPT_z = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_k = (1 << 7) * ENABLE_NC_SERVER, + OPT_i = (1 << (7+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_o = (1 << (8+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_z = (1 << (9+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, }; #define o_nflag (option_mask32 & OPT_n) #define o_udpmode (option_mask32 & OPT_u) -#if ENABLE_NC_SERVER -#define o_listen (option_mask32 & OPT_l) -#else -#define o_listen 0 -#endif #if ENABLE_NC_EXTRA #define o_ofile (option_mask32 & OPT_o) #define o_zero (option_mask32 & OPT_z) @@ -298,7 +300,7 @@ static int connect_w_timeout(int fd) incoming and returns an open connection *from* someplace. If we were given host/port args, any connections from elsewhere are rejected. This in conjunction with local-address binding should limit things nicely... */ -static void dolisten(void) +static void dolisten(int is_persistent, char **proggie) { int rr; @@ -371,6 +373,7 @@ create new one, and bind() it. TODO */ xconnect(netfd, &remend.u.sa, ouraddr->len); } else { /* TCP */ + another: arm(o_wait); /* wrap this in a timer, too; 0 = forever */ if (setjmp(jbuf) == 0) { again: @@ -405,6 +408,19 @@ create new one, and bind() it. TODO */ unarm(); } else bb_error_msg_and_die("timeout"); + + if (is_persistent && proggie) { + /* -l -k -e PROG */ + signal(SIGCHLD, SIG_IGN); /* no zombies please */ + if (xvfork() != 0) { + /* parent: go back and accept more connections */ + close(rr); + goto another; + } + /* child */ + signal(SIGCHLD, SIG_DFL); + } + xmove_fd(rr, netfd); /* dump the old socket, here's our new one */ /* find out what address the connection was *to* on our end, in case we're doing a listen-on-any on a multihomed machine. This allows one to @@ -454,6 +470,9 @@ create new one, and bind() it. TODO */ if (!o_nflag) free(remhostname); } + + if (proggie) + doexec(proggie); } /* udptest: @@ -730,6 +749,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) char *themdotted = themdotted; /* for compiler */ char **proggie; int x; + unsigned cnt_l = 0; unsigned o_lport = 0; INIT_G(); @@ -760,7 +780,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) if (proggie[0][0] == '-') { char *optpos = *proggie + 1; /* Skip all valid opts w/o params */ - optpos = optpos + strspn(optpos, "nuv"IF_NC_SERVER("l")IF_NC_EXTRA("z")); + optpos = optpos + strspn(optpos, "nuv"IF_NC_SERVER("lk")IF_NC_EXTRA("z")); if (*optpos == 'e' && !optpos[1]) { *optpos = '\0'; proggie++; @@ -774,17 +794,21 @@ int nc_main(int argc UNUSED_PARAM, char **argv) e_found: // -g -G -t -r deleted, unimplemented -a deleted too - opt_complementary = "?2:vv:w+"; /* max 2 params; -v is a counter; -w N */ - getopt32(argv, "np:s:uvw:" IF_NC_SERVER("l") + opt_complementary = "?2:vv:ll:w+"; /* max 2 params; -v and -l are counters; -w N */ + getopt32(argv, "np:s:uvw:" IF_NC_SERVER("lk") IF_NC_EXTRA("i:o:z"), &str_p, &str_s, &o_wait - IF_NC_EXTRA(, &str_i, &str_o), &o_verbose); + IF_NC_EXTRA(, &str_i, &str_o), &o_verbose IF_NC_SERVER(, &cnt_l)); argv += optind; #if ENABLE_NC_EXTRA if (option_mask32 & OPT_i) /* line-interval time */ o_interval = xatou_range(str_i, 1, 0xffff); #endif +#if ENABLE_NC_SERVER //if (option_mask32 & OPT_l) /* listen mode */ + if (option_mask32 & OPT_k) /* persistent server mode */ + cnt_l = 2; +#endif //if (option_mask32 & OPT_n) /* numeric-only, no DNS lookups */ //if (option_mask32 & OPT_o) /* hexdump log */ if (option_mask32 & OPT_p) { /* local source port */ @@ -833,7 +857,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) if (o_udpmode) socket_want_pktinfo(netfd); if (!ENABLE_FEATURE_UNIX_LOCAL - || o_listen + || cnt_l != 0 /* listen */ || ouraddr->u.sa.sa_family != AF_UNIX ) { xbind(netfd, &ouraddr->u.sa, ouraddr->len); @@ -862,11 +886,9 @@ int nc_main(int argc UNUSED_PARAM, char **argv) xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), ofd); #endif - if (o_listen) { - dolisten(); + if (cnt_l != 0) { + dolisten((cnt_l - 1), proggie); /* dolisten does its own connect reporting */ - if (proggie) /* -e given? */ - doexec(proggie); x = readwrite(); /* it even works with UDP! */ } else { /* Outbound connects. Now we're more picky about args... */ -- cgit v1.2.3-55-g6feb From 5d1c599d7611b6202190460ebc685e5fb1ae61ea Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 28 Feb 2013 12:25:49 +0100 Subject: run-parts: fix unicode creep in --help Signed-off-by: Peter Korsgaard Signed-off-by: Denys Vlasenko --- debianutils/run_parts.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index 916aa90e0..2c2b032be 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c @@ -25,16 +25,16 @@ //usage:#define run_parts_trivial_usage //usage: "[-a ARG]... [-u UMASK] " -//usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS("[--reverse] [--test] [-−exit−on−error] "IF_FEATURE_RUN_PARTS_FANCY("[--list] ")) +//usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS("[--reverse] [--test] [--exit-on-error] "IF_FEATURE_RUN_PARTS_FANCY("[--list] ")) //usage: "DIRECTORY" //usage:#define run_parts_full_usage "\n\n" //usage: "Run a bunch of scripts in DIRECTORY\n" //usage: "\n -a ARG Pass ARG as argument to scripts" //usage: "\n -u UMASK Set UMASK before running scripts" //usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS( -//usage: "\n -−reverse Reverse execution order" +//usage: "\n --reverse Reverse execution order" //usage: "\n --test Dry run" -//usage: "\n -−exit−on−error Exit if a script exits with non-zero" +//usage: "\n --exit-on-error Exit if a script exits with non-zero" //usage: IF_FEATURE_RUN_PARTS_FANCY( //usage: "\n --list Print names of matching files even if they are not executable" //usage: ) -- cgit v1.2.3-55-g6feb From efd0698f74caab0a0c8a51228b923ee142e8e278 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 12:34:18 +0100 Subject: make --help return exitcode 0. Closes 5612 Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 67df44690..c22686e55 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -750,7 +750,7 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) //TODO: just compare applet_no with APPLET_NO_test if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) { /* If you want "foo --help" to return 0: */ - /*xfunc_error_retval = 0;*/ + xfunc_error_retval = 0; bb_show_usage(); } } -- cgit v1.2.3-55-g6feb From ed954b68552efb0c496f01fc9de28a4adf0f2404 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 12:39:27 +0100 Subject: Fix config help text Signed-off-by: Denys Vlasenko --- networking/nc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/nc.c b/networking/nc.c index 8cb4b306e..5f4cb89cc 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -40,7 +40,7 @@ //config: This option makes nc closely follow original nc-1.10. //config: The code is about 2.5k bigger. It enables //config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses -//config: busybox-specific extensions: -f FILE and -ll. +//config: busybox-specific extensions: -f FILE. #if ENABLE_NC_110_COMPAT # include "nc_bloaty.c" -- cgit v1.2.3-55-g6feb From 47f8558eee4caa30078daaa669f37d7cc77163fd Mon Sep 17 00:00:00 2001 From: Bernhard Walle Date: Thu, 28 Feb 2013 12:42:38 +0100 Subject: pgrep: fix -x option Because when -x is used (exact match), then we cannot compile the regular expression with REG_NOSUB. The manual page regcomp(3) states in section "Byte offsets": Unless REG_NOSUB was set for the compilation of the pattern buffer, it is possible to obtain substring match addressing information. The problem was detected on an ARM system with glibc 2.16. Signed-off-by: Bernhard Walle Signed-off-by: Denys Vlasenko --- procps/pgrep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procps/pgrep.c b/procps/pgrep.c index dc7ffff48..7616027b7 100644 --- a/procps/pgrep.c +++ b/procps/pgrep.c @@ -128,7 +128,7 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); if (argv[0]) - xregcomp(&re_buffer, argv[0], REG_EXTENDED | REG_NOSUB); + xregcomp(&re_buffer, argv[0], OPT_ANCHOR ? REG_EXTENDED : (REG_EXTENDED|REG_NOSUB); matched_pid = 0; cmd_last = NULL; -- cgit v1.2.3-55-g6feb From 216e952fb86b1eb3ac29701225d03e4690ac9561 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 12:50:09 +0100 Subject: ifplugd: make -k send SIGINT, not SIGQUIT Signed-off-by: Denys Vlasenko --- networking/ifplugd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/networking/ifplugd.c b/networking/ifplugd.c index 86586f0fe..3cdc2c9d2 100644 --- a/networking/ifplugd.c +++ b/networking/ifplugd.c @@ -556,7 +556,8 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) if (opts & FLAG_KILL) { if (pid_from_pidfile > 0) - kill(pid_from_pidfile, SIGQUIT); + /* Upstream tool use SIGINT for -k */ + kill(pid_from_pidfile, SIGINT); return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From 7794c21daf452912275f0f51d6edd4614c43eccf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 15:51:55 +0100 Subject: pgrep: fix a "missing closing paren" build error Signed-off-by: Denys Vlasenko --- procps/pgrep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procps/pgrep.c b/procps/pgrep.c index 7616027b7..8daf5b28a 100644 --- a/procps/pgrep.c +++ b/procps/pgrep.c @@ -128,7 +128,7 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); if (argv[0]) - xregcomp(&re_buffer, argv[0], OPT_ANCHOR ? REG_EXTENDED : (REG_EXTENDED|REG_NOSUB); + xregcomp(&re_buffer, argv[0], OPT_ANCHOR ? REG_EXTENDED : (REG_EXTENDED|REG_NOSUB)); matched_pid = 0; cmd_last = NULL; -- cgit v1.2.3-55-g6feb From 577235dee826eed86d76b0d4ef866297a20ecd55 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 16:38:25 +0100 Subject: code shrink in check_errors_in_children() Signed-off-by: Denys Vlasenko --- archival/libarchive/open_transformer.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index dae04aa57..4e44a87e9 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -34,6 +34,7 @@ void check_errors_in_children(int signo) if (!signo) { /* block waiting for any child */ if (wait(&status) < 0) +//FIXME: check EINTR? return; /* probably there are no children */ goto check_status; } @@ -41,14 +42,18 @@ void check_errors_in_children(int signo) /* Wait for any child without blocking */ for (;;) { if (wait_any_nohang(&status) < 0) +//FIXME: check EINTR? /* wait failed?! I'm confused... */ return; check_status: - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/ + /* On Linux, the above can be checked simply as: */ + if (status == 0) /* this child exited with 0 */ continue; - /* Cannot happen? - if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */ + /* Cannot happen: + if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; + */ bb_got_signal = 1; } } -- cgit v1.2.3-55-g6feb From f2d8478e560fd77b45dbea7993d6219a5b635b2e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 18:04:22 +0100 Subject: fix error message on failure to oen /dev/null; fix zcat's help text Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 94d8a81c9..46f99cf78 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -68,7 +68,7 @@ int FAST_FUNC bbunpack(char **argv, if (option_mask32 & (OPT_STDOUT|OPT_TEST)) { if (option_mask32 & OPT_TEST) if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0)) - goto err; + xfunc_die(); filename = NULL; } @@ -93,7 +93,7 @@ int FAST_FUNC bbunpack(char **argv, } /* Check that the input is sane */ - if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) { + if (!(option_mask32 & OPT_FORCE) && isatty(STDIN_FILENO)) { bb_error_msg_and_die("compressed data not read from terminal, " "use -f to force it"); } @@ -241,7 +241,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) //usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" //usage: //usage:#define zcat_trivial_usage -//usage: "FILE" +//usage: "[FILE]..." //usage:#define zcat_full_usage "\n\n" //usage: "Decompress to stdout" @@ -316,7 +316,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) //usage: "\n -c Write to stdout" //usage: "\n -f Force" //usage:#define bzcat_trivial_usage -//usage: "FILE" +//usage: "[FILE]..." //usage:#define bzcat_full_usage "\n\n" //usage: "Decompress to stdout" //applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) @@ -365,7 +365,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) //usage: "\n -f Force" //usage: //usage:#define lzcat_trivial_usage -//usage: "FILE" +//usage: "[FILE]..." //usage:#define lzcat_full_usage "\n\n" //usage: "Decompress to stdout" //usage: @@ -385,7 +385,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) //usage: "\n -f Force" //usage: //usage:#define xzcat_trivial_usage -//usage: "FILE" +//usage: "[FILE]..." //usage:#define xzcat_full_usage "\n\n" //usage: "Decompress to stdout" -- cgit v1.2.3-55-g6feb From 8e96efa32314ec5a4e6ace9a6fe7a1694e2e7d90 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 18:06:09 +0100 Subject: zcat: if seamless uncompressors are defined, autodetect file's format function old new delta bbunpack 526 622 +96 packed_usage 29335 29341 +6 gunzip_main 64 67 +3 Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 54 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 46f99cf78..54dc2f5f1 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -14,6 +14,7 @@ enum { OPT_VERBOSE = 1 << 2, OPT_DECOMPRESS = 1 << 3, OPT_TEST = 1 << 4, + SEAMLESS_MAGIC = (1 << 31) * SEAMLESS_COMPRESSION, }; static @@ -39,7 +40,7 @@ int FAST_FUNC bbunpack(char **argv, ) { struct stat stat_buf; - IF_DESKTOP(long long) int status; + IF_DESKTOP(long long) int status = 0; char *filename, *new_name; smallint exitcode = 0; transformer_aux_data_t aux; @@ -54,14 +55,23 @@ int FAST_FUNC bbunpack(char **argv, /* Open src */ if (filename) { - if (stat(filename, &stat_buf) != 0) { - bb_simple_perror_msg(filename); + if (!(option_mask32 & SEAMLESS_MAGIC)) { + if (stat(filename, &stat_buf) != 0) { + err_name: + bb_simple_perror_msg(filename); err: - exitcode = 1; - goto free_name; + exitcode = 1; + goto free_name; + } + if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) + goto err; + } else { + /* "clever zcat" */ + int fd = open_zipped(filename); + if (fd < 0) + goto err_name; + xmove_fd(fd, STDIN_FILENO); } - if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) - goto err; } /* Special cases: test, stdout */ @@ -98,11 +108,23 @@ int FAST_FUNC bbunpack(char **argv, "use -f to force it"); } - init_transformer_aux_data(&aux); - aux.check_signature = 1; - status = unpacker(&aux); - if (status < 0) - exitcode = 1; + if (!(option_mask32 & SEAMLESS_MAGIC)) { + init_transformer_aux_data(&aux); + aux.check_signature = 1; + status = unpacker(&aux); + if (status < 0) + exitcode = 1; + } else { + /* "clever zcat" */ + if (!filename) { + if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_detected*/ 0)) + goto err; + } + if (bb_copyfd_eof(STDIN_FILENO, STDOUT_FILENO) < 0) { + /* Disk full, tty closed, etc. No point in continuing */ + xfunc_die(); + } + } if (!(option_mask32 & OPT_STDOUT)) xclose(STDOUT_FILENO); /* with error check! */ @@ -294,9 +316,13 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) { getopt32(argv, "cfvdtn"); argv += optind; - /* if called as zcat */ + + /* If called as zcat... + * Normally, "zcat" is just "gunzip -c". + * But if seamless magic is enabled, then we are much more clever. + */ if (applet_name[1] == 'c') - option_mask32 |= OPT_STDOUT; + option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC; return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL); } -- cgit v1.2.3-55-g6feb From 41655438c6b61d05ddf3619f31abc1fa3583e2be Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 18:37:04 +0100 Subject: zcat: fix "zcat FILE" trying to do detection twice Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 54dc2f5f1..d59c65571 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -66,12 +66,17 @@ int FAST_FUNC bbunpack(char **argv, if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) goto err; } else { - /* "clever zcat" */ + /* "clever zcat" with FILE */ int fd = open_zipped(filename); if (fd < 0) goto err_name; xmove_fd(fd, STDIN_FILENO); } + } else + if (option_mask32 & SEAMLESS_MAGIC) { + /* "clever zcat" on stdin */ + if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_detected*/ 0)) + goto err; } /* Special cases: test, stdout */ @@ -115,15 +120,9 @@ int FAST_FUNC bbunpack(char **argv, if (status < 0) exitcode = 1; } else { - /* "clever zcat" */ - if (!filename) { - if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_detected*/ 0)) - goto err; - } - if (bb_copyfd_eof(STDIN_FILENO, STDOUT_FILENO) < 0) { + if (bb_copyfd_eof(STDIN_FILENO, STDOUT_FILENO) < 0) /* Disk full, tty closed, etc. No point in continuing */ xfunc_die(); - } } if (!(option_mask32 & OPT_STDOUT)) -- cgit v1.2.3-55-g6feb From fb036636195be64b1a1471fc7cb2d4c3bf53a348 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Feb 2013 19:01:28 +0100 Subject: ifupdown: support "source" stanza in /etc/network/interfaces Signed-off-by: Denys Vlasenko --- networking/ifupdown.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 818048284..0f0857cb4 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -743,7 +743,7 @@ static const struct method_t *get_method(const struct address_family_t *af, char return NULL; } -static struct interfaces_file_t *read_interfaces(const char *filename) +static struct interfaces_file_t *read_interfaces(const char *filename, struct interfaces_file_t *defn) { /* Let's try to be compatible. * @@ -758,19 +758,25 @@ static struct interfaces_file_t *read_interfaces(const char *filename) * be ignored. Blank lines are ignored. Lines may be indented freely. * A "\" character at the very end of the line indicates the next line * should be treated as a continuation of the current one. + * + * Lines beginning with "source" are used to include stanzas from + * other files, so configuration can be split into many files. + * The word "source" is followed by the path of file to be sourced. */ #if ENABLE_FEATURE_IFUPDOWN_MAPPING struct mapping_defn_t *currmap = NULL; #endif struct interface_defn_t *currif = NULL; - struct interfaces_file_t *defn; FILE *f; char *buf; char *first_word; char *rest_of_line; enum { NONE, IFACE, MAPPING } currently_processing = NONE; - defn = xzalloc(sizeof(*defn)); + if (!defn) + defn = xzalloc(sizeof(*defn)); + + debug_noise("reading %s file:\n", filename); f = xfopen_for_read(filename); while ((buf = xmalloc_fgetline(f)) != NULL) { @@ -881,6 +887,8 @@ static struct interfaces_file_t *read_interfaces(const char *filename) debug_noise("\nauto %s\n", first_word); } currently_processing = NONE; + } else if (strcmp(first_word, "source") == 0) { + read_interfaces(next_word(&rest_of_line), defn); } else { switch (currently_processing) { case IFACE: @@ -934,6 +942,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename) bb_error_msg_and_die("%s: I/O error", filename); } fclose(f); + debug_noise("\ndone reading %s\n\n", filename); return defn; } @@ -1199,9 +1208,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) if (!DO_ALL) bb_show_usage(); } - debug_noise("reading %s file:\n", interfaces); - defn = read_interfaces(interfaces); - debug_noise("\ndone reading %s\n\n", interfaces); + defn = read_interfaces(interfaces, NULL); /* Create a list of interfaces to work on */ if (DO_ALL) { -- cgit v1.2.3-55-g6feb From 920c1baab7e64dc3d46a8413b66c29b81d5d9bdf Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 28 Feb 2013 17:21:50 -0500 Subject: bbunzip: ignore the -q flag with the decompressors The -q flag is used in shell scripts for suppressing output. Have our applets swallow the flag for compatibility. Reported-by: Mandeep Singh Baines Signed-off-by: Mike Frysinger --- archival/bbunzip.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index d59c65571..bc0f62733 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -12,8 +12,9 @@ enum { OPT_FORCE = 1 << 1, /* only some decompressors: */ OPT_VERBOSE = 1 << 2, - OPT_DECOMPRESS = 1 << 3, - OPT_TEST = 1 << 4, + OPT_QUIET = 1 << 3, + OPT_DECOMPRESS = 1 << 4, + OPT_TEST = 1 << 5, SEAMLESS_MAGIC = (1 << 31) * SEAMLESS_COMPRESSION, }; @@ -313,7 +314,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux) int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int gunzip_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "cfvdtn"); + getopt32(argv, "cfvdtqn"); argv += optind; /* If called as zcat... @@ -355,7 +356,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux) int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "cfvdt"); + getopt32(argv, "cfvdtq"); argv += optind; if (applet_name[2] == 'c') /* bzcat */ option_mask32 |= OPT_STDOUT; @@ -423,7 +424,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux) int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) { - IF_LZMA(int opts =) getopt32(argv, "cfvdt"); + IF_LZMA(int opts =) getopt32(argv, "cfvdtq"); # if ENABLE_LZMA /* lzma without -d or -t? */ if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) @@ -448,7 +449,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux) int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) { - IF_XZ(int opts =) getopt32(argv, "cfvdt"); + IF_XZ(int opts =) getopt32(argv, "cfvdtq"); # if ENABLE_XZ /* xz without -d or -t? */ if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) -- cgit v1.2.3-55-g6feb From 08e28e806dc6afdd1de5dac3f1471fd0310bf02b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 28 Feb 2013 21:28:21 -0500 Subject: bbunzip: fix order of flags vs bit defines Too much code shuffling. Reported-by: Mandeep Singh Baines Signed-off-by: Mike Frysinger --- archival/bbunzip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index bc0f62733..fe3b29b78 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -314,7 +314,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux) int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int gunzip_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "cfvdtqn"); + getopt32(argv, "cfvqdtn"); argv += optind; /* If called as zcat... @@ -356,7 +356,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux) int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "cfvdtq"); + getopt32(argv, "cfvqdt"); argv += optind; if (applet_name[2] == 'c') /* bzcat */ option_mask32 |= OPT_STDOUT; @@ -424,7 +424,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux) int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) { - IF_LZMA(int opts =) getopt32(argv, "cfvdtq"); + IF_LZMA(int opts =) getopt32(argv, "cfvqdt"); # if ENABLE_LZMA /* lzma without -d or -t? */ if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) @@ -449,7 +449,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux) int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) { - IF_XZ(int opts =) getopt32(argv, "cfvdtq"); + IF_XZ(int opts =) getopt32(argv, "cfvqdt"); # if ENABLE_XZ /* xz without -d or -t? */ if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) -- cgit v1.2.3-55-g6feb From 2fe5fed2dfea4ffdb8af5f6352ea2c19641de3bd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 1 Mar 2013 08:25:45 +0100 Subject: lzop: fiq -q and OPTION_DECOMPRESS mismatch Signed-off-by: Denys Vlasenko --- archival/lzop.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/archival/lzop.c b/archival/lzop.c index 56003d421..f5e06b54b 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -436,25 +436,26 @@ struct globals { //#define LZOP_VERSION_STRING "1.01" //#define LZOP_VERSION_DATE "Apr 27th 2003" -#define OPTION_STRING "cfvdt123456789CF" +#define OPTION_STRING "cfvqdt123456789CF" enum { OPT_STDOUT = (1 << 0), OPT_FORCE = (1 << 1), OPT_VERBOSE = (1 << 2), - OPT_DECOMPRESS = (1 << 3), - OPT_TEST = (1 << 4), - OPT_1 = (1 << 5), - OPT_2 = (1 << 6), - OPT_3 = (1 << 7), - OPT_4 = (1 << 8), - OPT_5 = (1 << 9), - OPT_6 = (1 << 10), - OPT_789 = (7 << 11), - OPT_7 = (1 << 11), - OPT_8 = (1 << 12), - OPT_C = (1 << 14), - OPT_F = (1 << 15), + OPT_QUIET = (1 << 3), + OPT_DECOMPRESS = (1 << 4), + OPT_TEST = (1 << 5), + OPT_1 = (1 << 6), + OPT_2 = (1 << 7), + OPT_3 = (1 << 8), + OPT_4 = (1 << 9), + OPT_5 = (1 << 10), + OPT_6 = (1 << 11), + OPT_789 = (7 << 12), + OPT_7 = (1 << 13), + OPT_8 = (1 << 14), + OPT_C = (1 << 15), + OPT_F = (1 << 16), }; /**********************************************************************/ @@ -1093,7 +1094,7 @@ int lzop_main(int argc UNUSED_PARAM, char **argv) if (applet_name[4] == 'c') option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS); /* unlzop? */ - if (applet_name[0] == 'u') + if (applet_name[4] == 'o') option_mask32 |= OPT_DECOMPRESS; global_crc32_table = crc32_filltable(NULL, 0); -- cgit v1.2.3-55-g6feb From c09fd27c0a1bc45b3bca4347f3ef7713c3898656 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 1 Mar 2013 14:37:58 +0100 Subject: decompress_unlzma: make "fast" version a bit smaller It is not slower. In fact it seems a tiny bit faster too. text data bss dec hex filename 2827 0 0 2827 b0b decompress_unlzma.o 2797 0 0 2797 aed decompress_unlzma.o Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_unlzma.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index cfde8ea56..dd08e77f3 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c @@ -45,16 +45,16 @@ typedef struct { #define RC_MODEL_TOTAL_BITS 11 -/* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */ -static size_inline void rc_read(rc_t *rc) +/* Called once in rc_do_normalize() */ +static void rc_read(rc_t *rc) { int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE); //TODO: return -1 instead //This will make unlzma delete broken unpacked file on unpack errors if (buffer_size <= 0) bb_error_msg_and_die("unexpected EOF"); - rc->ptr = RC_BUFFER; rc->buffer_end = RC_BUFFER + buffer_size; + rc->ptr = RC_BUFFER; } /* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */ @@ -78,15 +78,9 @@ static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ /* rc->ptr = rc->buffer_end; */ for (i = 0; i < 5; i++) { -#if ENABLE_FEATURE_LZMA_FAST - if (rc->ptr >= rc->buffer_end) - rc_read(rc); - rc->code = (rc->code << 8) | *rc->ptr++; -#else rc_do_normalize(rc); -#endif } - rc->range = 0xFFFFFFFF; + rc->range = 0xffffffff; return rc; } -- cgit v1.2.3-55-g6feb From a2d04e0702dcdd8b4d2e41145253608b8fd95c9d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 1 Mar 2013 14:43:07 +0100 Subject: decompress_unlzma: 10% speedup in "small" code text data bss dec hex filename 1796 0 0 1796 704 decompress_unlzma.o 1801 0 0 1801 709 decompress_unlzma.o Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_unlzma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index dd08e77f3..187035daa 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c @@ -114,7 +114,7 @@ static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) } /* Called 4 times in unlzma loop */ -static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) +static ALWAYS_INLINE int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) { int ret = rc_is_bit_1(rc, p); *symbol = *symbol * 2 + ret; -- cgit v1.2.3-55-g6feb From 507f6ea6d2de1bd8298c396edaa600a41bc5ae6e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 1 Mar 2013 14:48:10 +0100 Subject: decompress_unlzma: move function, no code changes Signed-off-by: Denys Vlasenko --- archival/libarchive/decompress_unlzma.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index 187035daa..ca32bd82c 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c @@ -65,6 +65,12 @@ static void rc_do_normalize(rc_t *rc) rc->range <<= 8; rc->code = (rc->code << 8) | *rc->ptr++; } +static ALWAYS_INLINE void rc_normalize(rc_t *rc) +{ + if (rc->range < (1 << RC_TOP_BITS)) { + rc_do_normalize(rc); + } +} /* Called once */ static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ @@ -90,13 +96,6 @@ static ALWAYS_INLINE void rc_free(rc_t *rc) free(rc); } -static ALWAYS_INLINE void rc_normalize(rc_t *rc) -{ - if (rc->range < (1 << RC_TOP_BITS)) { - rc_do_normalize(rc); - } -} - /* rc_is_bit_1 is called 9 times */ static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) { -- cgit v1.2.3-55-g6feb From 93b51819cf42728654769462130c4b7d50e9b67a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 3 Mar 2013 00:48:53 -0500 Subject: archival: note implicit dependencies between lzop & bbunzip Signed-off-by: Mike Frysinger --- archival/bbunzip.c | 1 + archival/lzop.c | 1 + 2 files changed, 2 insertions(+) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index fe3b29b78..b332eecd6 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -7,6 +7,7 @@ #include "libbb.h" #include "bb_archive.h" +/* Note: must be kept in sync with archival/lzop.c */ enum { OPT_STDOUT = 1 << 0, OPT_FORCE = 1 << 1, diff --git a/archival/lzop.c b/archival/lzop.c index f5e06b54b..9b42e5fd3 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -438,6 +438,7 @@ struct globals { #define OPTION_STRING "cfvqdt123456789CF" +/* Note: must be kept in sync with archival/bbunzip.c */ enum { OPT_STDOUT = (1 << 0), OPT_FORCE = (1 << 1), -- cgit v1.2.3-55-g6feb From 9bbf6b98c42a212b8a4b1aa02975ac18bb612922 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 4 Mar 2013 03:04:38 +0100 Subject: hostid: do not output sign-extended host id. Closes 6056 Signed-off-by: Denys Vlasenko --- coreutils/hostid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreutils/hostid.c b/coreutils/hostid.c index 5c1a4e086..e5b1f5188 100644 --- a/coreutils/hostid.c +++ b/coreutils/hostid.c @@ -36,7 +36,8 @@ int hostid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) bb_show_usage(); } - printf("%08lx\n", gethostid()); + /* POSIX says gethostid returns a "32-bit identifier" */ + printf("%08x\n", (unsigned)(uint32_t)gethostid()); return fflush_all(); } -- cgit v1.2.3-55-g6feb From bca5c556c43ced7b368fdd90a24e4aecf40045ac Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 12 Mar 2013 10:48:09 -0400 Subject: udhcpc: use readlink rather than realpath The realpath utility requires all paths exist when canonicalizing symlinks. If /etc/resolv.conf points to a tmpfs, then it might not exist initially. Use `readlink -f` so that we follow all symlinks that are available. Signed-off-by: Mike Frysinger --- examples/udhcp/simple.script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index 0397e506c..2a917eb6c 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script @@ -37,7 +37,7 @@ case "$1" in echo "Recreating $RESOLV_CONF" # If the file is a symlink somewhere (like /etc/resolv.conf # pointing to /run/resolv.conf), make sure things work. - realconf=$(realpath "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") + realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") tmpfile="$realconf-$$" > "$tmpfile" [ -n "$domain" ] && echo "search $domain" >> "$tmpfile" -- cgit v1.2.3-55-g6feb From 445e7543e80d629173d96a77fbfe228fe795cb88 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 12 Mar 2013 11:13:22 -0400 Subject: platform: use KERNEL_VERSION to simplify uClibc version checking This makes reading the logic (as well as adding new code) a lot simpler, and fixes one or two cases that were broken due to incorrect sub-version tests. Signed-off-by: Mike Frysinger --- coreutils/id.c | 4 +--- include/platform.h | 20 +++++++++++--------- networking/ether-wake.c | 5 +---- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/coreutils/id.c b/coreutils/id.c index 1f20b755e..1f3e1c4c2 100644 --- a/coreutils/id.c +++ b/coreutils/id.c @@ -64,12 +64,10 @@ /* This is a NOEXEC applet. Be very careful! */ #if !ENABLE_USE_BB_PWD_GRP -#if defined(__UCLIBC_MAJOR__) && (__UCLIBC_MAJOR__ == 0) -#if (__UCLIBC_MINOR__ < 9) || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 30) +#if defined(__UCLIBC__) && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 30) #error "Sorry, you need at least uClibc version 0.9.30 for id applet to build" #endif #endif -#endif enum { PRINT_REAL = (1 << 0), diff --git a/include/platform.h b/include/platform.h index f4deb30c0..917d87dd6 100644 --- a/include/platform.h +++ b/include/platform.h @@ -263,6 +263,12 @@ typedef unsigned smalluint; #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#ifdef __UCLIBC__ +# define UCLIBC_VERSION KERNEL_VERSION(__UCLIBC_MAJOR__, __UCLIBC_MINOR__, __UCLIBC_SUBLEVEL__) +#else +# define UCLIBC_VERSION 0 +#endif + /* ---- Miscellaneous --------------------------------------- */ @@ -305,8 +311,9 @@ typedef unsigned smalluint; * for a mmu-less system. */ #if ENABLE_NOMMU || \ - (defined __UCLIBC__ && __UCLIBC_MAJOR__ >= 0 && __UCLIBC_MINOR__ >= 9 && \ - __UCLIBC_SUBLEVEL__ > 28 && !defined __ARCH_USE_MMU__) + (defined __UCLIBC__ && \ + UCLIBC_VERSION > KERNEL_VERSION(0, 9, 28) && \ + !defined __ARCH_USE_MMU__) # define BB_MMU 0 # define USE_FOR_NOMMU(...) __VA_ARGS__ # define USE_FOR_MMU(...) @@ -373,13 +380,8 @@ typedef unsigned smalluint; #define HAVE_NET_ETHERNET_H 1 #define HAVE_SYS_STATFS_H 1 -#if defined(__UCLIBC_MAJOR__) -# if __UCLIBC_MAJOR__ == 0 \ - && ( __UCLIBC_MINOR__ < 9 \ - || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 32) \ - ) -# undef HAVE_STRVERSCMP -# endif +#if defined(__UCLIBC__) && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 32) +# undef HAVE_STRVERSCMP #endif #if defined(__dietlibc__) diff --git a/networking/ether-wake.c b/networking/ether-wake.c index bf09cd529..2d389ea30 100644 --- a/networking/ether-wake.c +++ b/networking/ether-wake.c @@ -121,10 +121,7 @@ static void get_dest_addr(const char *hostid, struct ether_addr *eaddr) eap = ether_aton_r(hostid, eaddr); if (eap) { bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eap)); -#if !defined(__UCLIBC_MAJOR__) \ - || __UCLIBC_MAJOR__ > 0 \ - || __UCLIBC_MINOR__ > 9 \ - || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ >= 30) +#if !defined(__UCLIBC__) || UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 30) } else if (ether_hostton(hostid, eaddr) == 0) { bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr)); #endif -- cgit v1.2.3-55-g6feb From af9e70b8cba23b17c554533c3cdab0b66e7015e8 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 12 Mar 2013 11:14:24 -0400 Subject: readlink: uClibc supports automatic allocation too now Signed-off-by: Mike Frysinger --- libbb/xreadlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c index ec95af222..0bdf394da 100644 --- a/libbb/xreadlink.c +++ b/libbb/xreadlink.c @@ -102,7 +102,8 @@ char* FAST_FUNC xmalloc_readlink_or_warn(const char *path) char* FAST_FUNC xmalloc_realpath(const char *path) { -#if defined(__GLIBC__) && !defined(__UCLIBC__) +#if defined(__GLIBC__) || \ + (defined(__UCLIBC__) && UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 31)) /* glibc provides a non-standard extension */ /* new: POSIX.1-2008 specifies this behavior as well */ return realpath(path, NULL); -- cgit v1.2.3-55-g6feb From 1b49c25e0a719ec3051eafa2329e68012c815abb Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 12 Mar 2013 11:38:03 -0400 Subject: readlink: note that our -f is really -e Signed-off-by: Mike Frysinger --- coreutils/readlink.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreutils/readlink.c b/coreutils/readlink.c index f7ad791ec..d73ef4ddb 100644 --- a/coreutils/readlink.c +++ b/coreutils/readlink.c @@ -39,7 +39,10 @@ * -q, --quiet, -s, --silent suppress most error messages * -v, --verbose report error messages * - * bbox supports: -f -n -v (fully), -q -s (accepts but ignores) + * bbox supports: -f (partially) -n -v (fully), -q -s (accepts but ignores) + * Note: we export the -f flag, but our -f behaves like coreutils' -e. + * Unfortunately, there isn't a C lib function we can leverage to get this + * behavior which means we'd have to implement the full stack ourselves :(. */ int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -- cgit v1.2.3-55-g6feb From 7991d45446216c493b00a2936d0682a2be49b684 Mon Sep 17 00:00:00 2001 From: Mandeep Singh Baines Date: Mon, 4 Mar 2013 16:33:12 -0800 Subject: losetup: fix util-linux compatibility Added -a support. Also made sure -f works as follows: losetup [-r] [-o offset] {-f|loopdev} file Removed support for 'losetup -r' with no arguments. Signed-off-by: Mandeep Singh Baines Signed-off-by: Mike Frysinger --- util-linux/losetup.c | 116 +++++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 51 deletions(-) diff --git a/util-linux/losetup.c b/util-linux/losetup.c index 21108d0bf..c69763335 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c @@ -8,16 +8,16 @@ */ //usage:#define losetup_trivial_usage -//usage: "[-r] [-o OFS] LOOPDEV FILE - associate loop devices\n" +//usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n" //usage: " losetup -d LOOPDEV - disassociate\n" -//usage: " losetup [-f] - show" +//usage: " losetup -a - show status of all\n" +//usage: " losetup -f - show next available" //usage:#define losetup_full_usage "\n\n" //usage: " -o OFS Start OFS bytes into FILE" //usage: "\n -r Read-only" -//usage: "\n -f Show first free loop device" +//usage: "\n -f Show/find first free loop device" //usage: //usage:#define losetup_notes_usage -//usage: "No arguments will display all current associations.\n" //usage: "One argument (losetup /dev/loop1) will display the current association\n" //usage: "(if any), or disassociate it (with -d). The display shows the offset\n" //usage: "and filename of the file the loop device is currently bound to.\n\n" @@ -31,77 +31,91 @@ int losetup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int losetup_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; - int n; char *opt_o; - unsigned long long offset = 0; + char dev[LOOP_NAMESIZE]; enum { OPT_d = (1 << 0), OPT_o = (1 << 1), OPT_f = (1 << 2), - OPT_r = (1 << 3), /* must be last */ + OPT_a = (1 << 3), + OPT_r = (1 << 4), /* must be last */ }; - /* max 2 args, -d,-o,-f opts are mutually exclusive */ - opt_complementary = "?2:d--of:o--df:f--do"; - opt = getopt32(argv, "do:fr", &opt_o); + opt_complementary = "?2:d--ofar:a--ofr"; + opt = getopt32(argv, "do:far", &opt_o); argv += optind; - if (opt == OPT_o) - offset = xatoull(opt_o); + /* LOOPDEV */ + if (!opt && argv[0] && !argv[1]) { + char *s; + s = query_loop(argv[0]); + if (!s) + bb_simple_perror_msg_and_die(argv[0]); + printf("%s: %s\n", argv[0], s); + if (ENABLE_FEATURE_CLEAN_UP) + free(s); + return EXIT_SUCCESS; + } + + /* -d LOOPDEV */ if (opt == OPT_d) { - /* -d BLOCKDEV */ - if (!argv[0] || argv[1]) - bb_show_usage(); if (del_loop(argv[0])) bb_simple_perror_msg_and_die(argv[0]); return EXIT_SUCCESS; } - if (argv[0]) { - char *s; - - if (opt == OPT_f) /* -f should not have arguments */ - bb_show_usage(); + /* -a */ + if (opt == OPT_a) { + int n; + for (n = 0; n < 10; n++) { + char *s; - if (argv[1]) { - /* [-r] [-o OFS] BLOCKDEV FILE */ - if (set_loop(&argv[0], argv[1], offset, (opt / OPT_r)) < 0) - bb_simple_perror_msg_and_die(argv[0]); - return EXIT_SUCCESS; + sprintf(dev, LOOP_FORMAT, n); + s = query_loop(dev); + if (s) { + printf("%s: %s\n", dev, s); + if (ENABLE_FEATURE_CLEAN_UP) + free(s); + } } - /* [-r] [-o OFS] BLOCKDEV */ - s = query_loop(argv[0]); - if (!s) - bb_simple_perror_msg_and_die(argv[0]); - printf("%s: %s\n", argv[0], s); - if (ENABLE_FEATURE_CLEAN_UP) - free(s); return EXIT_SUCCESS; } - /* [-r] [-o OFS|-f] with no params */ - n = 0; - while (1) { + /* contains -f */ + if (opt & OPT_f) { char *s; - char dev[LOOP_NAMESIZE]; + int n = 0; - sprintf(dev, LOOP_FORMAT, n); - s = query_loop(dev); - n++; - if (!s) { - if (n > 9 && errno && errno != ENXIO) - return EXIT_SUCCESS; - if (opt == OPT_f) { - puts(dev); - return EXIT_SUCCESS; - } - } else { - if (opt != OPT_f) - printf("%s: %s\n", dev, s); - if (ENABLE_FEATURE_CLEAN_UP) + do { + sprintf(dev, LOOP_FORMAT, n); + s = query_loop(dev); + if (s && ENABLE_FEATURE_CLEAN_UP) free(s); + } while (s); + if ((opt == OPT_f) && !argv[0]) { + puts(dev); + return EXIT_SUCCESS; } } - return EXIT_SUCCESS; + + /* [-r] [-o OFS] {-f|LOOPDEV} FILE */ + if (argv[0] && ((opt & OPT_f) || argv[1])) { + unsigned long long offset = 0; + char *d = dev; + + if (opt == OPT_o) + offset = xatoull(opt_o); + if (opt != OPT_f) + d = *(argv++); + + if (argv[0]) { + if (set_loop(&d, argv[0], offset, (opt / OPT_r)) < 0) + bb_simple_perror_msg_and_die(argv[0]); + return EXIT_SUCCESS; + } + } + + bb_show_usage(); + return EXIT_FAILURE; } -- cgit v1.2.3-55-g6feb From b79a0fef99627c457548e804fcd6e162b116cbe8 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Wed, 6 Mar 2013 21:01:05 +0100 Subject: awk: Fix handling of functions with empty body Signed-off-by: Bernhard Reutner-Fischer --- editors/awk.c | 3 ++- testsuite/awk.tests | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/editors/awk.c b/editors/awk.c index 3224788c0..0b573a065 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -2661,7 +2661,8 @@ static var *evaluate(node *op, var *res) var *vbeg, *v; const char *sv_progname; - if (!op->r.f->body.first) + /* The body might be empty, still has to eval the args */ + if (!op->r.n->info) syntax_error(EMSG_UNDEF_FUNC); vbeg = v = nvalloc(op->r.f->nargs + 1); diff --git a/testsuite/awk.tests b/testsuite/awk.tests index f9c3b6b4d..dad49c3f5 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -25,6 +25,25 @@ testing "awk if string == " "awk 'BEGIN{if(\"a\"==\"ab\") print \"bar\"}'" "" # 4294967295 = 0xffffffff testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n" + +# we were testing for a non-empty body when deciding if a function was +# defined or not. The testcase below caused: +# awk: cmd. line:8: Call to undefined function +prg=' +function empty_fun(count) { + # empty +} +END { + i=1 + print "L" i "\n" + empty_fun(i + i + ++i) + print "L" i "\n" +}' +testing "awk handles empty function f(arg){}" \ + "awk '$prg'" \ + "L1\n\nL2\n\n" \ + "" "" + optional DESKTOP testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n" testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n" -- cgit v1.2.3-55-g6feb From e3f5b73ad094775b0168108bb1fc443bc4b518b1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 13 Mar 2013 22:27:37 +0100 Subject: udhcpd: add -I LOCAL_ADDR option Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpd.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 9ad95954d..3c2a9cb4e 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -27,6 +27,7 @@ //usage: "DHCP server\n" //usage: "\n -f Run in foreground" //usage: "\n -S Log to syslog too" +//usage: "\n -I ADDR Local address" //usage: IF_FEATURE_UDHCP_PORT( //usage: "\n -P N Use port N (default 67)" //usage: ) @@ -302,6 +303,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) unsigned num_ips; unsigned opt; struct option_set *option; + char *str_I = str_I; IF_FEATURE_UDHCP_PORT(char *str_P;) #if ENABLE_FEATURE_UDHCP_PORT @@ -312,8 +314,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 opt_complementary = "vv"; #endif - opt = getopt32(argv, "fSv" - IF_FEATURE_UDHCP_PORT("P:", &str_P) + opt = getopt32(argv, "fSI:v" + IF_FEATURE_UDHCP_PORT("P:") + , &str_I + IF_FEATURE_UDHCP_PORT(, &str_P) IF_UDHCP_VERBOSE(, &dhcp_verbose) ); if (!(opt & 1)) { /* no -f */ @@ -326,8 +330,13 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) openlog(applet_name, LOG_PID, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } + if (opt & 4) { /* -I */ + len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET); + server_config.server_nip = lsa->u.sin.sin_addr.s_addr; + free(lsa); + } #if ENABLE_FEATURE_UDHCP_PORT - if (opt & 8) { /* -P */ + if (opt & 16) { /* -P */ SERVER_PORT = xatou16(str_P); CLIENT_PORT = SERVER_PORT + 1; } @@ -367,7 +376,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) if (udhcp_read_interface(server_config.interface, &server_config.ifindex, - &server_config.server_nip, + (server_config.server_nip == 0 ? &server_config.server_nip : NULL), server_config.server_mac) ) { retval = 1; -- cgit v1.2.3-55-g6feb From 7b5d5c1bdbb31661e7deb3dfc1a207fcf0f1d844 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 14 Mar 2013 02:18:52 +0100 Subject: udhcpd: also add -I ADDR to help text Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 3c2a9cb4e..a1a7f6b57 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -22,7 +22,7 @@ */ //usage:#define udhcpd_trivial_usage -//usage: "[-fS]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [CONFFILE]" +//usage: "[-fS] [-I ADDR]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [CONFFILE]" //usage:#define udhcpd_full_usage "\n\n" //usage: "DHCP server\n" //usage: "\n -f Run in foreground" -- cgit v1.2.3-55-g6feb From af4a07a24408667fa77a9a9bcc9fc773e0364e77 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 15 Mar 2013 00:11:35 +0100 Subject: ping[6]: accept and ignore -n. Code shrink function old new delta print_stats_and_exit 270 232 -38 Signed-off-by: Denys Vlasenko --- networking/ping.c | 61 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/networking/ping.c b/networking/ping.c index 3df67f5c3..e919b3a09 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -89,7 +89,9 @@ //usage: "[OPTIONS] HOST" //usage:# define ping_full_usage "\n\n" //usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" +//usage: IF_PING6( //usage: "\n -4,-6 Force IP or IPv6 name resolution" +//usage: ) //usage: "\n -c CNT Send only CNT pings" //usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" //usage: "\n -t TTL Set TTL" @@ -299,7 +301,7 @@ static int common_ping_main(sa_family_t af, char **argv) /* Full(er) version */ -#define OPT_STRING ("qvc:s:t:w:W:I:4" IF_PING6("6")) +#define OPT_STRING ("qvc:s:t:w:W:I:n4" IF_PING6("6")) enum { OPT_QUIET = 1 << 0, OPT_VERBOSE = 1 << 1, @@ -309,8 +311,9 @@ enum { OPT_w = 1 << 5, OPT_W = 1 << 6, OPT_I = 1 << 7, - OPT_IPV4 = 1 << 8, - OPT_IPV6 = (1 << 9) * ENABLE_PING6, + /*OPT_n = 1 << 8, - ignored */ + OPT_IPV4 = 1 << 9, + OPT_IPV6 = (1 << 10) * ENABLE_PING6, }; @@ -349,9 +352,6 @@ struct globals { #define source_lsa (G.source_lsa ) #define str_I (G.str_I ) #define datalen (G.datalen ) -#define ntransmitted (G.ntransmitted) -#define nreceived (G.nreceived ) -#define nrepeats (G.nrepeats ) #define pingcount (G.pingcount ) #define opt_ttl (G.opt_ttl ) #define myid (G.myid ) @@ -387,33 +387,40 @@ void BUG_ping_globals_too_big(void); static void print_stats_and_exit(int junk) NORETURN; static void print_stats_and_exit(int junk UNUSED_PARAM) { + unsigned long ul; + unsigned long nrecv; + signal(SIGINT, SIG_IGN); - printf("\n--- %s ping statistics ---\n", hostname); - printf("%lu packets transmitted, ", ntransmitted); - printf("%lu packets received, ", nreceived); - if (nrepeats) - printf("%lu duplicates, ", nrepeats); - if (ntransmitted) - ntransmitted = (ntransmitted - nreceived) * 100 / ntransmitted; - printf("%lu%% packet loss\n", ntransmitted); + nrecv = G.nreceived; + printf("\n--- %s ping statistics ---\n" + "%lu packets transmitted, " + "%lu packets received, ", + hostname, G.ntransmitted, nrecv + ); + if (G.nrepeats) + printf("%lu duplicates, ", G.nrepeats); + ul = G.ntransmitted; + if (ul != 0) + ul = (ul - nrecv) * 100 / ul; + printf("%lu%% packet loss\n", ul); if (tmin != UINT_MAX) { - unsigned tavg = tsum / (nreceived + nrepeats); + unsigned tavg = tsum / (nrecv + G.nrepeats); printf("round-trip min/avg/max = %u.%03u/%u.%03u/%u.%03u ms\n", tmin / 1000, tmin % 1000, tavg / 1000, tavg % 1000, tmax / 1000, tmax % 1000); } /* if condition is true, exit with 1 -- 'failure' */ - exit(nreceived == 0 || (deadline && nreceived < pingcount)); + exit(nrecv == 0 || (deadline && nrecv < pingcount)); } static void sendping_tail(void (*sp)(int), int size_pkt) { int sz; - CLR((uint16_t)ntransmitted % MAX_DUP_CHK); - ntransmitted++; + CLR((uint16_t)G.ntransmitted % MAX_DUP_CHK); + G.ntransmitted++; size_pkt += datalen; @@ -423,7 +430,7 @@ static void sendping_tail(void (*sp)(int), int size_pkt) if (sz != size_pkt) bb_error_msg_and_die(bb_msg_write_error); - if (pingcount == 0 || deadline || ntransmitted < pingcount) { + if (pingcount == 0 || deadline || G.ntransmitted < pingcount) { /* Didn't send all pings yet - schedule next in 1s */ signal(SIGALRM, sp); if (deadline) { @@ -439,7 +446,7 @@ static void sendping_tail(void (*sp)(int), int size_pkt) * otherwise ping waits for two RTTs. */ unsigned expire = timeout; - if (nreceived) { + if (G.nreceived) { /* approx. 2*tmax, in seconds (2 RTT) */ expire = tmax / (512*1024); if (expire == 0) @@ -458,7 +465,7 @@ static void sendping4(int junk UNUSED_PARAM) pkt->icmp_type = ICMP_ECHO; /*pkt->icmp_code = 0;*/ pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */ - pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ + pkt->icmp_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ pkt->icmp_id = myid; /* If datalen < 4, we store timestamp _past_ the packet, @@ -481,7 +488,7 @@ static void sendping6(int junk UNUSED_PARAM) pkt->icmp6_type = ICMP6_ECHO_REQUEST; /*pkt->icmp6_code = 0;*/ /*pkt->icmp6_cksum = 0;*/ - pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ + pkt->icmp6_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ pkt->icmp6_id = myid; /*if (datalen >= 4)*/ @@ -548,7 +555,7 @@ static void unpack_tail(int sz, uint32_t *tp, const char *dupmsg = " (DUP!)"; unsigned triptime = triptime; /* for gcc */ - ++nreceived; + ++G.nreceived; if (tp) { /* (int32_t) cast is for hypothetical 64-bit unsigned */ @@ -562,8 +569,8 @@ static void unpack_tail(int sz, uint32_t *tp, } if (TST(recv_seq % MAX_DUP_CHK)) { - ++nrepeats; - --nreceived; + ++G.nrepeats; + --G.nreceived; } else { SET(recv_seq % MAX_DUP_CHK); dupmsg += 7; @@ -692,7 +699,7 @@ static void ping4(len_and_sockaddr *lsa) continue; } unpack4(G.rcv_packet, c, &from); - if (pingcount && nreceived >= pingcount) + if (pingcount && G.nreceived >= pingcount) break; } } @@ -784,7 +791,7 @@ static void ping6(len_and_sockaddr *lsa) } } unpack6(G.rcv_packet, c, &from, hoplimit); - if (pingcount && nreceived >= pingcount) + if (pingcount && G.nreceived >= pingcount) break; } } -- cgit v1.2.3-55-g6feb From 0d61dcd6411129afa6b880653de0a1c4356974cc Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 15 Mar 2013 00:27:41 +0100 Subject: nanddump: fix build if nandwrite isn't enabled Signed-off-by: Alexander Shiyan Signed-off-by: Denys Vlasenko --- miscutils/nandwrite.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index 5908ac773..e3f9b565d 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c @@ -23,7 +23,7 @@ //config: Dump the content of raw NAND chip //applet:IF_NANDWRITE(APPLET(nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP)) -//applet:IF_NANDWRITE(APPLET_ODDNAME(nanddump, nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP, nanddump)) +//applet:IF_NANDDUMP(APPLET_ODDNAME(nanddump, nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP, nanddump)) //kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o //kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o @@ -31,14 +31,14 @@ //usage:#define nandwrite_trivial_usage //usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" //usage:#define nandwrite_full_usage "\n\n" -//usage: "Write to the specified MTD device\n" +//usage: "Write to MTD_DEVICE\n" //usage: "\n -p Pad to page size" //usage: "\n -s ADDR Start address" //usage:#define nanddump_trivial_usage -//usage: "[-o] [-b] [-s ADDR] [-f FILE] MTD_DEVICE" +//usage: "[-o] [-b] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" //usage:#define nanddump_full_usage "\n\n" -//usage: "Dump the specified MTD device\n" +//usage: "Dump MTD_DEVICE\n" //usage: "\n -o Dump oob data" //usage: "\n -b Omit bad block from the dump" //usage: "\n -s ADDR Start address" -- cgit v1.2.3-55-g6feb From 45dc96c8a6dce3aeea983f6c32572d4cee646b5d Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 15 Mar 2013 00:42:39 +0100 Subject: flash_eraseall: implement -N Signed-off-by: Alexander Shiyan Signed-off-by: Denys Vlasenko --- miscutils/flash_eraseall.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index 0598371d5..bf9b739a1 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c @@ -11,10 +11,11 @@ */ //usage:#define flash_eraseall_trivial_usage -//usage: "[-jq] MTD_DEVICE" +//usage: "[-jNq] MTD_DEVICE" //usage:#define flash_eraseall_full_usage "\n\n" //usage: "Erase an MTD device\n" //usage: "\n -j Format the device for jffs2" +//usage: "\n -N Don't skip bad blocks" //usage: "\n -q Don't display progress messages" #include "libbb.h" @@ -22,9 +23,9 @@ #include #define OPTION_J (1 << 0) -#define OPTION_Q (1 << 1) -#define IS_NAND (1 << 2) -#define BBTEST (1 << 3) +#define OPTION_N (1 << 1) +#define OPTION_Q (1 << 2) +#define IS_NAND (1 << 3) /* mtd/jffs2-user.h used to have this atrocity: extern int target_endian; @@ -71,7 +72,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) char *mtd_name; opt_complementary = "=1"; - flags = BBTEST | getopt32(argv, "jq"); + flags = getopt32(argv, "jNq"); mtd_name = argv[optind]; fd = xopen(mtd_name, O_RDWR); @@ -139,7 +140,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) { - if (flags & BBTEST) { + if (!(flags & OPTION_N)) { int ret; loff_t offset = erase.start; @@ -154,7 +155,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) * types e.g. NOR */ if (errno == EOPNOTSUPP) { - flags &= ~BBTEST; + flags |= OPTION_N; if (flags & IS_NAND) bb_error_msg_and_die("bad block check not available"); } else { -- cgit v1.2.3-55-g6feb From 4a600f8777f3fa0f673b47ccc8a0ba9cf6634249 Mon Sep 17 00:00:00 2001 From: Guilherme Maciel Ferreira Date: Fri, 8 Mar 2013 16:50:51 -0300 Subject: traceroute: free some memory allocated by xzalloc() Signed-off-by: Guilherme Maciel Ferreira Signed-off-by: Denys Vlasenko --- networking/traceroute.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/networking/traceroute.c b/networking/traceroute.c index 6b7b2ebdd..0c18d6c0c 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c @@ -805,6 +805,7 @@ common_traceroute_main(int op, char **argv) char *waittime_str; char *pausemsecs_str; char *first_ttl_str; + char *dest_str; #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE llist_t *source_route_list = NULL; int lsrr = 0; @@ -1059,8 +1060,12 @@ common_traceroute_main(int op, char **argv) xsetgid(getgid()); xsetuid(getuid()); - printf("traceroute to %s (%s)", argv[0], - xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa)); + dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa); + printf("traceroute to %s (%s)", argv[0], dest_str); + if (ENABLE_FEATURE_CLEAN_UP) { + free(dest_str); + } + if (op & OPT_SOURCE) printf(" from %s", source); printf(", %d hops max, %d byte packets\n", max_ttl, packlen); @@ -1216,6 +1221,12 @@ common_traceroute_main(int op, char **argv) } } + if (ENABLE_FEATURE_CLEAN_UP) { + free(to); + free(lastaddr); + free(from_lsa); + } + return 0; } -- cgit v1.2.3-55-g6feb From 257a77568ab452244de55d4cd35ba39541fce2a7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 15 Mar 2013 01:50:35 +0100 Subject: sysklogd: trim help text Signed-off-by: Denys Vlasenko --- sysklogd/syslogd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 3fe3f5348..4f45b4f7f 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -29,7 +29,7 @@ //usage: "\n -b N N rotated logs to keep (default:1, max=99, 0=purge)" //usage: ) //usage: IF_FEATURE_REMOTE_LOG( -//usage: "\n -R HOST[:PORT] Log to IP or hostname on PORT (default PORT=514/UDP)" +//usage: "\n -R HOST[:PORT] Log to HOST:PORT (default PORT:514)" //usage: "\n -L Log locally and via network (default is network only if -R)" //usage: ) //usage: IF_FEATURE_SYSLOGD_DUP( -- cgit v1.2.3-55-g6feb From cb5aa725df472a7ab84c7c513a8dda98b9b3a6bc Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 7 Mar 2013 20:37:23 +0000 Subject: vi: fix adjustment of buffer on partial file read The second argument to text_hole_delete was incorrect: it should be a pointer to the end of the hole. Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/vi.c b/editors/vi.c index 7173415c8..3d6182bbf 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2530,7 +2530,7 @@ static int file_insert(const char *fn, char *p, int update_ro_status) p = text_hole_delete(p, p + size - 1); // un-do buffer insert } else if (cnt < size) { // There was a partial read, shrink unused space text[] - p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert + p = text_hole_delete(p + cnt, p + size - 1); // un-do buffer insert status_line_bold("can't read '%s'", fn); } if (cnt >= size) -- cgit v1.2.3-55-g6feb From 9e7c002182d2ce57ac23dc65dde23e5f1f6557f0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 15 Mar 2013 02:17:29 +0100 Subject: vi: code shrink function old new delta status_line_bold_errno - 32 +32 colon 2891 2873 -18 file_insert 354 313 -41 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/2 up/down: 32/-59) Total: -27 bytes Signed-off-by: Denys Vlasenko --- editors/vi.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 3d6182bbf..3615ee469 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -478,6 +478,7 @@ static void flash(int); // flash the terminal screen static void show_status_line(void); // put a message on the bottom line static void status_line(const char *, ...); // print to status buf static void status_line_bold(const char *, ...); +static void status_line_bold_errno(const char *fn); static void not_implemented(const char *); // display "Not implemented" message static int format_edit_status(void); // format file status on status line static void redraw(int); // force a full screen refresh @@ -1321,7 +1322,7 @@ static void colon(char *buf) } if (l < 0) { if (l == -1) - status_line_bold("'%s' %s", fn, strerror(errno)); + status_line_bold_errno(fn); } else { status_line("'%s' %dL, %dC", fn, li, l); if (q == text && r == end - 1 && l == ch) { @@ -2503,7 +2504,7 @@ static int file_insert(const char *fn, char *p, int update_ro_status) /* Validate file */ if (stat(fn, &statbuf) < 0) { - status_line_bold("'%s' %s", fn, strerror(errno)); + status_line_bold_errno(fn); goto fi0; } if (!S_ISREG(statbuf.st_mode)) { @@ -2519,14 +2520,14 @@ static int file_insert(const char *fn, char *p, int update_ro_status) // read file to buffer fd = open(fn, O_RDONLY); if (fd < 0) { - status_line_bold("'%s' %s", fn, strerror(errno)); + status_line_bold_errno(fn); goto fi0; } size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX); p += text_hole_make(p, size); cnt = safe_read(fd, p, size); if (cnt < 0) { - status_line_bold("'%s' %s", fn, strerror(errno)); + status_line_bold_errno(fn); p = text_hole_delete(p, p + size - 1); // un-do buffer insert } else if (cnt < size) { // There was a partial read, shrink unused space text[] @@ -2717,6 +2718,11 @@ static void status_line_bold(const char *format, ...) have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2; } +static void status_line_bold_errno(const char *fn) +{ + status_line_bold("'%s' %s", fn, strerror(errno)); +} + // format status buffer static void status_line(const char *format, ...) { -- cgit v1.2.3-55-g6feb From aeb717aa5e8a5ae650a283306091a2872628cffd Mon Sep 17 00:00:00 2001 From: Stefan Hellermann Date: Sun, 3 Mar 2013 15:29:32 +0100 Subject: ash: move code to allow setting $HOME in /etc/profile move HISTFILE=$HOME/.ash_history below reading /etc/profile, so that /etc/profile can set $HOME. HOME can be unset when directly invoking ash --login from init without going through getty. Signed-off-by: Stefan Hellermann Signed-off-by: Denys Vlasenko --- shell/ash.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 0b5111a39..5f09fd474 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13191,19 +13191,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv) setstackmark(&smark); procargs(argv); -#if ENABLE_FEATURE_EDITING_SAVEHISTORY - if (iflag) { - const char *hp = lookupvar("HISTFILE"); - if (!hp) { - hp = lookupvar("HOME"); - if (hp) { - char *defhp = concat_path_file(hp, ".ash_history"); - setvar("HISTFILE", defhp, 0); - free(defhp); - } - } - } -#endif if (argv[0] && argv[0][0] == '-') isloginsh = 1; if (isloginsh) { @@ -13243,6 +13230,15 @@ int ash_main(int argc UNUSED_PARAM, char **argv) #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY if (iflag) { const char *hp = lookupvar("HISTFILE"); + if (!hp) { + hp = lookupvar("HOME"); + if(hp) { + hp = concat_path_file(hp, ".ash_history"); + setvar("HISTFILE", hp, 0); + free((char*)hp); + hp = lookupvar("HISTFILE"); + } + } if (hp) line_input_state->hist_file = hp; # if ENABLE_FEATURE_SH_HISTFILESIZE -- cgit v1.2.3-55-g6feb From 4ef1439c593daadeffb3f00eaaf49e190a3039e1 Mon Sep 17 00:00:00 2001 From: Stefan Hellermann Date: Fri, 15 Mar 2013 02:45:50 +0100 Subject: ash: read $HOME/.profile instead of $(pwd)/.profile ash --login should read ~/.profile instead of .profile in the current directory. I noticed it while trying to figure out why /root/.profile is only read sometimes. function old new delta ash_main 1374 1398 +24 Signed-off-by: Stefan Hellermann Signed-off-by: Denys Vlasenko --- shell/ash.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 5f09fd474..fbbdb06b0 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13194,11 +13194,18 @@ int ash_main(int argc UNUSED_PARAM, char **argv) if (argv[0] && argv[0][0] == '-') isloginsh = 1; if (isloginsh) { + const char *hp; + state = 1; read_profile("/etc/profile"); state1: state = 2; - read_profile(".profile"); + hp = lookupvar("HOME"); + if (hp) { + hp = concat_path_file(hp, ".profile"); + read_profile(hp); + free((char*)hp); + } } state2: state = 3; @@ -13232,7 +13239,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) const char *hp = lookupvar("HISTFILE"); if (!hp) { hp = lookupvar("HOME"); - if(hp) { + if (hp) { hp = concat_path_file(hp, ".ash_history"); setvar("HISTFILE", hp, 0); free((char*)hp); -- cgit v1.2.3-55-g6feb From 88b532d59af81f3b788864b2d6d42e1f86bc8de0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 17 Mar 2013 14:11:04 +0100 Subject: hush: source builtin should override $N only if it has args function old new delta builtin_source 174 184 +10 Signed-off-by: Denys Vlasenko --- shell/hush.c | 9 +++++++-- shell/hush_test/hush-misc/source2.right | 4 ++++ shell/hush_test/hush-misc/source2.tests | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 shell/hush_test/hush-misc/source2.right create mode 100755 shell/hush_test/hush-misc/source2.tests diff --git a/shell/hush.c b/shell/hush.c index e2dc1e2d0..b23325725 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -8880,6 +8880,9 @@ static int FAST_FUNC builtin_source(char **argv) free(arg_path); if (!input) { /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ + /* POSIX: non-interactive shell should abort here, + * not merely fail. So far no one complained :) + */ return EXIT_FAILURE; } close_on_exec_on(fileno(input)); @@ -8889,12 +8892,14 @@ static int FAST_FUNC builtin_source(char **argv) /* "we are inside sourced file, ok to use return" */ G.flag_return_in_progress = -1; #endif - save_and_replace_G_args(&sv, argv); + if (argv[1]) + save_and_replace_G_args(&sv, argv); parse_and_run_file(input); fclose(input); - restore_G_args(&sv, argv); + if (argv[1]) + restore_G_args(&sv, argv); #if ENABLE_HUSH_FUNCTIONS G.flag_return_in_progress = sv_flg; #endif diff --git a/shell/hush_test/hush-misc/source2.right b/shell/hush_test/hush-misc/source2.right new file mode 100644 index 000000000..0587bad67 --- /dev/null +++ b/shell/hush_test/hush-misc/source2.right @@ -0,0 +1,4 @@ +0:arg0 1:arg1 2:arg2 +Ok1:0 +0:arg0 1:q 2:w +Ok2:0 diff --git a/shell/hush_test/hush-misc/source2.tests b/shell/hush_test/hush-misc/source2.tests new file mode 100755 index 000000000..40b6b83cd --- /dev/null +++ b/shell/hush_test/hush-misc/source2.tests @@ -0,0 +1,8 @@ +echo 'echo "0:$0 1:$1 2:$2"' >sourced1 +set -- 1 2 3 +"$THIS_SH" -c '. ./sourced1' arg0 arg1 arg2 +echo Ok1:$? +"$THIS_SH" -c '. ./sourced1 q w e' arg0 arg1 arg2 +echo Ok2:$? + +rm sourced1 -- cgit v1.2.3-55-g6feb From 091f831424e8aa2052484ef07f0225f5405d086f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 17 Mar 2013 14:25:22 +0100 Subject: ash: add comment about failures in source builtin. No code changes. Signed-off-by: Denys Vlasenko --- shell/ash.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/shell/ash.c b/shell/ash.c index fbbdb06b0..edcb7c028 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12258,6 +12258,9 @@ dotcmd(int argc, char **argv) /* "false; . empty_file; echo $?" should print 0, not 1: */ exitstatus = 0; + /* This aborts if file isn't found, which is POSIXly correct. + * bash returns exitcode 1 instead. + */ fullname = find_dot_file(argv[1]); argv += 2; @@ -12269,6 +12272,9 @@ dotcmd(int argc, char **argv) shellparam.p = argv; }; + /* This aborts if file can't be opened, which is POSIXly correct. + * bash returns exitcode 1 instead. + */ setinputfile(fullname, INPUT_PUSH_FILE); commandname = fullname; cmdloop(0); -- cgit v1.2.3-55-g6feb From c56d12505bc372969a3ec15c74f79ebf5cc09c86 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 17 Mar 2013 22:59:51 +0100 Subject: nc: fix build failure ("subscripted value is neither array nor pointer") Signed-off-by: Denys Vlasenko --- networking/nc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/nc.c b/networking/nc.c index 5f4cb89cc..126bec906 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -229,7 +229,7 @@ int nc_main(int argc, char **argv) xdup2(0, 1); /*xdup2(0, 2); - original nc 1.10 does this, we don't */ IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) - bb_perror_msg_and_die("can't execute '%s'", execparam[0]); + IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);) } /* Select loop copying stdin to cfd, and cfd to stdout */ -- cgit v1.2.3-55-g6feb From 4424dfd69bc4edfe514b17b7006f8855892a338b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 17 Mar 2013 23:01:17 +0100 Subject: mdev: fix build failure The error was "error: 'struct globals' has no member named 'parser'" Signed-off-by: Denys Vlasenko --- util-linux/mdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util-linux/mdev.c b/util-linux/mdev.c index c5c0d613c..5fe6bbbde 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -646,9 +646,8 @@ static void make_device(char *device_name, char *path, int operation) } /* else: it's final implicit "match-all" rule */ rule_matches: -#endif dbg2("rule matched, line %d", G.parser ? G.parser->lineno : -1); - +#endif /* Build alias name */ alias = NULL; if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) { -- cgit v1.2.3-55-g6feb From 7c6f2d4207e11ca60964132deb3bd1c4cb583aba Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 18 Mar 2013 02:26:58 +0100 Subject: mkfs_minix: use get_volume_size_in_bytes instead of local version Hopefully this also closes 4730 function old new delta valid_offset 55 - -55 mkfs_minix_main 2925 2674 -251 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 0/1 up/down: 0/-306) Total: -306 bytes Signed-off-by: Denys Vlasenko --- util-linux/mkfs_minix.c | 77 +++++++++---------------------------------------- 1 file changed, 14 insertions(+), 63 deletions(-) diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c index 59d7d23d4..49afd1176 100644 --- a/util-linux/mkfs_minix.c +++ b/util-linux/mkfs_minix.c @@ -196,54 +196,6 @@ static void minix_clrbit(char *a, unsigned i) # define BLKGETSIZE _IO(0x12,96) /* return device size */ #endif - -static long valid_offset(int fd, int offset) -{ - char ch; - - if (lseek(fd, offset, SEEK_SET) < 0) - return 0; - if (read(fd, &ch, 1) < 1) - return 0; - return 1; -} - -static int count_blocks(int fd) -{ - int high, low; - - low = 0; - for (high = 1; valid_offset(fd, high); high *= 2) - low = high; - - while (low < high - 1) { - const int mid = (low + high) / 2; - - if (valid_offset(fd, mid)) - low = mid; - else - high = mid; - } - valid_offset(fd, 0); - return (low + 1); -} - -static int get_size(const char *file) -{ - int fd; - long size; - - fd = xopen(file, O_RDWR); - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - close(fd); - return (size * 512); - } - - size = count_blocks(fd); - close(fd); - return size; -} - static void write_tables(void) { /* Mark the superblock valid. */ @@ -636,7 +588,6 @@ int mkfs_minix_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; char *tmp; - struct stat statbuf; char *str_i; char *listfile = NULL; @@ -673,13 +624,17 @@ int mkfs_minix_main(int argc UNUSED_PARAM, char **argv) #endif } - G.device_name = *argv++; + G.device_name = argv[0]; if (!G.device_name) bb_show_usage(); - if (*argv) - G.total_blocks = xatou32(*argv); - else - G.total_blocks = get_size(G.device_name) / 1024; + + /* Check if it is mounted */ + if (find_mount_point(G.device_name, 0)) + bb_error_msg_and_die("can't format mounted filesystem"); + + xmove_fd(xopen(G.device_name, O_RDWR), dev_fd); + + G.total_blocks = get_volume_size_in_bytes(dev_fd, argv[1], 1024, /*extend:*/ 1) / 1024; if (G.total_blocks < 10) bb_error_msg_and_die("must have at least 10 blocks"); @@ -690,25 +645,21 @@ int mkfs_minix_main(int argc UNUSED_PARAM, char **argv) G.magic = MINIX2_SUPER_MAGIC; } else if (G.total_blocks > 65535) G.total_blocks = 65535; - - /* Check if it is mounted */ - if (find_mount_point(G.device_name, 0)) - bb_error_msg_and_die("can't format mounted filesystem"); - - xmove_fd(xopen(G.device_name, O_RDWR), dev_fd); +#if 0 + struct stat statbuf; xfstat(dev_fd, &statbuf, G.device_name); +/* why? */ if (!S_ISBLK(statbuf.st_mode)) opt &= ~1; // clear -c (check) - +#if 0 /* I don't know why someone has special code to prevent mkfs.minix * on IDE devices. Why IDE but not SCSI, etc?... */ -#if 0 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) /* what is this? */ bb_error_msg_and_die("will not try " "to make filesystem on '%s'", G.device_name); #endif - +#endif tmp = G.root_block; *(short *) tmp = 1; strcpy(tmp + 2, "."); -- cgit v1.2.3-55-g6feb From 14285d14a5826eb172e02cf2f6f1ec096add01b0 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 25 Feb 2013 00:45:06 +0200 Subject: sendmail: avoid sending mail to wrong addresses If we get an address we cannot parse properly, we currently just strip the unknown characters and still try to send it. This is considered harmful as the resulting address may still be valid but different from what the user originally intended. Instead, skip sending to an address we cannot fully understand and print the characters what we have scanned so far. Leading and trailing whitespace is allowed and silently stripped. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index c426e9d85..4f73512e9 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -94,9 +94,22 @@ static char *sane_address(char *str) { char *s = str; char *p = s; + int leading_space = 1; + int trailing_space = 0; + while (*s) { - if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { + if (isspace(*s)) { + trailing_space = !leading_space; + } else { *p++ = *s; + if ((!isalnum(*s) && !strchr("_-.@", *s)) || + trailing_space) { + *p = '\0'; + bb_error_msg("Bad address: %s", str); + *str = '\0'; + return str; + } + leading_space = 0; } s++; } @@ -106,6 +119,8 @@ static char *sane_address(char *str) static void rcptto(const char *s) { + if (!*s) + return; // N.B. we don't die if recipient is rejected, for the other recipients may be accepted if (250 != smtp_checkp("RCPT TO:<%s>", s, -1)) bb_error_msg("Bad recipient: <%s>", s); -- cgit v1.2.3-55-g6feb From 95e99e5271cb15247ba8926f0352387643164528 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 25 Feb 2013 00:45:07 +0200 Subject: sendmail: don't mangle e-mail headers Leave the original To: and Cc: headers untouched, when we try to extract addresses from them. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 4f73512e9..0f536adae 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -299,7 +299,9 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // To: or Cc: headers add recipients if (opts & OPT_t) { if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { - rcptto(sane_address(s+3)); + char *r = xstrdup(s+3); + rcptto(sane_address(r)); + free(r); goto addheader; } // Bcc: header adds blind copy (hidden) recipient -- cgit v1.2.3-55-g6feb From 06ad964ae61591ef74313d7c1746367430d0d82b Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 25 Feb 2013 00:45:08 +0200 Subject: sendmail: support addresses inside angle brackets When we extract addresses from the e-mail, try to first check for an address inside angle brackets. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 0f536adae..10a5a85d4 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -117,6 +117,24 @@ static char *sane_address(char *str) return str; } +// check for an address inside angle brackets, if not found fall back to normal +static char *angle_address(char *str) +{ + char *s = str; + char *e = str + strlen(str); + + while (e != str && (isspace(*e) || *e == '\0')) + e--; + if (*e != '>') + goto done; + *e = '\0'; + e = strrchr(s, '<'); + if (e != NULL) + s = e + 1; +done: + return sane_address(s); +} + static void rcptto(const char *s) { if (!*s) @@ -300,13 +318,13 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) if (opts & OPT_t) { if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { char *r = xstrdup(s+3); - rcptto(sane_address(r)); + rcptto(angle_address(r)); free(r); goto addheader; } // Bcc: header adds blind copy (hidden) recipient if (0 == strncasecmp("Bcc:", s, 4)) { - rcptto(sane_address(s+4)); + rcptto(angle_address(s+4)); free(s); continue; // N.B. Bcc: vanishes from headers! } -- cgit v1.2.3-55-g6feb From a8ba0a0d0ce4fa5f5afd0a8246e2378c2664c424 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 25 Feb 2013 00:45:09 +0200 Subject: sendmail: support address lists Headers To:, Cc: and Bcc: may have a list of comma-separated addresses. Add support for that. Commas inside double quotes are ignored. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 10a5a85d4..c5df5f5d3 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -144,6 +144,33 @@ static void rcptto(const char *s) bb_error_msg("Bad recipient: <%s>", s); } +// send to a list of comma separated addresses +static void rcptto_list(const char *_str) +{ + char *str = xstrdup(_str); + int len = strlen(str); + int in_quote = 0; + char *s = str; + char prev = 0; + int pos; + + for (pos = 0; pos < len; pos++) { + char ch = str[pos]; + + if (ch == '"' && prev != '\\') { + in_quote = !in_quote; + } else if (!in_quote && ch == ',') { + str[pos] = '\0'; + rcptto(angle_address(s)); + s = str + pos + 1; + } + prev = ch; + } + if (prev != ',') + rcptto(angle_address(s)); + free(str); +} + int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sendmail_main(int argc UNUSED_PARAM, char **argv) { @@ -317,14 +344,12 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // To: or Cc: headers add recipients if (opts & OPT_t) { if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { - char *r = xstrdup(s+3); - rcptto(angle_address(r)); - free(r); + rcptto_list(s+3); goto addheader; } // Bcc: header adds blind copy (hidden) recipient if (0 == strncasecmp("Bcc:", s, 4)) { - rcptto(angle_address(s+4)); + rcptto_list(s+4); free(s); continue; // N.B. Bcc: vanishes from headers! } -- cgit v1.2.3-55-g6feb From 236f222cde03b2594732dacdfe031c7c16e20f4a Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 25 Feb 2013 00:45:10 +0200 Subject: sendmail: support long header fields for recipients Support long header fields in To:, Cc: and Bcc: headers. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index c5df5f5d3..22f735b3d 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -181,6 +181,12 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) char *host = sane_address(safe_gethostname()); unsigned nheaders = 0; int code; + enum { + HDR_OTHER = 0, + HDR_TOCC, + HDR_BCC, + } last_hdr = 0; + int check_hdr; enum { //--- standard options @@ -345,20 +351,31 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) if (opts & OPT_t) { if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { rcptto_list(s+3); + last_hdr = HDR_TOCC; goto addheader; } // Bcc: header adds blind copy (hidden) recipient if (0 == strncasecmp("Bcc:", s, 4)) { rcptto_list(s+4); free(s); + last_hdr = HDR_BCC; continue; // N.B. Bcc: vanishes from headers! } } - if (strchr(s, ':') || (list && isspace(s[0]))) { + check_hdr = list && isspace(s[0]); + if (strchr(s, ':') || check_hdr) { // other headers go verbatim // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. // Continuation is denoted by prefixing additional lines with whitespace(s). // Thanks (stefan.seyfried at googlemail.com) for pointing this out. + if (check_hdr && last_hdr != HDR_OTHER) { + rcptto_list(s+1); + if (last_hdr == HDR_BCC) + continue; + // N.B. Bcc: vanishes from headers! + } else { + last_hdr = HDR_OTHER; + } addheader: // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) -- cgit v1.2.3-55-g6feb From 4a732220e907bfed95e87be38cea6e15253a9ad8 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 25 Feb 2013 00:45:11 +0200 Subject: sendmail: don't add To: header if it already exists If the message we are sending already has To: header, don't add a new one. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 22f735b3d..36a1b97cb 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -187,6 +187,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) HDR_BCC, } last_hdr = 0; int check_hdr; + int has_to = 0; enum { //--- standard options @@ -348,8 +349,10 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // analyze headers // To: or Cc: headers add recipients + check_hdr = 0 == strncasecmp("To:", s, 3); + has_to |= check_hdr; if (opts & OPT_t) { - if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { + if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) { rcptto_list(s+3); last_hdr = HDR_TOCC; goto addheader; @@ -391,7 +394,9 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) rcptto(t); //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) // goto bail; - llist_add_to_end(&list, xasprintf("To: %s", t)); + if (!has_to) + llist_add_to_end(&list, + xasprintf("To: %s", t)); argv++; } // enter "put message" mode -- cgit v1.2.3-55-g6feb From e82bfef8395bc0aff7c770bfadcd9e58a48ffc04 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 25 Feb 2013 00:45:12 +0200 Subject: sendmail: don't add multiple To: headers When adding To: header, add only a single header. If there are multiple addresses, make it multiline. Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 36a1b97cb..d58f503a0 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -365,7 +365,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) continue; // N.B. Bcc: vanishes from headers! } } - check_hdr = list && isspace(s[0]); + check_hdr = (list && isspace(s[0])); if (strchr(s, ':') || check_hdr) { // other headers go verbatim // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. @@ -389,14 +389,27 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // so stop "analyze headers" mode reenter: // put recipients specified on cmdline + check_hdr = 1; while (*argv) { char *t = sane_address(*argv); rcptto(t); //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) // goto bail; - if (!has_to) + if (!has_to) { + const char *hdr; + + if (check_hdr && argv[1]) + hdr = "To: %s,"; + else if (check_hdr) + hdr = "To: %s"; + else if (argv[1]) + hdr = "To: %s," + 3; + else + hdr = "To: %s" + 3; llist_add_to_end(&list, - xasprintf("To: %s", t)); + xasprintf(hdr, t)); + check_hdr = 0; + } argv++; } // enter "put message" mode -- cgit v1.2.3-55-g6feb From a42f530e034b673726a91ea5d8202254e677f066 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 18 Mar 2013 18:47:16 +0100 Subject: sendmail: code shrink on top of previous patches Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 72 ++++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index d58f503a0..b5aa1d17b 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -92,47 +92,37 @@ static int smtp_check(const char *fmt, int code) // strip argument of bad chars static char *sane_address(char *str) { - char *s = str; - char *p = s; - int leading_space = 1; - int trailing_space = 0; + char *s; + trim(str); + s = str; while (*s) { - if (isspace(*s)) { - trailing_space = !leading_space; - } else { - *p++ = *s; - if ((!isalnum(*s) && !strchr("_-.@", *s)) || - trailing_space) { - *p = '\0'; - bb_error_msg("Bad address: %s", str); - *str = '\0'; - return str; - } - leading_space = 0; + if (!isalnum(*s) && !strchr("_-.@", *s)) { + bb_error_msg("bad address '%s'", str); + /* returning "": */ + str[0] = '\0'; + return str; } s++; } - *p = '\0'; return str; } // check for an address inside angle brackets, if not found fall back to normal static char *angle_address(char *str) { - char *s = str; - char *e = str + strlen(str); - - while (e != str && (isspace(*e) || *e == '\0')) - e--; - if (*e != '>') - goto done; - *e = '\0'; - e = strrchr(s, '<'); - if (e != NULL) - s = e + 1; -done: - return sane_address(s); + char *s, *e; + + trim(str); + e = last_char_is(str, '>'); + if (e) { + s = strrchr(str, '<'); + if (s) { + *e = '\0'; + str = s + 1; + } + } + return sane_address(str); } static void rcptto(const char *s) @@ -145,29 +135,27 @@ static void rcptto(const char *s) } // send to a list of comma separated addresses -static void rcptto_list(const char *_str) +static void rcptto_list(const char *list) { - char *str = xstrdup(_str); - int len = strlen(str); - int in_quote = 0; + char *str = xstrdup(list); char *s = str; char prev = 0; - int pos; + int in_quote = 0; - for (pos = 0; pos < len; pos++) { - char ch = str[pos]; + while (*s) { + char ch = *s++; if (ch == '"' && prev != '\\') { in_quote = !in_quote; } else if (!in_quote && ch == ',') { - str[pos] = '\0'; - rcptto(angle_address(s)); - s = str + pos + 1; + s[-1] = '\0'; + rcptto(angle_address(str)); + str = s; } prev = ch; } if (prev != ',') - rcptto(angle_address(s)); + rcptto(angle_address(str)); free(str); } @@ -349,7 +337,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // analyze headers // To: or Cc: headers add recipients - check_hdr = 0 == strncasecmp("To:", s, 3); + check_hdr = (0 == strncasecmp("To:", s, 3)); has_to |= check_hdr; if (opts & OPT_t) { if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) { -- cgit v1.2.3-55-g6feb