From 4a97d5bab9f2369e8af32617da3c780b59a817f2 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Fri, 10 Feb 2017 10:03:19 +0100 Subject: [PATCH] libopkg: do not rely on getline() OpenWrt/LEDE uses opkg on both the target systems and the build hosts and not every supported host system provides a getline() implementation. Rewrite affected code to not require the getline() function. Signed-off-by: Jo-Philipp Wich --- libopkg/parse_util.c | 82 ++++++++++++++++++++++++++++++++++ libopkg/parse_util.h | 4 ++ libopkg/pkg_hash.c | 9 +++- libopkg/pkg_parse.c | 98 +++++------------------------------------ libopkg/pkg_parse.h | 5 ++- libopkg/release_parse.c | 27 ++++-------- 6 files changed, 116 insertions(+), 109 deletions(-) diff --git a/libopkg/parse_util.c b/libopkg/parse_util.c index e01b124..fbecba6 100644 --- a/libopkg/parse_util.c +++ b/libopkg/parse_util.c @@ -22,6 +22,7 @@ #include "libbb/libbb.h" #include "parse_util.h" +#include "pkg_parse.h" int is_field(const char *type, const char *line) @@ -86,3 +87,84 @@ parse_list(const char *raw, unsigned int *count, const char sep, int skip_field) *count = line_count; return depends; } + +int +parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask, + char **buf0, size_t buf0len) +{ + int ret, lineno; + char *buf, *nl; + size_t buflen; + + lineno = 1; + ret = 0; + + buflen = buf0len; + buf = *buf0; + buf[0] = '\0'; + + while (1) { + if (fgets(buf, (int)buflen, fp) == NULL) { + if (ferror(fp)) { + opkg_perror(ERROR, "fgets"); + ret = -1; + } else if (strlen(*buf0) == buf0len-1) { + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(item, *buf0, mask); + } + break; + } + + nl = strchr(buf, '\n'); + if (nl == NULL) { + if (strlen(buf) < buflen-1) { + /* + * Line could be exactly buflen-1 long and + * missing a newline, but we won't know until + * fgets fails to read more data. + */ + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(item, *buf0, mask); + break; + } + if (buf0len >= EXCESSIVE_LINE_LEN) { + opkg_msg(ERROR, "Excessively long line at " + "%d. Corrupt file?\n", + lineno); + ret = -1; + break; + } + + /* + * Realloc and point buf past the data already read, + * at the NULL terminator inserted by fgets. + * |<--------------- buf0len ----------------->| + * | |<------- buflen ---->| + * |---------------------|---------------------| + * buf0 buf + */ + buflen = buf0len +1; + buf0len *= 2; + *buf0 = xrealloc(*buf0, buf0len); + buf = *buf0 + buflen -2; + + continue; + } + + *nl = '\0'; + + lineno++; + + if (parse_line(item, *buf0, mask)) + break; + + buf = *buf0; + buflen = buf0len; + buf[0] = '\0'; + } + + return ret; +} + diff --git a/libopkg/parse_util.h b/libopkg/parse_util.h index e4e2abe..3263509 100644 --- a/libopkg/parse_util.h +++ b/libopkg/parse_util.h @@ -22,4 +22,8 @@ int is_field(const char *type, const char *line); char *parse_simple(const char *type, const char *line); char **parse_list(const char *raw, unsigned int *count, const char sep, int skip_field); +typedef int (*parse_line_t)(void *, const char *, uint); +int parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask, + char **buf0, size_t buf0len); + #endif diff --git a/libopkg/pkg_hash.c b/libopkg/pkg_hash.c index 2a76be8..7f76da1 100644 --- a/libopkg/pkg_hash.c +++ b/libopkg/pkg_hash.c @@ -23,6 +23,7 @@ #include "opkg_message.h" #include "pkg_vec.h" #include "pkg_hash.h" +#include "parse_util.h" #include "pkg_parse.h" #include "opkg_utils.h" #include "sprintf_alloc.h" @@ -119,8 +120,14 @@ pkg_hash_add_from_file(const char *file_name, pkg->src = src; pkg->dest = dest; - ret = pkg_parse_from_stream_nomalloc(pkg, fp, 0, + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, 0, &buf, len); + + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + if (ret) { pkg_deinit (pkg); free(pkg); diff --git a/libopkg/pkg_parse.c b/libopkg/pkg_parse.c index e0d7fce..b54ad9a 100644 --- a/libopkg/pkg_parse.c +++ b/libopkg/pkg_parse.c @@ -104,9 +104,11 @@ get_arch_priority(const char *arch) return 0; } -static int -pkg_parse_line(pkg_t *pkg, const char *line, uint mask) +int +pkg_parse_line(void *ptr, const char *line, uint mask) { + pkg_t *pkg = (pkg_t *) ptr; + /* these flags are a bit hackish... */ static int reading_conffiles = 0, reading_description = 0; int ret = 0; @@ -265,91 +267,6 @@ dont_reset_flags: return ret; } -int -pkg_parse_from_stream_nomalloc(pkg_t *pkg, FILE *fp, uint mask, - char **buf0, size_t buf0len) -{ - int ret, lineno; - char *buf, *nl; - size_t buflen; - - lineno = 1; - ret = 0; - - buflen = buf0len; - buf = *buf0; - buf[0] = '\0'; - - while (1) { - if (fgets(buf, (int)buflen, fp) == NULL) { - if (ferror(fp)) { - opkg_perror(ERROR, "fgets"); - ret = -1; - } else if (strlen(*buf0) == buf0len-1) { - opkg_msg(ERROR, "Missing new line character" - " at end of file!\n"); - pkg_parse_line(pkg, *buf0, mask); - } - break; - } - - nl = strchr(buf, '\n'); - if (nl == NULL) { - if (strlen(buf) < buflen-1) { - /* - * Line could be exactly buflen-1 long and - * missing a newline, but we won't know until - * fgets fails to read more data. - */ - opkg_msg(ERROR, "Missing new line character" - " at end of file!\n"); - pkg_parse_line(pkg, *buf0, mask); - break; - } - if (buf0len >= EXCESSIVE_LINE_LEN) { - opkg_msg(ERROR, "Excessively long line at " - "%d. Corrupt file?\n", - lineno); - ret = -1; - break; - } - - /* - * Realloc and point buf past the data already read, - * at the NULL terminator inserted by fgets. - * |<--------------- buf0len ----------------->| - * | |<------- buflen ---->| - * |---------------------|---------------------| - * buf0 buf - */ - buflen = buf0len +1; - buf0len *= 2; - *buf0 = xrealloc(*buf0, buf0len); - buf = *buf0 + buflen -2; - - continue; - } - - *nl = '\0'; - - lineno++; - - if (pkg_parse_line(pkg, *buf0, mask)) - break; - - buf = *buf0; - buflen = buf0len; - buf[0] = '\0'; - } - - if (pkg->name == NULL) { - /* probably just a blank line */ - ret = 1; - } - - return ret; -} - int pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask) { @@ -358,8 +275,13 @@ pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask) const size_t len = 4096; buf = xmalloc(len); - ret = pkg_parse_from_stream_nomalloc(pkg, fp, mask, &buf, len); + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf, len); free(buf); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + return ret; } diff --git a/libopkg/pkg_parse.h b/libopkg/pkg_parse.h index 7020a90..bab88fb 100644 --- a/libopkg/pkg_parse.h +++ b/libopkg/pkg_parse.h @@ -18,10 +18,11 @@ #ifndef PKG_PARSE_H #define PKG_PARSE_H +#include "pkg.h" + int parse_version(pkg_t *pkg, const char *raw); int pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask); -int pkg_parse_from_stream_nomalloc(pkg_t *pkg, FILE *fp, uint mask, - char **buf0, size_t buf0len); +int pkg_parse_line(void *ptr, const char *line, uint mask); #define EXCESSIVE_LINE_LEN (4096 << 8) diff --git a/libopkg/release_parse.c b/libopkg/release_parse.c index e1d9a84..f411045 100644 --- a/libopkg/release_parse.c +++ b/libopkg/release_parse.c @@ -23,8 +23,10 @@ #include "parse_util.h" static int -release_parse_line(release_t *release, const char *line) +release_parse_line(void *ptr, const char *line, uint mask) { + release_t *release = (release_t *) ptr; + int ret = 0; unsigned int count = 0; char **list = 0; @@ -111,25 +113,14 @@ dont_reset_flags: int release_parse_from_stream(release_t *release, FILE *fp) { - int ret = 0; - char *buf = NULL; - size_t buflen, nread; - - nread = getline(&buf, &buflen, fp); - while ( nread != -1 ) { - if (buf[nread-1] == '\n') buf[nread-1] = '\0'; - if (release_parse_line(release, buf)) - opkg_msg(DEBUG, "Failed to parse release line for %s:\n\t%s\n", - release->name, buf); - nread = getline(&buf, &buflen, fp); - } - - if (!feof(fp)) { - opkg_perror(ERROR, "Problems reading Release file for %sd\n", release->name); - ret = -1; - } + int ret; + char *buf; + const size_t len = 4096; + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len); free(buf); + return ret; } -- 2.25.1