From 968c9e3e7715c080f23a1fd80c31d4bcf20d241b Mon Sep 17 00:00:00 2001 From: haozi007 Date: Thu, 16 Apr 2020 15:16:41 +0800 Subject: [PATCH 43/49] support error report Signed-off-by: haozi007 --- src/lxc/attach.c | 60 +++++++++++++++++++++++++++++++++++++++++++---- src/lxc/attach_options.h | 12 ++++++++++ src/lxc/cgroups/cgfsng.c | 1 + src/lxc/conf.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/conf.h | 5 ++++ src/lxc/execute.c | 7 ++++++ src/lxc/lxccontainer.c | 47 +++++++++++++++++++++++++++++++++++++ src/lxc/start.c | 21 +++++++++++++++++ src/lxc/start.h | 4 ++++ src/lxc/tools/lxc_ls.c | 8 +++++++ src/lxc/tools/lxc_start.c | 5 ++++ src/lxc/utils.c | 16 +++++++++++++ 12 files changed, 241 insertions(+), 4 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 510c069..734cddd 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -677,9 +677,13 @@ static int attach_child_main(struct attach_clone_payload *payload) bool needs_lsm = (options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label; - #ifdef HAVE_ISULAD - /*isulad: set system umask */ + int msg_fd = -1; + + /*isulad: record errpipe fd*/ + msg_fd = init_ctx->container->lxc_conf->errpipe[1]; + init_ctx->container->lxc_conf->errpipe[1] = -1; + /*isulad: set system umask */ umask(init_ctx->container->lxc_conf->umask); #endif @@ -963,10 +967,12 @@ static int attach_child_main(struct attach_clone_payload *payload) payload->ipc_socket = -EBADF; lxc_proc_put_context_info(init_ctx); payload->init_ctx = NULL; -#endif - + _exit(payload->exec_function(payload->exec_payload, msg_fd)); +#else /* We're done, so we can now do whatever the user intended us to do. */ _exit(payload->exec_function(payload->exec_payload)); +#endif + on_error: lxc_put_attach_clone_payload(payload); @@ -1331,6 +1337,25 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, return -1; } +#ifdef HAVE_ISULAD + /* isulad: pipdfd for get error message of child or grandchild process. */ + if (pipe2(conf->errpipe, O_CLOEXEC) != 0) { + SYSERROR("Failed to init errpipe"); + if (options->attach_flags & LXC_ATTACH_TERMINAL) { + lxc_terminal_delete(&terminal); + lxc_terminal_conf_free(&terminal); + if (exec_command.maincmd_fd != -1) { + close(exec_command.maincmd_fd); + } + } + close(ipc_sockets[0]); + close(ipc_sockets[1]); + free(cwd); + lxc_proc_put_context_info(init_ctx); + return -1; + } +#endif + /* Create intermediate subprocess, two reasons: * 1. We can't setns() in the child itself, since we want to make * sure we are properly attached to the pidns. @@ -1365,6 +1390,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, /* close unneeded file descriptors */ close(ipc_sockets[1]); free(cwd); +#ifdef HAVE_ISULAD + /* isulad: close errpipe */ + close(conf->errpipe[1]); + conf->errpipe[1] = -1; +#endif lxc_proc_close_ns_fd(init_ctx); if (options->attach_flags & LXC_ATTACH_TERMINAL) lxc_attach_terminal_close_slave(&terminal); @@ -1398,7 +1428,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, /* Setup resource limits */ if (!lxc_list_empty(&conf->limits)) { +#ifdef HAVE_ISULAD + ret = setup_resource_limits(&conf->limits, pid, -1); +#else ret = setup_resource_limits(&conf->limits, pid); +#endif if (ret < 0) goto on_error; } @@ -1561,6 +1595,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, /* close unneeded file descriptors */ close_prot_errno_disarm(ipc_sockets[0]); +#ifdef HAVE_ISULAD + /* isulad: close errpipe */ + close(conf->errpipe[0]); + conf->errpipe[0] = -1; +#endif + if (options->attach_flags & LXC_ATTACH_TERMINAL) { lxc_attach_terminal_close_master(&terminal); lxc_attach_terminal_close_peer(&terminal); @@ -1665,7 +1705,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, _exit(EXIT_SUCCESS); } +#ifdef HAVE_ISULAD +int lxc_attach_run_command(void *payload, int msg_fd) +#else int lxc_attach_run_command(void *payload) +#endif { int ret = -1; lxc_attach_command_t *cmd = payload; @@ -1681,11 +1725,19 @@ int lxc_attach_run_command(void *payload) break; } } +#ifdef HAVE_ISULAD + /* isulad: write error messages */ + lxc_write_error_message(msg_fd, "exec: \"%s\": %s.", cmd->program, strerror(errno)); +#endif return log_error_errno(ret, errno, "Failed to exec \"%s\"", cmd->program); } +#ifdef HAVE_ISULAD +int lxc_attach_run_shell(void* payload, int msg_fd) +#else int lxc_attach_run_shell(void* payload) +#endif { __do_free char *buf = NULL; uid_t uid; diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h index 5f01739..d5d4f44 100644 --- a/src/lxc/attach_options.h +++ b/src/lxc/attach_options.h @@ -49,7 +49,11 @@ enum { * * \return Function should return \c 0 on success, and any other value to denote failure. */ +#ifdef HAVE_ISULAD +typedef int (*lxc_attach_exec_t)(void* payload, int msg_fd); +#else typedef int (*lxc_attach_exec_t)(void* payload); +#endif /*! * LXC attach options for \ref lxc_container \c attach(). @@ -153,7 +157,11 @@ typedef struct lxc_attach_command_t { * * \return \c -1 on error, exit code of lxc_attach_command_t program on success. */ +#ifdef HAVE_ISULAD +extern int lxc_attach_run_command(void* payload, int msg_fd); +#else extern int lxc_attach_run_command(void* payload); +#endif /*! * \brief Run a shell command in the container. @@ -162,7 +170,11 @@ extern int lxc_attach_run_command(void* payload); * * \return Exit code of shell. */ +#ifdef HAVE_ISULAD +extern int lxc_attach_run_shell(void* payload, int msg_fd); +#else extern int lxc_attach_run_shell(void* payload); +#endif #ifdef __cplusplus } diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c index 1e1df3b..002f051 100644 --- a/src/lxc/cgroups/cgfsng.c +++ b/src/lxc/cgroups/cgfsng.c @@ -4233,6 +4233,7 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) cgfsng_ops->data_init = cgfsng_data_init; #ifdef HAVE_ISULAD + cgfsng_ops->errfd = conf ? conf->errpipe[1] : -1; cgfsng_ops->payload_destroy = isulad_cgfsng_payload_destroy; #else cgfsng_ops->payload_destroy = cgfsng_payload_destroy; diff --git a/src/lxc/conf.c b/src/lxc/conf.c index e8ee749..d7a78bd 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2275,8 +2275,15 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, if (hasmntopt(mntent, "create=dir")) { ret = mkdir_p(path, 0755); +#ifdef HAVE_ISULAD + if (ret < 0 && errno != EEXIST) { + lxc_write_error_message(rootfs->errfd, "%s:%d: mkdir %s: %s.", __FILE__, __LINE__, path, strerror(errno)); + return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); + } +#else if (ret < 0 && errno != EEXIST) return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); +#endif } if (!hasmntopt(mntent, "create=file")) @@ -2293,12 +2300,26 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, p2 = dirname(p1); ret = mkdir_p(p2, 0755); +#ifdef HAVE_ISULAD + if (ret < 0 && errno != EEXIST) { + lxc_write_error_message(rootfs->errfd, "%s:%d: mkdir %s: %s.", __FILE__, __LINE__, path, strerror(errno)); + return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); + } +#else if (ret < 0 && errno != EEXIST) return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); +#endif ret = mknod(path, S_IFREG | 0000, 0); +#ifdef HAVE_ISULAD + if (ret < 0 && errno != EEXIST) { + lxc_write_error_message(rootfs->errfd, "%s:%d: open %s: %s.", __FILE__, __LINE__, path, strerror(errno)); + return -errno; + } +#else if (ret < 0 && errno != EEXIST) return -errno; +#endif return 0; } @@ -2960,7 +2981,11 @@ static int parse_resource(const char *res) return resid; } +#ifdef HAVE_ISULAD +int setup_resource_limits(struct lxc_list *limits, pid_t pid, int errfd) +#else int setup_resource_limits(struct lxc_list *limits, pid_t pid) +#endif { int resid; struct lxc_list *it; @@ -2974,8 +2999,17 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) return log_error(-1, "Unknown resource %s", lim->resource); #if HAVE_PRLIMIT || HAVE_PRLIMIT64 +#if HAVE_ISULAD + if (prlimit(pid, resid, &lim->limit, NULL) != 0) { + lxc_write_error_message(errfd, "%s:%d: Failed to set limit %s %lu %lu: %s.", + __FILE__, __LINE__, lim->resource, + lim->limit.rlim_cur, lim->limit.rlim_max, strerror(errno)); + return log_error_errno(-1, errno, "Failed to set limit %s", lim->resource); + } +#else if (prlimit(pid, resid, &lim->limit, NULL) != 0) return log_error_errno(-1, errno, "Failed to set limit %s", lim->resource); +#endif TRACE("Setup \"%s\" limit", lim->resource); #else @@ -3134,6 +3168,9 @@ struct lxc_conf *lxc_conf_init(void) new->console.pipes[2][0] = -1; new->console.pipes[2][1] = -1; lxc_list_init(&new->console.fifos); + new->errmsg = NULL; + new->errpipe[0] = -1; + new->errpipe[1] = -1; #endif return new; @@ -4534,8 +4571,16 @@ int lxc_setup(struct lxc_handler *handler) char *keyring_context = NULL; ret = lxc_setup_rootfs_prepare_root(lxc_conf, name, lxcpath); +#ifdef HAVE_ISULAD + if (ret < 0) { + lxc_write_error_message(lxc_conf->errpipe[1], "%s:%d: failed to setup rootfs %s.", + __FILE__, __LINE__, lxc_conf->rootfs.path); + return log_error(-1, "Failed to setup rootfs"); + } +#else if (ret < 0) return log_error(-1, "Failed to setup rootfs"); +#endif if (handler->nsfd[LXC_NS_UTS] == -EBADF) { ret = setup_utsname(lxc_conf->utsname); @@ -5243,6 +5288,8 @@ void lxc_conf_free(struct lxc_conf *conf) lxc_clear_populate_devices(conf); lxc_clear_rootfs_masked_paths(conf); lxc_clear_rootfs_ro_paths(conf); + free(conf->errmsg); + lxc_close_error_pipe(conf->errpipe); #endif free(conf); } @@ -6127,4 +6174,16 @@ int lxc_clear_rootfs_ro_paths(struct lxc_conf *c) return 0; } +/*isulad: close error pipe */ +void lxc_close_error_pipe(int *errpipe) +{ + if (errpipe[0] >= 0) { + close(errpipe[0]); + errpipe[0] = -1; + } + if (errpipe[1] >= 0) { + close(errpipe[1]); + errpipe[1] = -1; + } +} #endif diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 7b6fd3b..4b6409e 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -506,7 +506,11 @@ extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name, const char *lxcpath); extern int lxc_setup(struct lxc_handler *handler); extern int lxc_setup_parent(struct lxc_handler *handler); +#ifdef HAVE_ISULAD +extern int setup_resource_limits(struct lxc_list *limits, pid_t pid, int errfd); +#else extern int setup_resource_limits(struct lxc_list *limits, pid_t pid); +#endif extern int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype); extern int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype); @@ -557,5 +561,6 @@ int lxc_clear_rootfs_masked_paths(struct lxc_conf *c); int lxc_clear_rootfs_ro_paths(struct lxc_conf *c); int lxc_drop_caps(struct lxc_conf *conf); int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath); +void lxc_close_error_pipe(int *errpipe); #endif #endif /* __LXC_CONF_H */ diff --git a/src/lxc/execute.c b/src/lxc/execute.c index 59ff604..16c0fed 100644 --- a/src/lxc/execute.c +++ b/src/lxc/execute.c @@ -19,7 +19,11 @@ lxc_log_define(execute, start); +#ifdef HAVE_ISULAD +static int execute_start(struct lxc_handler *handler, void* data, int fd) +#else static int execute_start(struct lxc_handler *handler, void* data) +#endif { int argc_add, j; char **argv; @@ -71,6 +75,9 @@ static int execute_start(struct lxc_handler *handler, void* data) execvp(argv[0], argv); SYSERROR("Failed to exec %s", argv[0]); +#ifdef HAVE_ISULAD + lxc_write_error_message(fd, "Failed to exec: \"%s\": %s.", argv[0], strerror(errno)); +#endif free(argv); out1: return 1; diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 818848a..ed09a59 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -972,6 +972,8 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a char **init_cmd = NULL; #ifdef HAVE_ISULAD int keepfds[] = {-1, -1, -1, -1, -1}; + ssize_t size_read; + char errbuf[BUFSIZ + 1] = {0}; #else int keepfds[3] = {-1, -1, -1}; #endif @@ -1046,10 +1048,23 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a char title[2048]; pid_t pid_first, pid_second; +#ifdef HAVE_ISULAD + //isulad: pipdfd for get error message of child or grandchild process. + if (pipe2(conf->errpipe, O_CLOEXEC) != 0) { + SYSERROR("Failed to init errpipe"); + free_init_cmd(init_cmd); + lxc_free_handler(handler); + return false; + } +#endif + pid_first = fork(); if (pid_first < 0) { free_init_cmd(init_cmd); lxc_free_handler(handler); +#ifdef HAVE_ISULAD + lxc_close_error_pipe(conf->errpipe); +#endif return false; } @@ -1059,11 +1074,25 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a * the PID file, child will do the free and unlink. */ c->pidfile = NULL; +#ifdef HAVE_ISULAD + close(conf->errpipe[1]); + conf->errpipe[1] = -1; +#endif /* Wait for container to tell us whether it started * successfully. */ started = wait_on_daemonized_start(handler, pid_first); +#ifdef HAVE_ISULAD + if (!started) { + size_read = read(conf->errpipe[0], errbuf, BUFSIZ); + if (size_read > 0) { + conf->errmsg = safe_strdup(errbuf); + } + } + close(conf->errpipe[0]); + conf->errpipe[0] = -1; +#endif free_init_cmd(init_cmd); lxc_free_handler(handler); @@ -1099,6 +1128,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a if (pid_second != 0) { free_init_cmd(init_cmd); lxc_free_handler(handler); +#ifdef HAVE_ISULAD + lxc_close_error_pipe(conf->errpipe); +#endif _exit(EXIT_SUCCESS); } @@ -1114,6 +1146,11 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a keepfds[0] = handler->conf->maincmd_fd; keepfds[1] = handler->state_socket_pair[0]; keepfds[2] = handler->state_socket_pair[1]; +#ifdef HAVE_ISULAD + keepfds[4] = conf->errpipe[1]; + close(conf->errpipe[0]); + conf->errpipe[0] = -1; +#endif ret = lxc_check_inherited(conf, true, keepfds, sizeof(keepfds) / sizeof(keepfds[0])); if (ret < 0) @@ -1148,6 +1185,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a if (w < 0 || (size_t)w >= sizeof(pidstr)) { free_init_cmd(init_cmd); lxc_free_handler(handler); +#ifdef HAVE_ISULAD + lxc_close_error_pipe(conf->errpipe); +#endif SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile); @@ -1161,6 +1201,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a if (ret < 0) { free_init_cmd(init_cmd); lxc_free_handler(handler); +#ifdef HAVE_ISULAD + lxc_close_error_pipe(conf->errpipe); +#endif SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile); @@ -1224,6 +1267,9 @@ reboot: if (conf->exit_fd >= 0) { keepfds[3] = conf->exit_fd; } + /* isulad: keep errpipe fd */ + if (c->daemonize) + keepfds[4] = conf->errpipe[1]; #endif ret = lxc_check_inherited(conf, c->daemonize, keepfds, @@ -3250,6 +3296,7 @@ static bool container_destroy(struct lxc_container *c, ERROR("Sprintf failed"); goto out; } + c->error_string = safe_strdup(msg); #endif goto out; } diff --git a/src/lxc/start.c b/src/lxc/start.c index 0bc1143..134235f 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -836,6 +836,9 @@ int lxc_init(const char *name, struct lxc_handler *handler) ret = lxc_terminal_setup(conf); if (ret < 0) { ERROR("Failed to create console"); +#ifdef HAVE_ISULAD + lxc_write_error_message(conf->errpipe[1], "Failed to create console for container \"%s\".", name); +#endif goto out_restore_sigmask; } TRACE("Created console"); @@ -1470,6 +1473,9 @@ static int do_start(void *data) /* Setup the container, ip, names, utsname, ... */ ret = lxc_setup(handler); if (ret < 0) { +#ifdef HAVE_ISULAD + lxc_write_error_message(handler->conf->errpipe[1], "Failed to setup lxc, please check the config file."); +#endif ERROR("Failed to setup container \"%s\"", handler->name); goto out_warn_father; } @@ -1763,7 +1769,11 @@ static int do_start(void *data) /* After this call, we are in error because this ops should not return * as it execs. */ +#ifdef HAVE_ISULAD + handler->ops->start(handler, handler->data, handler->daemonize ? handler->conf->errpipe[1] : -1); +#else handler->ops->start(handler, handler->data); +#endif out_warn_father: /* We want the parent to know something went wrong, so we return a @@ -2246,7 +2256,11 @@ static int lxc_spawn(struct lxc_handler *handler) goto out_delete_net; if (!lxc_list_empty(&conf->limits)) { +#ifdef HAVE_ISULAD + ret = setup_resource_limits(&conf->limits, handler->pid, conf->errpipe[1]); +#else ret = setup_resource_limits(&conf->limits, handler->pid); +#endif if (ret < 0) { ERROR("Failed to setup resource limits"); goto out_delete_net; @@ -2652,7 +2666,11 @@ struct start_args { char *const *argv; }; +#ifdef HAVE_ISULAD +static int start(struct lxc_handler *handler, void* data, int fd) +#else static int start(struct lxc_handler *handler, void* data) +#endif { struct start_args *arg = data; @@ -2660,6 +2678,9 @@ static int start(struct lxc_handler *handler, void* data) execvp(arg->argv[0], arg->argv); SYSERROR("Failed to exec \"%s\"", arg->argv[0]); +#ifdef HAVE_ISULAD + lxc_write_error_message(fd, "exec: \"%s\": %s.", arg->argv[0], strerror(errno)); +#endif return 0; } diff --git a/src/lxc/start.h b/src/lxc/start.h index cea37bc..ebeeb72 100644 --- a/src/lxc/start.h +++ b/src/lxc/start.h @@ -141,7 +141,11 @@ struct execute_args { }; struct lxc_operations { +#ifdef HAVE_ISULAD + int (*start)(struct lxc_handler *, void *, int); +#else int (*start)(struct lxc_handler *, void *); +#endif int (*post_start)(struct lxc_handler *, void *); }; diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c index 4be8564..e601f9d 100644 --- a/src/lxc/tools/lxc_ls.c +++ b/src/lxc/tools/lxc_ls.c @@ -106,7 +106,11 @@ struct wrapargs { /* * Takes struct wrapargs as argument. */ +#ifdef HAVE_ISULAD +static int ls_get_wrapper(void *wrap, int msgfd); +#else static int ls_get_wrapper(void *wrap); +#endif /* * To calculate swap usage we should not simply check memory.usage_in_bytes and @@ -1005,7 +1009,11 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) return 0; } +#ifdef HAVE_ISULAD +static int ls_get_wrapper(void *wrap, int msgfd) +#else static int ls_get_wrapper(void *wrap) +#endif { int ret = -1; size_t len = 0; diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c index b430a1e..4f2c8af 100644 --- a/src/lxc/tools/lxc_start.c +++ b/src/lxc/tools/lxc_start.c @@ -392,6 +392,11 @@ int main(int argc, char *argv[]) else err = c->start(c, 0, args) ? EXIT_SUCCESS : EXIT_FAILURE; if (err) { +#ifdef HAVE_ISULAD + if (c->lxc_conf->errmsg) + fprintf(stderr, "%s:%s:%s:%d starting container process caused \"%s\"", c->name, + __FILE__, __func__, __LINE__, c->lxc_conf->errmsg); +#endif ERROR("The container failed to start"); if (my_args.daemonize) diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 810b7fe..4e418fb 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -73,6 +73,9 @@ static int _recursive_rmdir(const char *dirname, dev_t pdev, int ret; struct dirent *direntp; char pathname[PATH_MAX]; +#ifdef HAVE_ISULAD + int saved_errno = 0; +#endif dir = opendir(dirname); if (!dir) @@ -135,6 +138,11 @@ static int _recursive_rmdir(const char *dirname, dev_t pdev, } else { ret = unlink(pathname); if (ret < 0) { +#ifdef HAVE_ISULAD + if (saved_errno == 0) { + saved_errno = errno; + } +#endif __do_close int fd = -EBADF; fd = open(pathname, O_RDONLY | O_CLOEXEC | O_NONBLOCK); @@ -160,10 +168,18 @@ static int _recursive_rmdir(const char *dirname, dev_t pdev, } if (rmdir(dirname) < 0 && !btrfs_try_remove_subvol(dirname) && !hadexclude) { +#ifdef HAVE_ISULAD + if (saved_errno == 0) { + saved_errno = errno; + } +#endif SYSERROR("Failed to delete \"%s\"", dirname); failed = 1; } +#ifdef HAVE_ISULAD + errno = saved_errno; +#endif return failed ? -1 : 0; } -- 1.8.3.1