Hello Louis Yung-Chieh Lo, build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/22490
to look at the new patch set (#2).
Change subject: Add a file utility library
......................................................................
Add a file utility library
This adds a library for BSD-licensed helper functions for dealing
with files.
Currently the library only has scanft() which was ported over from
mosys. This function recursively scans files in a filesystem tree
and can optionally match the beginning content. This is particularly
useful for searching for devices in sysfs, which may be infinitely
recursive (due to symlinks) and typically contain single values, such
as a module alias.
BUG=none
TEST=used in follow-up CLs to find I2C and SPI buses and addresses
Example test output using /sys/bus/i2c/devices/ as root path,
following 2 levels of symbolic links, physical i2c bus is 4 but
got shifted to 6:
gec_i2c_probe_programmer: probing for GEC on I2C...
gec_i2c_probe_programmer: chromeos-ec found in \
"/sys/bus/i2c/devices/i2c-6/6-001e/name"
gec_i2c_probe_programmer: bus: 6, addr: 0x1e
Change-Id: I6c86ad3a50748e6bdbaa6675b05e75ef714b3994
Reviewed-on: https://gerrit.chromium.org/gerrit/23466
Reviewed-by: Yung-Chieh Lo <yjlou%chromium.org(a)gtempaccount.com>
Commit-Ready: David Hendricks <dhendrix(a)chromium.org>
Tested-by: David Hendricks <dhendrix(a)chromium.org>
---
M Makefile
A file.c
A file.h
3 files changed, 175 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/90/22490/2
--
To view, visit https://review.coreboot.org/22490
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I6c86ad3a50748e6bdbaa6675b05e75ef714b3994
Gerrit-Change-Number: 22490
Gerrit-PatchSet: 2
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
Gerrit-Reviewer: Louis Yung-Chieh Lo <yjlou(a)chromium.org>
Gerrit-Reviewer: build bot (Jenkins) <no-reply(a)coreboot.org>
Hello Brian Norris,
I'd like you to do a code review. Please visit
https://review.coreboot.org/22494
to review the following change.
Change subject: file: read in entire file (up to 4K) instead of stat()'ing for size
......................................................................
file: read in entire file (up to 4K) instead of stat()'ing for size
We use find_string() to check files in both /proc (e.g.,
/proc/device-tree/...) and /sys (e.g., /sys/bus/spi/devices/...).
find_string() currently tries to iteratively read pieces of these files,
using stat() to get the file size. However, this size is inaccurate on
sysfs, as these files are often dynamically generated, so it reports a
size of PAGE_SIZE (i.e., 4096).
Instead of trying to pre-determine the file size, let's read in the
whole file (up to 4KiB - 1) and do a series of string searches to find
any matching strings. The 4KiB limitation should be OK, since we're only
looking for things like modalias and compatible strings.
As a side effect, this eliminates a lot of unnecessary strlen() calls,
and allows us to again avoid hand-rolling strstr().
BUG=chrome-os-partner:51651
BRANCH=none
TEST=`flashrom --wp-status` doesn't show log spam
TEST=`flashrom --read /tmp/flashX` gives same results before/after
Change-Id: I2d053b18ba624f4ce3ebc1956b9e7945b693b0bc
Signed-off-by: Brian Norris <briannorris(a)chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/335353
Reviewed-by: David Hendricks <dhendrix(a)chromium.org>
---
M file.c
1 file changed, 41 insertions(+), 44 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/94/22494/1
diff --git a/file.c b/file.c
index 3b9abdf..7b39428 100644
--- a/file.c
+++ b/file.c
@@ -50,21 +50,36 @@
#define FDT_ROOT "/proc/device-tree"
#define FDT_ALIASES "/proc/device-tree/aliases"
+/* Like strstr(), but allowing NULL bytes within haystack */
+static int __find_string(const char *haystack, size_t hlen, const char *needle)
+{
+ const char *p = haystack;
+ const char *end = haystack + hlen;
+
+ while (p < end) {
+ if (strstr(p, needle))
+ return 1;
+ p = memchr(p, '\0', end - p);
+ if (!p)
+ /* Not found? We're at the end */
+ return 0;
+ else
+ /* Skip past the NULL separator */
+ p++;
+ }
+
+ return 0;
+}
+
/* returns 1 if string if found, 0 if not, and <0 to indicate error */
static int find_string(const char *path, const char *str)
{
- int fd, ret = 0;
- struct stat s;
- off_t i;
+ char contents[4096];
+ int fd, ret;
+ ssize_t len;
- if (stat(path, &s) < 0) {
- msg_gerr("Cannot stat file \"%s\"\n", path);
- ret = -1;
- goto find_string_exit_0;
- }
-
- if (s.st_size < strlen(str))
- goto find_string_exit_0;
+ msg_pdbg("%s: checking path \"%s\" for contents \"%s\"\n",
+ __func__, path, str);
fd = open(path, O_RDONLY, 0);
if (fd < 0) {
@@ -73,39 +88,18 @@
goto find_string_exit_0;
}
- /* mmap() would be nice but it might not be implemented for some
- * files in sysfs and procfs */
- for (i = 0; i <= s.st_size - strlen(str); i++) {
- int match_found = 1;
- off_t j;
-
- if (lseek(fd, i, SEEK_SET) == (off_t)-1) {
- msg_gerr("Failed to seek within \"%s\"\n", path);
- ret = -1;
- goto find_string_exit_1;
- }
-
- for (j = 0; j < strlen(str); j++) {
- char c;
-
- if (read(fd, &c, 1) != 1) {
- msg_gerr("Failed to read \"%s\"\n", path);
- ret = -1;
- goto find_string_exit_1;
- }
-
- if (str[j] != c) {
- match_found = 0;
- break;
- }
- }
-
- if (match_found) {
- ret = 1;
- break;
- }
-
+ /* mmap() (or even read() with a file length) would be nice but these
+ * might not be implemented for files in sysfs and procfs.
+ * Let's also leave room for a terminator. */
+ len = read(fd, contents, sizeof(contents) - 1);
+ if (len == -1) {
+ msg_gerr("Cannot read file \"%s\"\n", path);
+ ret = -1;
+ goto find_string_exit_1;
}
+ /* Terminate the contents, in case they weren't terminated for us */
+ contents[len++] = '\0';
+ ret = __find_string(contents, len, str);
find_string_exit_1:
close(fd);
@@ -113,7 +107,7 @@
return ret;
}
- /*
+/*
* scanft - scan filetree for file with option to search for content
*
* @root: Where to begin search
@@ -125,6 +119,9 @@
* The caller should be specific enough with root and symdepth arguments
* to avoid finding duplicate information (especially in sysfs).
*
+ * Also, note that we may only scan a bounded portion of the beginning of the
+ * file for a match.
+ *
* returns allocated string with path of matching file if successful
* returns NULL to indicate failure
*/
--
To view, visit https://review.coreboot.org/22494
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2d053b18ba624f4ce3ebc1956b9e7945b693b0bc
Gerrit-Change-Number: 22494
Gerrit-PatchSet: 1
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
Gerrit-Reviewer: Brian Norris <briannorris(a)chromium.org>
Hello Brian Norris,
I'd like you to do a code review. Please visit
https://review.coreboot.org/22493
to review the following change.
Change subject: file: add new helper functions to grok FDT nodes
......................................................................
file: add new helper functions to grok FDT nodes
This file is intended to help find SPI devices using the FDT.
Here's how it works:
Under /proc/device-tree there is a node called "aliases" where
each file is a device name with an instance (e.g. "spi0"). The
content of the file is the controller's memory-mapped address.
That info can be used to find the appropriate node directory to
search under /proc/device-tree, where we can recursively search
for "compatible" nodes and scan for the matching user-provided
compatible string.
For SPI devices, we need to look for the matching "compatible"
node and then read the corresponding "reg" node to obtain chip-
select number.
BUG=chrome-os-partner:43453
BRANCH=none
TEST=reads now work on danger without specifying a SPI device
Signed-off-by: David Hendricks <dhendrix(a)chromium.org>
Change-Id: I1f771bcca61de71daa54e358e058723d3fd37079
Reviewed-on: https://chromium-review.googlesource.com/310072
Commit-Ready: David Hendricks <dhendrix(a)chromium.org>
Tested-by: David Hendricks <dhendrix(a)chromium.org>
Reviewed-by: Brian Norris <briannorris(a)chromium.org>
---
M file.c
M file.h
2 files changed, 160 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/93/22493/1
diff --git a/file.c b/file.c
index 24ded2a..3b9abdf 100644
--- a/file.c
+++ b/file.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2012, The Chromium OS Authors
+ * Copyright 2015, The Chromium OS Authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,16 +34,21 @@
#include <dirent.h>
#include <errno.h>
+#include <glob.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <arpa/inet.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "flash.h"
+
+#define FDT_ROOT "/proc/device-tree"
+#define FDT_ALIASES "/proc/device-tree/aliases"
/* returns 1 if string if found, 0 if not, and <0 to indicate error */
static int find_string(const char *path, const char *str)
@@ -171,3 +176,155 @@
closedir(dp);
return ret;
}
+
+/*
+ * do_fdt_find_spi_nor_flash - Search FDT via procfs for SPI NOR flash
+ *
+ * @prefix: Prefix of alias, for example "spi" will match spi*.
+ * @compat: String to look for in "compatible" node
+ *
+ * This function attempt to match FDT aliases with devices that have the given
+ * compatible string.
+ *
+ * Example: If prefix is "spi" and compat is "jedec,spi-nor" then this function
+ * will read the device descriptors in every alias beginning with "spi" and
+ * search their respective devicetree nodes for "compatible" files containing
+ * the string "jedec,spi-nor".
+ *
+ * returns 0 to indicate NOR flash has been found, <0 to indicate error
+ */
+static int do_fdt_find_spi_nor_flash(const char *prefix,
+ const char *compat, unsigned int *bus, uint32_t *cs)
+{
+ DIR *dp;
+ struct dirent *d;
+ struct stat s;
+ int found = 0;
+
+ if ((dp = opendir(FDT_ALIASES)) == NULL)
+ return -1;
+
+ /*
+ * This loop will go thru the aliases sub-directory and kick-off a
+ * recursive search thru matching devicetree nodes.
+ */
+ while (!found && (d = readdir(dp))) {
+ char node[PATH_MAX];
+ char pattern[PATH_MAX];
+ char alias[64];
+ int i, fd, len;
+ glob_t pglob;
+
+ /* allow partial match */
+ if (strncmp(prefix, d->d_name, strlen(prefix)))
+ continue;
+
+ sprintf(node, "%s/%s", FDT_ALIASES, d->d_name);
+ if (stat(node, &s) < 0) {
+ msg_pdbg("%s: Error stat'ing %s: %s\n",
+ __func__, node, strerror(errno));
+ continue;
+ }
+
+ if (!S_ISREG(s.st_mode))
+ continue;
+
+ fd = open(node, O_RDONLY);
+ if (fd < 0) {
+ msg_perr("Could not open %s\n", d->d_name);
+ continue;
+ }
+
+ /* devicetree strings and files aren't always terminated */
+ len = read(fd, alias, sizeof(alias) - 1);
+ if (len < 0) {
+ msg_perr("Could not read %s\n", d->d_name);
+ close(fd);
+ continue;
+ }
+ alias[len] = '\0';
+ close(fd);
+
+ /* We expect something in the form "/<type>@<address>", for
+ example "/spi@ff110000" */
+ if (alias[0] != '/')
+ continue;
+
+ snprintf(node, sizeof(node), "%s%s", FDT_ROOT, alias);
+
+ /*
+ * Descend into this node's directory. According to the DT
+ * specification, the SPI device node will be a subnode of
+ * the bus node. Thus, we need to look for:
+ * <path-to-spi-bus-node>/.../compatible
+ */
+ sprintf(pattern, "%s/*/compatible", node);
+ msg_pspew("Scanning glob pattern \"%s\"\n", pattern);
+ i = glob(pattern, 0, NULL, &pglob);
+ if (i == GLOB_NOSPACE)
+ goto err_out;
+ else if (i != 0)
+ continue;
+
+ /*
+ * For chip-select, look at the "reg" file located in
+ * the same sub-directory as the "compatible" file.
+ */
+ for (i = 0; i < pglob.gl_pathc; i++) {
+ char *reg_path;
+
+ if (!find_string(pglob.gl_pathv[i], compat))
+ continue;
+
+ reg_path = strdup(pglob.gl_pathv[i]);
+ if (!reg_path) {
+ globfree(&pglob);
+ goto err_out;
+ }
+
+ sprintf(strstr(reg_path, "compatible"), "reg");
+ fd = open(reg_path, O_RDONLY);
+ if (fd < 0) {
+ msg_gerr("Cannot open \"%s\"\n", reg_path);
+ free(reg_path);
+ continue;
+ }
+
+ /* value is a 32-bit big-endian unsigned in FDT. */
+ if (read(fd, cs, 4) != 4) {
+ msg_gerr("Cannot read \"%s\"\n", reg_path);
+ free(reg_path);
+ close(fd);
+ continue;
+ }
+
+ *cs = ntohl(*cs);
+ found = 1;
+ free(reg_path);
+ close(fd);
+ }
+
+ if (found) {
+ /* Extract bus from the alias filename. */
+ if (sscanf(d->d_name, "spi%u", bus) != 1) {
+ msg_gerr("Unexpected format: \"d->d_name\"\n");
+ found = 0;
+ globfree(&pglob);
+ goto err_out;
+ }
+ }
+
+ globfree(&pglob);
+ }
+
+err_out:
+ closedir(dp);
+ return found ? 0 : -1;
+}
+
+/* Wrapper in case we want to use a list of compat strings or extend
+ * this to search for other types of devices */
+int fdt_find_spi_nor_flash(unsigned int *bus, unsigned int *cs)
+{
+ return do_fdt_find_spi_nor_flash("spi", "jedec,spi-nor", bus, cs);
+}
diff --git a/file.h b/file.h
index ea37084..9af84bf 100644
--- a/file.h
+++ b/file.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2012, The Chromium OS Authors
+ * Copyright 2015, The Chromium OS Authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,3 +31,4 @@
const char *scanft(const char *root, const char *filename,
const char *str, int symdepth);
+int fdt_find_spi_nor_flash(unsigned int *bus, unsigned int *cs);
--
To view, visit https://review.coreboot.org/22493
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1f771bcca61de71daa54e358e058723d3fd37079
Gerrit-Change-Number: 22493
Gerrit-PatchSet: 1
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
Gerrit-Reviewer: Brian Norris <briannorris(a)chromium.org>
Hello Brian Norris,
I'd like you to do a code review. Please visit
https://review.coreboot.org/22492
to review the following change.
Change subject: file: Re-implement file parsing function
......................................................................
file: Re-implement file parsing function
This re-does the original file parsing function to be a little bit
more robust. The old version just copied the file content and did
a string compare. The new version will read the file character-by-
character, comparing with the specified string as we go along, until
a match is found.
BUG=none
BRANCH=none
TEST=Works as expected on veyron_mickey to grok thru sysfs. Also
tested with an upcoming FDT-related patch to search thru procfs.
Signed-off-by: David Hendricks <dhendrix(a)chromium.org>
Change-Id: I6e3811acf352d85c3f43192f87388833a997dd2c
Reviewed-on: https://chromium-review.googlesource.com/310653
Reviewed-by: Brian Norris <briannorris(a)chromium.org>
---
M file.c
1 file changed, 58 insertions(+), 28 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/92/22492/1
diff --git a/file.c b/file.c
index 8bc34aa..24ded2a 100644
--- a/file.c
+++ b/file.c
@@ -45,45 +45,75 @@
#include "flash.h"
-/*returns 1 if contents matches, 0 if not, and <0 to indicate error */
-static int file_contents_match(const char *path, const char *str)
+/* returns 1 if string if found, 0 if not, and <0 to indicate error */
+static int find_string(const char *path, const char *str)
{
- FILE *fp;
- char *content;
- int len = strlen(str);
- int ret = -1;
+ int fd, ret = 0;
+ struct stat s;
+ off_t i;
- content = malloc(len);
- if (!content)
- return -1;
-
- if ((fp = fopen(path, "r")) == NULL) {
- msg_pdbg("Error opening %s: %s\n", path, strerror(errno));
- goto file_contents_match_done;
- }
- if (fread(content, 1, len, fp) < 1) {
- msg_pdbg("Error reading %s: %s\n", path, strerror(ferror(fp)));
- goto file_contents_match_done;
+ if (stat(path, &s) < 0) {
+ msg_gerr("Cannot stat file \"%s\"\n", path);
+ ret = -1;
+ goto find_string_exit_0;
}
- if (!strncmp(str, content, len))
- ret = 1;
- else
- ret = 0;
+ if (s.st_size < strlen(str))
+ goto find_string_exit_0;
-file_contents_match_done:
- fclose(fp);
- free(content);
+ fd = open(path, O_RDONLY, 0);
+ if (fd < 0) {
+ msg_gerr("Cannot open file \"%s\"\n", path);
+ ret = -1;
+ goto find_string_exit_0;
+ }
+
+ /* mmap() would be nice but it might not be implemented for some
+ * files in sysfs and procfs */
+ for (i = 0; i <= s.st_size - strlen(str); i++) {
+ int match_found = 1;
+ off_t j;
+
+ if (lseek(fd, i, SEEK_SET) == (off_t)-1) {
+ msg_gerr("Failed to seek within \"%s\"\n", path);
+ ret = -1;
+ goto find_string_exit_1;
+ }
+
+ for (j = 0; j < strlen(str); j++) {
+ char c;
+
+ if (read(fd, &c, 1) != 1) {
+ msg_gerr("Failed to read \"%s\"\n", path);
+ ret = -1;
+ goto find_string_exit_1;
+ }
+
+ if (str[j] != c) {
+ match_found = 0;
+ break;
+ }
+ }
+
+ if (match_found) {
+ ret = 1;
+ break;
+ }
+
+ }
+
+find_string_exit_1:
+ close(fd);
+find_string_exit_0:
return ret;
}
/*
- * scanft - scan filetree for file with option to parse some content
+ * scanft - scan filetree for file with option to search for content
*
* @root: Where to begin search
* @filename: Name of file to search for
- * @str: Optional NULL terminated string to check at the beginning
- * of the file
+ * @str: Optional NULL terminated string to search for
* @symdepth: Maximum depth of symlinks to follow. A negative value means
* follow indefinitely. Zero means do not follow symlinks.
*
@@ -130,7 +160,7 @@
snprintf(newpath, sizeof(newpath), "%s/%s", root, d->d_name);
if (!strcmp(d->d_name, filename)) {
- if (!str || file_contents_match(newpath, str))
+ if (!str || (find_string(newpath, str) == 1))
ret = strdup(newpath);
}
--
To view, visit https://review.coreboot.org/22492
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6e3811acf352d85c3f43192f87388833a997dd2c
Gerrit-Change-Number: 22492
Gerrit-PatchSet: 1
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
Gerrit-Reviewer: Brian Norris <briannorris(a)chromium.org>
Hello Julius Werner,
I'd like you to do a code review. Please visit
https://review.coreboot.org/22491
to review the following change.
Change subject: avoid unnecessary syscalls in scanft()
......................................................................
avoid unnecessary syscalls in scanft()
This adds a test to see if the path given to scanft() is a symlink
or a directory before calling opendir() and readdir(). This cuts
down on syscalls which can be very slow.
BUG=none
BRANCH=none
TEST="flashrom -p host -i RW_ELOG:/tmp/elog.bin -r -V" ran on pit a
few hundred milliseconds faster (without other optimizations applied)
Change-Id: Ib067cfda1ba3edbc0b1bba604fa5eb57c64501f2
Reviewed-on: https://chromium-review.googlesource.com/176580
Commit-Queue: David Hendricks <dhendrix(a)chromium.org>
Tested-by: David Hendricks <dhendrix(a)chromium.org>
Reviewed-by: Julius Werner <jwerner(a)chromium.org>
---
M file.c
1 file changed, 2 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/91/22491/1
diff --git a/file.c b/file.c
index 6f15ff9..8bc34aa 100644
--- a/file.c
+++ b/file.c
@@ -112,6 +112,8 @@
return NULL;
else if (symdepth > 0) /* Follow if not too deep in */
symdepth--;
+ } else if (!S_ISDIR(s.st_mode)) {
+ return NULL;
}
if ((dp = opendir(root)) == NULL)
--
To view, visit https://review.coreboot.org/22491
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib067cfda1ba3edbc0b1bba604fa5eb57c64501f2
Gerrit-Change-Number: 22491
Gerrit-PatchSet: 1
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
Gerrit-Reviewer: Julius Werner <jwerner(a)chromium.org>