platform: preserve errno in nm_platform_sysctl_set()
We want to preserve the relevant errno during nm_platform_sysctl_set(). Also, if the final close() fails, fail altogether.
This commit is contained in:
@@ -2473,6 +2473,7 @@ sysctl_set (NMPlatform *platform, const char *path, const char *value)
|
|||||||
gsize len;
|
gsize len;
|
||||||
char *actual;
|
char *actual;
|
||||||
gs_free char *actual_free = NULL;
|
gs_free char *actual_free = NULL;
|
||||||
|
int errsv;
|
||||||
|
|
||||||
g_return_val_if_fail (path != NULL, FALSE);
|
g_return_val_if_fail (path != NULL, FALSE);
|
||||||
g_return_val_if_fail (value != NULL, FALSE);
|
g_return_val_if_fail (value != NULL, FALSE);
|
||||||
@@ -2483,18 +2484,22 @@ sysctl_set (NMPlatform *platform, const char *path, const char *value)
|
|||||||
/* Don't write to suspicious locations */
|
/* Don't write to suspicious locations */
|
||||||
g_assert (!strstr (path, "/../"));
|
g_assert (!strstr (path, "/../"));
|
||||||
|
|
||||||
if (!nm_platform_netns_push (platform, &netns))
|
if (!nm_platform_netns_push (platform, &netns)) {
|
||||||
|
errno = ENETDOWN;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
fd = open (path, O_WRONLY | O_TRUNC);
|
fd = open (path, O_WRONLY | O_TRUNC);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
if (errno == ENOENT) {
|
errsv = errno;
|
||||||
|
if (errsv == ENOENT) {
|
||||||
_LOGD ("sysctl: failed to open '%s': (%d) %s",
|
_LOGD ("sysctl: failed to open '%s': (%d) %s",
|
||||||
path, errno, strerror (errno));
|
path, errsv, strerror (errsv));
|
||||||
} else {
|
} else {
|
||||||
_LOGE ("sysctl: failed to open '%s': (%d) %s",
|
_LOGE ("sysctl: failed to open '%s': (%d) %s",
|
||||||
path, errno, strerror (errno));
|
path, errsv, strerror (errsv));
|
||||||
}
|
}
|
||||||
|
errno = errsv;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2515,26 +2520,43 @@ sysctl_set (NMPlatform *platform, const char *path, const char *value)
|
|||||||
actual[len] = '\0';
|
actual[len] = '\0';
|
||||||
|
|
||||||
/* Try to write the entire value three times if a partial write occurs */
|
/* Try to write the entire value three times if a partial write occurs */
|
||||||
|
errsv = 0;
|
||||||
for (tries = 0, nwrote = 0; tries < 3 && nwrote != len; tries++) {
|
for (tries = 0, nwrote = 0; tries < 3 && nwrote != len; tries++) {
|
||||||
nwrote = write (fd, actual, len);
|
nwrote = write (fd, actual, len);
|
||||||
if (nwrote == -1) {
|
if (nwrote == -1) {
|
||||||
if (errno == EINTR) {
|
errsv = errno;
|
||||||
|
if (errsv == EINTR) {
|
||||||
_LOGD ("sysctl: interrupted, will try again");
|
_LOGD ("sysctl: interrupted, will try again");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nwrote == -1 && errno != EEXIST) {
|
if (nwrote == -1 && errsv != EEXIST) {
|
||||||
_LOGE ("sysctl: failed to set '%s' to '%s': (%d) %s",
|
_LOGE ("sysctl: failed to set '%s' to '%s': (%d) %s",
|
||||||
path, value, errno, strerror (errno));
|
path, value, errsv, strerror (errsv));
|
||||||
} else if (nwrote < len) {
|
} else if (nwrote < len) {
|
||||||
_LOGE ("sysctl: failed to set '%s' to '%s' after three attempts",
|
_LOGE ("sysctl: failed to set '%s' to '%s' after three attempts",
|
||||||
path, value);
|
path, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
close (fd);
|
if (nwrote != len) {
|
||||||
return (nwrote == len);
|
if (close (fd) != 0) {
|
||||||
|
if (errsv != 0)
|
||||||
|
errno = errsv;
|
||||||
|
} else if (errsv != 0)
|
||||||
|
errno = errsv;
|
||||||
|
else
|
||||||
|
errno = EIO;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (close (fd) != 0) {
|
||||||
|
/* errno is already properly set. */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success. errno is undefined (no need to set). */
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GSList *sysctl_clear_cache_list;
|
static GSList *sysctl_clear_cache_list;
|
||||||
|
Reference in New Issue
Block a user