summaryrefslogtreecommitdiffstats
path: root/discover/grub2
diff options
context:
space:
mode:
authorAlan Dunn <amdunn@google.com>2016-02-24 08:12:25 -0800
committerSam Mendoza-Jonas <sam@mendozajonas.com>2016-03-15 14:10:22 +1100
commit939660528bf1568c55b6dcf982cc9020c1dbcdd2 (patch)
tree7163c3684434f644537ea253b95305fe9b2ec466 /discover/grub2
parent6e5cd61065181460be8152a73dfc79f94ecd27fe (diff)
downloadtalos-petitboot-939660528bf1568c55b6dcf982cc9020c1dbcdd2.tar.gz
talos-petitboot-939660528bf1568c55b6dcf982cc9020c1dbcdd2.zip
Change parser interface to allow stat
Currently, the GRUB2 parser incorrectly reports "[ -f <path> ]" as false if the size of the file is above 1 MB. This patch changes the parser interface to allow stating files (with parser_stat_file). Then in the implementation of "[ -f <path> ]", we can use parser_stat_file instead of parser_request_file which has the size limitation. I eliminate parser_check_dir in lieu of this new interface, which has the side effect of making "[ -d <path> ]" work (the error code for stat was not checked correctly before). I add a basic test for the test file operations -f, -s, and -d (to show that my changes to test file operations do not break them) and minorly modify the test framework to ensure it has enough fidelity to cause the expected results. Unfortunately the test wouldn't have caught the issue with -d, since the test framework stubs out the parser interface itself. Nor can the test framework catch the initial problem with -f because the imposed limit is (transitively) in function parser_request_file. Note that -f and -d follow symlinks despite the fact that GRUB does not (see http://lists.gnu.org/archive/html/grub-devel/2016-02/msg00142.html discussing GRUB's behavior). This is not a change to Petitboot's behavior though. Tested: The test test-grub2-test-file-ops passes. I booted Petitboot against a GRUB snippet: status=success if [ ! -f /large_file -a $status = success ] then status=fail_large_file fi if [ ! -d /a_directory -a $status = success ] then status=fail_dir fi menuentry $status { linux /vmlinux } (after making /large_file a file of size > 1 MiB and /a_directory a directory) and the menuentry had title "success", as desired. Signed-off-by: Alan Dunn <amdunn@google.com> Signed-off-by: Sam Mendoza-Jonas <sam@mendozajonas.com>
Diffstat (limited to 'discover/grub2')
-rw-r--r--discover/grub2/builtins.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c
index 6ada2a6..8bff732 100644
--- a/discover/grub2/builtins.c
+++ b/discover/grub2/builtins.c
@@ -124,43 +124,58 @@ static int builtin_search(struct grub2_script *script,
return 0;
}
+/* Note that GRUB does not follow symlinks in evaluating all file
+ * tests but -s, unlike below. However, it seems like a bad idea to
+ * emulate GRUB's behavior (e.g., it would take extra work), so we
+ * implement the behavior that coreutils' test binary has. */
static bool builtin_test_op_file(struct grub2_script *script, char op,
const char *file)
{
bool result;
- int len, rc;
- char *buf;
+ int rc;
+ struct stat statbuf;
- rc = parser_request_file(script->ctx, script->ctx->device,
- file, &buf, &len);
+ rc = parser_stat_path(script->ctx, script->ctx->device,
+ file, &statbuf);
if (rc)
return false;
switch (op) {
case 's':
/* -s: return true if file exists and has non-zero size */
- result = len > 0;
+ result = statbuf.st_size > 0;
break;
case 'f':
- /* -f: return true if file exists */
- result = true;
+ /* -f: return true if file exists and is not a directory. This is
+ * different than the behavior of "test", but is what GRUB does
+ * (though note as above that we follow symlinks unlike GRUB). */
+ result = !S_ISDIR(statbuf.st_mode);
break;
default:
result = false;
}
- talloc_free(buf);
return result;
}
+/* See comment at builtin_test_op_file for differences between how
+ * GRUB implements file tests versus Petitboot's GRUB parser. */
static bool builtin_test_op_dir(struct grub2_script *script, char op,
const char *dir)
{
+ int rc;
+ struct stat statbuf;
+
if (op != 'd')
return false;
- return parser_check_dir(script->ctx, script->ctx->device, dir) == 0;
+ rc = parser_stat_path(script->ctx, script->ctx->device, dir, &statbuf);
+ if (rc) {
+ return false;
+ }
+
+ return S_ISDIR(statbuf.st_mode);
}
static bool builtin_test_op(struct grub2_script *script,
OpenPOWER on IntegriCloud