]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
hostname: re-read file later when failed to update file
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 22 Jan 2021 07:38:52 +0000 (16:38 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 9 Feb 2021 04:49:27 +0000 (13:49 +0900)
Previously, even when writing e.g. /etc/hostname fails, the static
hostname in Context is not restored. So, the subsequent call of the same
method succeeds:
```
$ sudo chattr +i /etc/hostname
$ sudo hostnamectl --static set-hostname aaa
Could not set static hostname: Access denied
$ echo $?
1
$ sudo hostnamectl --static set-hostname aaa
$ echo $?
0
```

This makes when updating file is failed, the saved stat is cleared. So,
the static hostname or machine information in the context are always
consistent to the corresponding files.

src/hostname/hostnamed.c

index cc5c21cd1f875bf0236b9825509f60431296b10d..73949fbfb8949e373fe93e37e1a54cf596bfdc6a 100644 (file)
@@ -367,20 +367,41 @@ static int context_update_kernel_hostname(
         return r; /* 0 if no change, 1 if something was done  */
 }
 
+static void unset_statp(struct stat **p) {
+        if (!*p)
+                return;
+
+        **p = (struct stat) {};
+}
+
 static int context_write_data_static_hostname(Context *c) {
+        _cleanup_(unset_statp) struct stat *s = NULL;
+        int r;
+
         assert(c);
 
+        /* Make sure that if we fail here, we invalidate the cached information, since it was updated
+         * already, even if we can't make it hit the disk. */
+        s = &c->etc_hostname_stat;
+
         if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
-                if (unlink("/etc/hostname") < 0)
-                        return errno == ENOENT ? 0 : -errno;
+                if (unlink("/etc/hostname") < 0 && errno != ENOENT)
+                        return -errno;
+
+                TAKE_PTR(s);
                 return 0;
         }
 
-        return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
+        r = write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
+        if (r < 0)
+                return r;
+
+        TAKE_PTR(s);
+        return 0;
 }
 
 static int context_write_data_machine_info(Context *c) {
-
+        _cleanup_(unset_statp) struct stat *s = NULL;
         static const char * const name[_PROP_MAX] = {
                 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
                 [PROP_ICON_NAME] = "ICON_NAME",
@@ -388,12 +409,15 @@ static int context_write_data_machine_info(Context *c) {
                 [PROP_DEPLOYMENT] = "DEPLOYMENT",
                 [PROP_LOCATION] = "LOCATION",
         };
-
         _cleanup_strv_free_ char **l = NULL;
         int r;
 
         assert(c);
 
+        /* Make sure that if we fail here, we invalidate the cached information, since it was updated
+         * already, even if we can't make it hit the disk. */
+        s = &c->etc_machine_info_stat;
+
         r = load_env_file(NULL, "/etc/machine-info", &l);
         if (r < 0 && r != -ENOENT)
                 return r;
@@ -421,13 +445,19 @@ static int context_write_data_machine_info(Context *c) {
         }
 
         if (strv_isempty(l)) {
-                if (unlink("/etc/machine-info") < 0)
-                        return errno == ENOENT ? 0 : -errno;
+                if (unlink("/etc/machine-info") < 0 && errno != ENOENT)
+                        return -errno;
 
+                TAKE_PTR(s);
                 return 0;
         }
 
-        return write_env_file_label("/etc/machine-info", l);
+        r = write_env_file_label("/etc/machine-info", l);
+        if (r < 0)
+                return r;
+
+        TAKE_PTR(s);
+        return 0;
 }
 
 static int property_get_hardware_vendor(