Commit 36ef9b2c authored by Rusty Russell's avatar Rusty Russell

Helper routines for saving errno in error paths.

parent c62437a9
#include <stdio.h>
#include <string.h>
#include "config.h"
/**
* noerr - routines for cleaning up without blatting errno
*
* It is a good idea to follow the standard C convention of setting errno in
* your own helper functions. Unfortunately, care must be taken in the error
* paths as most standard functions can (and do) overwrite errno, even if they
* succeed.
*
* Example:
* #include <sys/types.h>
* #include <sys/stat.h>
* #include <fcntl.h>
*
* bool write_string_to_file(const char *file, const char *string)
* {
* int ret, fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0600);
* if (fd < 0)
* return false;
* ret = write(fd, string, strlen(string));
* if (ret < 0) {
* // Preserve errno from write above.
* close_noerr(fd);
* unlink_noerr(file);
* return false;
* }
* if (close(fd) != 0) {
* // Again, preserve errno.
* unlink_noerr(file);
* return false;
* }
* // A short write means out of space.
* if (ret < strlen(string)) {
* unlink(file);
* errno = ENOSPC;
* return false;
* }
* return true;
* }
*/
int main(int argc, char *argv[])
{
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0)
/* Nothing. */
return 0;
return 1;
}
#include "noerr.h"
#include <unistd.h>
#include <errno.h>
int close_noerr(int fd)
{
int saved_errno = errno, ret;
if (close(fd) != 0)
ret = errno;
else
ret = 0;
errno = saved_errno;
return ret;
}
int unlink_noerr(const char *pathname)
{
int saved_errno = errno, ret;
if (unlink(pathname) != 0)
ret = errno;
else
ret = 0;
errno = saved_errno;
return ret;
}
#ifndef NOERR_H
#define NOERR_H
/**
* close_noerr - close without stomping errno.
* @fd: the file descriptor to close.
*
* errno is saved and restored across the call to close: if an error occurs,
* the resulting (non-zero) errno is returned.
*/
int close_noerr(int fd);
/**
* unlink_noerr - unlink a file without stomping errno.
* @pathname: the path to unlink.
*
* errno is saved and restored across the call to unlink: if an error occurs,
* the resulting (non-zero) errno is returned.
*/
int unlink_noerr(const char *pathname);
#endif /* NOERR_H */
#include "noerr/noerr.h"
#include "tap.h"
#include "noerr/noerr.c"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <assert.h>
int main(int argc, char *argv[])
{
/* tempnam(3) is generally a bad idea, but OK here. */
char *name = tempnam(NULL, "noerr");
int fd;
plan_tests(12);
/* Should fail to unlink. */
ok1(unlink(name) != 0);
ok1(errno == ENOENT);
/* This one should not set errno. */
errno = 100;
ok1(unlink_noerr(name) == ENOENT);
ok1(errno == 100);
/* Should fail to close. */
ok1(close(-1) != 0);
ok1(errno == EBADF);
/* This one should not set errno. */
errno = 100;
ok1(close_noerr(-1) == EBADF);
ok1(errno == 100);
/* Test successful close/unlink doesn't hit errno either. */
fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0600);
assert(fd >= 0);
errno = 100;
ok1(close_noerr(fd) == 0);
ok1(errno == 100);
errno = 100;
ok1(unlink_noerr(name) == 0);
ok1(errno == 100);
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment