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:
Thomas Haller
2016-04-20 11:09:25 +02:00
parent eab817d34a
commit 67d45ea1d3

View File

@@ -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;