void watchdog_close(bool disarm) { if (watchdogfd < 0) { return; } if (disarm) { int r; int flags = WDIOS_DISABLECARD;; /* Explicitly disarm it */ r = ioctl(watchdogfd, WDIOC_SETOPTIONS, &flags); if (r < 0) { cl_perror("Failed to disable hardware watchdog %s", watchdogdev); } /* To be sure, use magic close logic, too */ for (;;) { if (write(watchdogfd, "V", 1) > 0) { break; } cl_perror("Cannot disable watchdog device %s", watchdogdev); } } if (close(watchdogfd) < 0) { cl_perror("Watchdog close(%d) failed", watchdogfd); } watchdogfd = -1; }
static char * read_local_file(char *local_file) { FILE *fp = fopen(local_file, "r"); char buf[MAX_VALUE_LEN+1]; char *p; if (!fp) { if (errno != ENOENT) { cl_perror("%s:%d: cannot open %s" , __FUNCTION__, __LINE__, local_file); } return NULL; } if (!fgets(buf, MAX_VALUE_LEN, fp)) { cl_perror("%s:%d: cannot read %s" , __FUNCTION__, __LINE__, local_file); return NULL; } /* strip white space */ for (p = buf+strlen(buf)-1; p >= buf && isspace(*p); p--) ; *(p+1) = '\0'; return g_strdup(buf); }
int write_local_hb_uuid(const char *new_value) { int fd; int rc = 0; cl_uuid_t uuid; char *buffer = strdup(new_value); rc = cl_uuid_parse(buffer, &uuid); if (rc != 0) { fprintf(stderr, "Invalid ASCII UUID supplied: [%s]\n", new_value); fprintf(stderr, "ASCII UUIDs must be of the form" " XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" " and contain only letters and digits\n"); return 5; } if ((fd = open(UUID_FILE, O_WRONLY | O_SYNC | O_CREAT, 0644)) < 0) { cl_perror("Could not open %s", UUID_FILE); return 6; } if (write(fd, uuid.uuid, UUID_LEN) != UUID_LEN) { cl_perror("Could not write UUID to %s", UUID_FILE); rc = 7; } if (close(fd) < 0) { cl_perror("Could not close %s", UUID_FILE); rc = 8; } return rc; }
/* * Change directory to the directory our core file needs to go in * Call after you establish the userid you're running under. */ int cl_cdtocoredir(void) { const char * dir = coreroot; int rc; struct passwd* pwent; if (dir == NULL) { dir = HA_COREDIR; } if ((rc=chdir(dir)) < 0) { int errsave = errno; cl_perror("Cannot chdir to [%s]", dir); errno = errsave; return rc; } pwent = getpwuid(getuid()); if (pwent == NULL) { int errsave = errno; cl_perror("Cannot get name for uid [%d]", getuid()); errno = errsave; return -1; } if ((rc=chdir(pwent->pw_name)) < 0) { int errsave = errno; cl_perror("Cannot chdir to [%s/%s]", dir, pwent->pw_name); errno = errsave; } return rc; }
void sysrq_init(void) { FILE* procf; int c; procf = fopen("/proc/sys/kernel/sysrq", "r"); if (!procf) { cl_perror("cannot open /proc/sys/kernel/sysrq for read."); return; } if (fscanf(procf, "%d", &c) != 1) { cl_perror("Parsing sysrq failed"); c = 0; } fclose(procf); if (c == 1) return; /* 8 for debugging dumps of processes, 128 for reboot/poweroff */ c |= 136; procf = fopen("/proc/sys/kernel/sysrq", "w"); if (!procf) { cl_perror("cannot open /proc/sys/kernel/sysrq for writing"); return; } fprintf(procf, "%d", c); fclose(procf); return; }
void dup_reg_test(void) { /* apphbd should not allow a process register two times */ int rc; char app_instance[APPNAME_LEN]; char app_name[] = "dup_reg_test"; snprintf(app_instance, sizeof(app_instance) , "%s_%ld", app_name, (long)getpid()); cl_log(LOG_INFO, "----Client %s trying to register twice----" , app_instance); cl_log(LOG_INFO, "Client %s registering", app_instance); rc = apphb_register(app_name, app_instance); if (rc < 0) { cl_perror("%s first register fail", app_instance); exit(1); } sleep(3); cl_log(LOG_INFO, "Client %s registering again", app_instance); rc = apphb_register(app_name, app_instance); if (rc < 0) { cl_perror("%s second register fail", app_instance); exit(1); } errno = 0; }
void multi_hb_test(int child_proc_num, int hb_intvl_ms, int hb_num, int delaysecs , int dofailuretests) { int j; cl_log(LOG_INFO, "----Start %d client(s) with hb interval %d ms----" , child_proc_num, hb_intvl_ms); for (j=0; j < child_proc_num; ++j) { switch(fork()) { case 0: hb_normal(hb_intvl_ms, delaysecs ,hb_num); exit(0); break; case -1: cl_perror("Can't fork!"); exit(1); break; default: /* In the parent. */ break; } } /* Wait for all our child processes to exit*/ while(wait(NULL) > 0); errno = 0; if (dofailuretests) { cl_log(LOG_INFO, "----Start %d client(s) doing fail test----" , child_proc_num); for (j = 0; j < child_proc_num; ++j) { switch(fork()) { case 0: doafailtest(); exit(0); break; case -1: cl_perror("Can't fork!"); exit(1); break; default: break; } } /* Wait for all our child processes to exit*/ while(wait(NULL) > 0); errno = 0; } }
void watchdog_close(void) { if (watchdogfd >= 0) { if (write(watchdogfd, "V", 1) != 1) { cl_perror( "Watchdog write magic character failure: closing %s!", watchdogdev); } if (close(watchdogfd) < 0) { cl_perror("Watchdog close(2) failed."); } watchdogfd = -1; } }
/** * *@return 0 on success * -1 and errno is ENOMEM */ int recover_app(RecoveryInfo *info, int eventindex) { pid_t pid; pid = fork(); if (pid < 0) { cl_log(LOG_CRIT,"Failed to fork recovery process"); return -1; } else if (0 == pid) { child_setup_function(info); if (debug >= DBGDETAIL) { cl_log(LOG_INFO, "current euid[%ld]", (long)geteuid()); cl_log(LOG_INFO, "current egid[%ld]", (long)getegid()); cl_log(LOG_DEBUG,"script = %s", info->scriptname); cl_log(LOG_DEBUG,"args = %s", info->event[eventindex].args); } if (eventindex > MAXEVENTS) { eventindex = 0; } if (execl(info->scriptname, info->scriptname, info->event[eventindex].args, (const char *)NULL) < 0) { cl_perror("Failed to exec recovery script for %s", info->appname); _exit(EXIT_FAILURE); } } return 0; }
/** * This function is called for every requested connection. * This is where we accept it or not. */ static gboolean pending_conn_dispatch(IPC_Channel* src, gpointer user) { if (debug >= DBGMIN) { cl_log(LOG_DEBUG,"received connection request"); cl_log(LOG_DEBUG, "recoverymgr dispatch: IPC_channel: 0x%x" " pid=%d" , GPOINTER_TO_UINT(src) , src->farside_pid); } if (src != NULL) { /* This sets up comm channel w/client * Ignoring the result value is OK, because * the client registers itself w/event system. */ (void)recoverymgr_client_new(src); } else { cl_perror("accept_connection failed"); sleep(1); /* WHY IS THIS HERE? */ } return TRUE; }
/* * Make sure only one copy is running at a time... */ static gboolean TempProcessTrigger(gpointer ginfo) { struct tempproc_track* info = ginfo; int pid; /* Make sure only one copy is running at a time. */ /* This avoids concurrency problems. */ if (info->isrunning) { info->runagain = TRUE; return TRUE; } info->isrunning = TRUE; if (info->prefork) { if (debug_level > 1) { cl_log(LOG_DEBUG , "%s: Calling prefork for temp process %s" , __FUNCTION__, info->procname); } info->prefork(info->userdata); } if (ANYDEBUG) { cl_log(LOG_DEBUG, "Forking temp process %s", info->procname); } switch ((pid=fork())) { int rc; case -1: cl_perror("%s: Can't fork temporary child" " process [%s]!", __FUNCTION__ , info->procname); info->isrunning = FALSE; break; case 0: /* Child */ if ((rc=info->fun(info->userdata)) == HA_OK) { exit(0); } cl_log(LOG_WARNING , "%s: %s returns %d", __FUNCTION__ , info->procname, rc); exit(1); break; default: /* Fall out */; } if (pid > 0) { NewTrackedProc(pid, 0, (ANYDEBUG? PT_LOGVERBOSE : PT_LOGNORMAL) , ginfo, &TempProcessTrackOps); if (info->postfork) { if (debug_level > 1) { cl_log(LOG_DEBUG , "%s: Calling postfork for temp process %s" , __FUNCTION__, info->procname); } info->postfork(info->userdata); } } return TRUE; }
int watchdog_init_interval(void) { int timeout = timeout_watchdog; if (watchdogfd < 0) { return 0; } if (watchdog_set_timeout == 0) { cl_log(LOG_INFO, "NOT setting watchdog timeout on explicit user request!"); return 0; } if (ioctl(watchdogfd, WDIOC_SETTIMEOUT, &timeout) < 0) { cl_perror( "WDIOC_SETTIMEOUT" ": Failed to set watchdog timer to %u seconds.", timeout); cl_log(LOG_CRIT, "Please validate your watchdog configuration!"); cl_log(LOG_CRIT, "Choose a different watchdog driver or specify -T to skip this if you are completely sure."); return -1; } else { cl_log(LOG_INFO, "Set watchdog timeout to %u seconds.", timeout); } return 0; }
static void sbd_memlock(int stackgrowK, int heapgrowK) { #ifdef _POSIX_MEMLOCK /* * We could call setrlimit(RLIMIT_MEMLOCK,...) with a large * number, but the mcp runs as root and mlock(2) says: * * Since Linux 2.6.9, no limits are placed on the amount of memory * that a privileged process may lock, and this limit instead * governs the amount of memory that an unprivileged process may * lock. */ if (mlockall(MCL_CURRENT|MCL_FUTURE) >= 0) { cl_log(LOG_INFO, "Locked ourselves in memory"); /* Now allocate some extra pages (MCL_FUTURE will ensure they stay around) */ sbd_malloc_hogger(heapgrowK); sbd_stack_hogger(NULL, stackgrowK); } else { cl_perror("Unable to lock ourselves into memory"); } #else cl_log(LOG_ERR, "Unable to lock ourselves into memory"); #endif }
pid_t make_daemon(void) { pid_t pid; const char * devnull = "/dev/null"; pid = fork(); if (pid < 0) { cl_log(LOG_ERR, "%s: could not start daemon\n", cmdname); cl_perror("fork"); exit(1); }else if (pid > 0) { return pid; } qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_FALSE); /* This is the child; ensure privileges have not been lost. */ maximize_priority(); sysrq_init(); umask(022); close(0); (void)open(devnull, O_RDONLY); close(1); (void)open(devnull, O_WRONLY); close(2); (void)open(devnull, O_WRONLY); sbd_cdtocoredir(); return 0; }
static void logd_stop(void) { long running_logd_pid = cl_read_pidfile(LOGD_PIDFILE); int err; if (running_logd_pid < 0) { fprintf(stderr, "ha_logd already stopped.\n"); cl_log(LOG_INFO, "ha_logd already stopped."); exit(LSB_EXIT_OK); } cl_log(LOG_DEBUG, "Stopping ha_logd with pid %ld", running_logd_pid); if (kill((pid_t)running_logd_pid, SIGTERM) >= 0) { /* Wait for the running logd to die */ cl_log(LOG_INFO, "Waiting for pid=%ld to exit", running_logd_pid); alarm(0); do { sleep(1); }while (IsRunning(running_logd_pid)); } else if (errno != ESRCH) { err = errno; cl_perror("Pid %ld not killed", running_logd_pid); exit((err == EPERM || err == EACCES) ? LSB_EXIT_EPERM : LSB_EXIT_GENERIC); } cl_log(LOG_INFO, "Pid %ld exited", running_logd_pid); exit(LSB_EXIT_OK); }
static gboolean child_death_dispatch(int sig, gpointer notused) { int status; pid_t pid; const int waitflags = WNOHANG; struct sigaction saveaction; int childcount = 0; /* * wait3(WNOHANG) isn't _supposed_ to hang * Unfortunately, it seems to do just that on some OSes. * * The workaround is to set an alarm. I don't think for this purpose * that it matters if siginterrupt(SIGALRM) is set TRUE or FALSE since * the tiniest little excuse seems to cause the wait3() to finish. */ memset(&saveaction, 0, sizeof(saveaction)); cl_signal_set_simple_handler(SIGALRM, G_main_alarm_helper, &saveaction); alarm_count = 0; cl_signal_set_interrupt(SIGALRM, TRUE); setmsrepeattimer(WAITALARM); /* Might as well be persistent ;-) */ while((pid=wait3(&status, waitflags, NULL)) > 0 || (pid < 0 && errno == EINTR)) { cancelmstimer(); if (pid > 0) { ++childcount; ReportProcHasDied(pid, status); } setmsrepeattimer(WAITALARM); /* Let's be persistent ;-) */ } cancelmstimer(); cl_signal_set_simple_handler(SIGALRM, saveaction.sa_handler, &saveaction); if (pid < 0 && errno != ECHILD) { cl_perror("%s: wait3() failed" , __FUNCTION__); } #if defined(DEBUG) if (childcount < 1) { /* * This happens when we receive a SIGCHLD after we clear * 'sig_src->signal_triggered' in G_SIG_dispatch() but * before the last wait3() call returns no child above. */ cl_log(LOG_DEBUG, "NOTE: %s called without children to wait on" , __FUNCTION__); } #endif if (alarm_count) { cl_log(LOG_ERR , "%s: wait3() call hung %d times. childcount = %d" , __FUNCTION__, alarm_count, childcount); alarm_count = 0; } return TRUE; }
static int get_resource_list(GList ** rsc_info) { struct dirent **namelist; GList* item; int file_num; char subdir[FILENAME_MAX+1]; if ( rsc_info == NULL ) { cl_log(LOG_ERR, "Parameter error: get_resource_list"); return -2; } if ( *rsc_info != NULL ) { cl_log(LOG_ERR, "Parameter error: get_resource_list."\ "will cause memory leak."); *rsc_info = NULL; } file_num = scandir(RA_PATH, &namelist, NULL, alphasort); if (file_num < 0) { return -2; } while (file_num--) { GList* ra_subdir = NULL; struct stat prop; if ('.' == namelist[file_num]->d_name[0]) { free(namelist[file_num]); continue; } snprintf(subdir,FILENAME_MAX,"%s/%s", RA_PATH, namelist[file_num]->d_name); if (stat(subdir, &prop) == -1) { cl_perror("%s:%s:%d: stat failed for %s" , __FILE__, __FUNCTION__, __LINE__, subdir); free(namelist[file_num]); continue; } else if (!S_ISDIR(prop.st_mode)) { free(namelist[file_num]); continue; } get_runnable_list(subdir,&ra_subdir); merge_string_list(rsc_info,ra_subdir); while (NULL != (item = g_list_first(ra_subdir))) { ra_subdir = g_list_remove_link(ra_subdir, item); g_free(item->data); g_list_free_1(item); } free(namelist[file_num]); } free(namelist); return 0; }
/** * Scan email for virus. Returns 1 if virus * detected or 0 if no virus is detected. Sets * lscan.virname to virua or error output... */ int scan_clamav(char * scanpath) { sprintf(lscan.scanpath, "%s", scanpath); lscan.iNo = 0; /** lets load all our virus defs database's into memory */ lscan.root = NULL; /** without this line, the dbload will crash... */ if((lscan.i = cl_loaddbdir(cl_retdbdir(), &lscan.root, &lscan.iNo))) { sprintf(lscan.virname, "error: [%s]", cl_perror(lscan.i)); } else { if((lscan.i = cl_build(lscan.root))) { sprintf(lscan.virname, "database initialization error: [%s]", cl_perror(lscan.i)); cl_free(lscan.root); } memset(&lscan.limits, 0x0, sizeof(struct cl_limits)); lscan.limits.maxfiles = 1000; /** max files */ lscan.limits.maxfilesize = 10 * 1048576; /** maximal archived file size == 10 Mb */ lscan.limits.maxreclevel = 12; /** maximal recursion level */ lscan.limits.maxratio = 200; /** maximal compression ratio */ lscan.limits.archivememlim = 0; /** disable memory limit for bzip2 scanner */ if ((lscan.i = cl_scanfile(lscan.scanpath, (const char **)&lscan.virname, NULL, lscan.root, &lscan.limits, CL_SCAN_ARCHIVE | CL_SCAN_MAIL | CL_SCAN_OLE2 | CL_SCAN_BLOCKBROKEN | CL_SCAN_HTML | CL_SCAN_PE)) != CL_VIRUS) { if (lscan.i != CL_CLEAN) { sprintf(lscan.virname, "error: [%s]", cl_perror(lscan.i)); } else { lscan.virname = NULL; } } if (lscan.root != NULL) { cl_free(lscan.root); } memset(&lscan.limits, 0x0, sizeof(struct cl_limits)); } /** lets delete the spool message as we don't need it any more */ if (lscan.virname != NULL) { /** remove the file if we have a virus as we are going to reject it */ return(1); } else { /** else keep the file for spam filtering */ return(0); } return(1); } /** scan_clamav */
void sbd_make_realtime(int priority, int stackgrowK, int heapgrowK) { if(priority < 0) { return; } #ifdef SCHED_RR { int pcurrent = 0; int pmin = sched_get_priority_min(SCHED_RR); int pmax = sched_get_priority_max(SCHED_RR); if (priority == 0) { priority = pmax; } else if (priority < pmin) { priority = pmin; } else if (priority > pmax) { priority = pmax; } pcurrent = sched_getscheduler(0); if (pcurrent < 0) { cl_perror("Unable to get scheduler priority"); } else if(pcurrent < priority) { struct sched_param sp; memset(&sp, 0, sizeof(sp)); sp.sched_priority = priority; if (sched_setscheduler(0, SCHED_RR, &sp) < 0) { cl_perror("Unable to set scheduler priority to %d", priority); } else { cl_log(LOG_INFO, "Scheduler priority is now %d", priority); } } } #else cl_log(LOG_ERR, "System does not support updating the scheduler priority"); #endif sbd_memlock(heapgrowK, stackgrowK); }
/* Enable/disable core dumps for ourselves and our child processes */ int cl_enable_coredumps(int doenable) { int rc; struct rlimit rlim; if ((rc = getrlimit(RLIMIT_CORE, &rlim)) < 0) { int errsave = errno; cl_perror("Cannot get current core limit value."); errno = errsave; return rc; } if (rlim.rlim_max == 0 && geteuid() == 0) { rlim.rlim_max = RLIM_INFINITY; } rlim.rlim_cur = (doenable ? rlim.rlim_max : 0); if (doenable && rlim.rlim_max == 0) { cl_log(LOG_WARNING , "Not possible to enable core dumps (rlim_max is 0)"); } if ((rc = setrlimit(RLIMIT_CORE, &rlim)) < 0) { int errsave = errno; cl_perror("Unable to %s core dumps" , doenable ? "enable" : "disable"); errno = errsave; return rc; } if (getenv(CHECKED_KERNEL_CORE_ENV) == NULL && core_uses_pid() == 0) { cl_log(LOG_WARNING , "Core dumps could be lost if multiple dumps occur."); cl_log(LOG_WARNING , "Consider setting non-default value in %s" " (or equivalent) for maximum supportability", PROC_SYS_KERNEL_CORE_PAT); cl_log(LOG_WARNING , "Consider setting %s (or equivalent) to" " 1 for maximum supportability", PROC_SYS_KERNEL_CORE_PID); } return 0; }
int read_local_hb_uuid(void) { int rc = 0; cl_uuid_t uuid; char *buffer = NULL; long start = 0, read_len = 0; FILE *input = fopen(UUID_FILE, "r"); if (input == NULL) { cl_perror("Could not open UUID file %s\n", UUID_FILE); return 1; } /* see how big the file is */ start = ftell(input); fseek(input, 0L, SEEK_END); if (UUID_LEN != ftell(input)) { fprintf(stderr, "%s must contain exactly %d bytes\n", UUID_FILE, UUID_LEN); abort(); } fseek(input, 0L, start); if (start != ftell(input)) { fprintf(stderr, "fseek not behaving: %ld vs. %ld\n", start, ftell(input)); rc = 2; goto bail; } /* fprintf(stderr, "Reading %d bytes from: %s\n", UUID_LEN, UUID_FILE); */ buffer = malloc(50); read_len = fread(uuid.uuid, 1, UUID_LEN, input); if (read_len != UUID_LEN) { fprintf(stderr, "Expected and read bytes differ: %d vs. %ld\n", UUID_LEN, read_len); rc = 3; goto bail; } else if (buffer != NULL) { cl_uuid_unparse(&uuid, buffer); fprintf(stdout, "%s\n", buffer); } else { fprintf(stderr, "No buffer to unparse\n"); rc = 4; } bail: free(buffer); fclose(input); return rc; }
static struct sbd_context * open_device(const char* devname, int loglevel) { struct sbd_context *st; if (!devname) return NULL; st = malloc(sizeof(struct sbd_context)); if (!st) return NULL; memset(st, 0, sizeof(struct sbd_context)); if (io_setup(1, &st->ioctx) != 0) { cl_perror("io_setup failed"); free(st); return NULL; } st->devfd = open(devname, O_SYNC|O_RDWR|O_DIRECT); if (st->devfd == -1) { if (loglevel == LOG_DEBUG) { DBGLOG(loglevel, "Opening device %s failed.", devname); } else { cl_log(loglevel, "Opening device %s failed.", devname); } free(st); return NULL; } ioctl(st->devfd, BLKSSZGET, §or_size); if (sector_size == 0) { cl_perror("Get sector size failed.\n"); close_device(st); return NULL; } return st; }
int watchdog_tickle(void) { if (watchdogfd >= 0) { if (write(watchdogfd, "", 1) != 1) { cl_perror("Watchdog write failure: %s!", watchdogdev); return -1; } } return 0; }
/** * Sends a registration message to the apphbd * and sets the heartbeat interval. * Sets up a callback for sending heartbeats. */ int register_hb(void) { int rc; rc = apphb_register("recovery manager", "normal"); if (rc < 0) { cl_perror("registration failure"); return 1; } rc = apphb_setinterval(HBINTERVAL_MSEC); if (rc < 0) { cl_perror("setinterval failure"); return 2; } setup_hb_callback(); return 0; }
static void cl_coredump_signal_handler(int nsig) { return_to_orig_privs(); if (geteuid() == 0) { /* Put ALL privileges back to root... */ if (setuid(0) < 0) { cl_perror("cl_coredump_signal_handler: unable to setuid(0)"); } } cl_untaint_coredumps(); /* Do the best we know how to do... */ CL_SIGNAL(nsig, SIG_DFL); kill(getpid(), nsig); }
void maximize_priority(void) { if (skip_rt) { cl_log(LOG_INFO, "Not elevating to realtime (-R specified)."); return; } sbd_make_realtime(0, 256, 256); if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT, 1)) != 0) { cl_perror("ioprio_set() call failed."); } }
void sysrq_trigger(char t) { FILE *procf; procf = fopen("/proc/sysrq-trigger", "a"); if (!procf) { cl_perror("Opening sysrq-trigger failed."); return; } cl_log(LOG_INFO, "sysrq-trigger: %c\n", t); fprintf(procf, "%c\n", t); fclose(procf); return; }
/* * Change directory to the directory our core file needs to go in * Call after you establish the userid you're running under. */ int sbd_cdtocoredir(void) { int rc; static const char *dir = NULL; if (dir == NULL) { dir = CRM_CORE_DIR; } if ((rc=chdir(dir)) < 0) { int errsave = errno; cl_perror("Cannot chdir to [%s]", dir); errno = errsave; } return rc; }
void sbd_get_uname(void) { struct utsname uname_buf; int i; if (uname(&uname_buf) < 0) { cl_perror("uname() failed?"); exit(1); } local_uname = strdup(uname_buf.nodename); for (i = 0; i < strlen(local_uname); i++) local_uname[i] = tolower(local_uname[i]); }
int watchdog_init(void) { if (watchdogfd < 0 && watchdogdev != NULL) { watchdogfd = open(watchdogdev, O_WRONLY); if (watchdogfd >= 0) { cl_log(LOG_NOTICE, "Using watchdog device '%s'", watchdogdev); if ((watchdog_init_interval() < 0) || (watchdog_tickle() < 0)) { return -1; } }else{ cl_perror("Cannot open watchdog device '%s'", watchdogdev); return -1; } } return 0; }