Even if /run exists, it may not be world-writable. This is the case on
NixOS. Add an alternative option to lock the device node instead.

This should eventually be made the default when it has enjoyed more
testing.

Signed-off-by: Ahmad Fatoum <a.fat...@pengutronix.de>
---
 configure.ac              |  9 +++++++++
 meson.build               |  1 +
 src/barebox-state.c       | 30 ++++++++++++++++++------------
 src/barebox-state/state.c |  4 ++++
 src/barebox-state/state.h | 21 +++++++++++++++++++++
 5 files changed, 53 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index be8967eb0809..117a1e169ba9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -27,6 +27,15 @@ AS_IF([test "x${enable_state_backward_compatibility}" = 
"xyes"], [
         AC_DEFINE(CONFIG_STATE_BACKWARD_COMPATIBLE, [0])
 ])
 
+AC_ARG_ENABLE([lock-device],
+        AS_HELP_STRING([--enable-lock-device], [barebox-state: lock device 
node instead of global lock in /run @<:@default=disabled@:>@]),
+        [], [enable_lock_device=no])
+AS_IF([test "x${enable_lock_device}" = "xyes"], [
+        AC_DEFINE(CONFIG_LOCK_DEVICE_NODE, [1], [lock device node backing 
state.])
+], [
+        AC_DEFINE(CONFIG_LOCK_DEVICE_NODE, [0], [use global lock in /run.])
+])
+
 AC_DEFINE(CONFIG_MTD, [1], [Statically define to be enabled to harmonize 
barebox' & dt-utils' code base.])
 
 AC_DEFINE(CONFIG_STATE, [1], [Statically define to be enabled to harmonize 
barebox' & dt-utils' code base.])
diff --git a/meson.build b/meson.build
index 22b522ea4d0e..2fc13f55ed62 100644
--- a/meson.build
+++ b/meson.build
@@ -20,6 +20,7 @@ conf = configuration_data()
 conf.set10('CONFIG_MTD', true)
 conf.set10('CONFIG_STATE', true)
 conf.set10('CONFIG_STATE_BACKWARD_COMPATIBLE', 
get_option('state-backward-compatibility'))
+conf.set10('CONFIG_LOCK_DEVICE_NODE', get_option('lock-device'))
 
 meson.add_dist_script(
   find_program('check-news.sh').path(),
diff --git a/src/barebox-state.c b/src/barebox-state.c
index c5acd1f7780a..7cf2fbf070a9 100644
--- a/src/barebox-state.c
+++ b/src/barebox-state.c
@@ -499,6 +499,8 @@ int main(int argc, char *argv[])
                        printf(PACKAGE_STRING "\n");
                        printf("Configured with build-time option 
'--%s-state-backward-compatibility'.\n",
                               (CONFIG_STATE_BACKWARD_COMPATIBLE) ? "enable" : 
"disable");
+                       printf("                                  
'--%s-lock-device-node'.\n",
+                              (CONFIG_LOCK_DEVICE_NODE) ? "enable" : 
"disable");
                        exit(0);
                case 'g':
                        sg = xzalloc(sizeof(*sg));
@@ -568,17 +570,19 @@ int main(int argc, char *argv[])
                ++nr_states;
        }
 
-       lock_fd = open(BAREBOX_STATE_LOCKFILE, O_CREAT | O_RDWR, 0600);
-       if (lock_fd < 0) {
-               pr_err("Failed to open lock-file " BAREBOX_STATE_LOCKFILE "\n");
-               exit(1);
-       }
+       if (!IS_ENABLED(CONFIG_LOCK_DEVICE_NODE)) {
+               lock_fd = open(BAREBOX_STATE_LOCKFILE, O_CREAT | O_RDWR, 0600);
+               if (lock_fd < 0) {
+                       pr_err("Failed to open lock-file " 
BAREBOX_STATE_LOCKFILE "\n");
+                       exit(1);
+               }
 
-       ret = flock(lock_fd, LOCK_EX);
-       if (ret < 0) {
-               pr_err("Failed to lock " BAREBOX_STATE_LOCKFILE ": %m\n");
-               close(lock_fd);
-               exit(1);
+               ret = flock(lock_fd, LOCK_EX);
+               if (ret < 0) {
+                       pr_err("Failed to lock " BAREBOX_STATE_LOCKFILE ": 
%m\n");
+                       close(lock_fd);
+                       exit(1);
+               }
        }
 
        list_for_each_entry(state, &state_list.list, list) {
@@ -700,8 +704,10 @@ int main(int argc, char *argv[])
 
        ret = 0;
 out_unlock:
-       flock(lock_fd, LOCK_UN);
-       close(lock_fd);
+       if (!IS_ENABLED(CONFIG_LOCK_DEVICE_NODE)) {
+               flock(lock_fd, LOCK_UN);
+               close(lock_fd);
+       }
 
        return ret;
 }
diff --git a/src/barebox-state/state.c b/src/barebox-state/state.c
index 42ce88d3f161..371ae3959d6c 100644
--- a/src/barebox-state/state.c
+++ b/src/barebox-state/state.c
@@ -664,6 +664,10 @@ struct state *state_new_from_node(struct device_node 
*node, bool readonly)
        pr_debug("%s: backend resolved to %s %lld %zu\n", node->full_name,
                 state->backend_path, (long long)offset, size);
 
+       /* will be released on program exit */
+       if (IS_ENABLED(CONFIG_LOCK_DEVICE_NODE))
+               (void)open_exclusive(state->backend_path, readonly ? O_RDONLY : 
O_RDWR);
+
        state->backend_reproducible_name = 
of_get_reproducible_name(partition_node);
 
        ret = of_property_read_string(node, "backend-type", &backend_type);
diff --git a/src/barebox-state/state.h b/src/barebox-state/state.h
index 4abfa84285c3..bbbc1892f846 100644
--- a/src/barebox-state/state.h
+++ b/src/barebox-state/state.h
@@ -3,6 +3,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <driver.h>
+#include <sys/file.h>
 
 struct state;
 struct mtd_info_user;
@@ -269,3 +270,23 @@ static inline int state_string_copy_to_raw(struct 
state_string *string,
 
        return 0;
 }
+
+static inline int open_exclusive(const char *path, int flags)
+{
+       int fd;
+
+       fd = open(path, flags);
+       if (fd < 0)
+               return fd;
+
+       if (IS_ENABLED(CONFIG_LOCK_DEVICE_NODE)) {
+               int ret = flock(fd, LOCK_EX);
+               if (ret < 0) {
+                       pr_err("Failed to lock %s: %d\n", path, -errno);
+                       close(fd);
+                       return -EWOULDBLOCK;
+               }
+       }
+
+       return fd;
+}
-- 
2.39.2


Reply via email to