/* the actual shutdown procedure */ static void doshutdown(void) { int ret; /* this should probably go away at some point */ upslogx(LOG_CRIT, "Executing automatic power-fail shutdown"); wall("Executing automatic power-fail shutdown\n"); do_notify(NULL, NOTIFY_SHUTDOWN); sleep(finaldelay); /* in the pipe model, we let the parent do this for us */ if (use_pipe) { char ch; ch = 1; ret = write(pipefd[1], &ch, 1); } else { /* one process model = we do all the work here */ if (geteuid() != 0) upslogx(LOG_WARNING, "Not root, shutdown may fail"); set_pdflag(); ret = system(shutdowncmd); if (ret != 0) upslogx(LOG_ERR, "Unable to call shutdown command: %s", shutdowncmd); } exit(EXIT_SUCCESS); }
/*!@brief Report a USB comm failure, and reconnect if necessary * * @param[in] res Result code from libusb/libhid call * @param[in] msg Error message to display */ void usb_comm_fail(int res, const char *msg) { static int try = 0; switch(res) { case -EBUSY: upslogx(LOG_WARNING, "%s: Device claimed by another process", msg); fatalx(EXIT_FAILURE, "Terminating: EBUSY"); break; default: upslogx(LOG_WARNING, "%s: Device detached? (error %d: %s)", msg, res, usb_strerror()); upslogx(LOG_NOTICE, "Reconnect attempt #%d", ++try); hd = NULL; reconnect_ups(); if(hd) { upslogx(LOG_NOTICE, "Successfully reconnected"); try = 0; upsdrv_initinfo(); } else { if(try > MAX_RECONNECT_TRIES) { fatalx(EXIT_FAILURE, "Too many unsuccessful reconnection attempts"); } } break; }
/* exit with success only if it exists and is proper */ static int check_pdflag(void) { int ret; ret = pdflag_status(); if (ret == -1) { upslogx(LOG_ERR, "POWERDOWNFLAG (%s) does not contain " "the upsmon magic string", powerdownflag); return EXIT_FAILURE; } if (ret == 0) { /* not there - this is not a shutdown event */ upslogx(LOG_ERR, "Power down flag is not set"); return EXIT_FAILURE; } if (ret != 1) { upslogx(LOG_ERR, "Programming error: pdflag_status returned %d", ret); return EXIT_FAILURE; } /* only thing left - must be time for a shutdown */ upslogx(LOG_INFO, "Power down flag is set"); return EXIT_SUCCESS; }
/* * Error handler for usb_get/set_* functions. Return value > 0 success, * 0 unknown or temporary failure (ignored), < 0 permanent failure (reconnect) */ static int libusb_strerror(const int ret, const char *desc) { if (ret > 0) { return ret; } switch(ret) { case -EBUSY: /* Device or resource busy */ case -EPERM: /* Operation not permitted */ case -ENODEV: /* No such device */ case -EACCES: /* Permission denied */ case -EIO: /* I/O error */ case -ENXIO: /* No such device or address */ case -ENOENT: /* No such file or directory */ case -EPIPE: /* Broken pipe */ case -ENOSYS: /* Function not implemented */ upslogx(LOG_DEBUG, "%s: %s", desc, usb_strerror()); return ret; case -ETIMEDOUT: /* Connection timed out */ upsdebugx(2, "%s: Connection timed out", desc); return 0; case -EOVERFLOW: /* Value too large for defined data type */ case -EPROTO: /* Protocol error */ upsdebugx(2, "%s: %s", desc, usb_strerror()); return 0; default: /* Undetermined, log only */ upslogx(LOG_DEBUG, "%s: %s", desc, usb_strerror()); return 0; } }
static void log_unknown(int numarg, char **arg) { int i; upslogx(LOG_INFO, "Unknown command on socket: "); for (i = 0; i < numarg; i++) upslogx(LOG_INFO, "arg %d: %s", i, arg[i]); }
static void parse_at(const char *ntype, const char *un, const char *cmd, const char *ca1, const char *ca2) { /* complain both ways in case we don't have a tty */ if (!cmdscript) { printf("CMDSCRIPT must be set before any ATs in the config file!\n"); fatalx(EXIT_FAILURE, "CMDSCRIPT must be set before any ATs in the config file!"); } if (!pipefn) { printf("PIPEFN must be set before any ATs in the config file!\n"); fatalx(EXIT_FAILURE, "PIPEFN must be set before any ATs in the config file!"); } if (!lockfn) { printf("LOCKFN must be set before any ATs in the config file!\n"); fatalx(EXIT_FAILURE, "LOCKFN must be set before any ATs in the config file!"); } /* check upsname: does this apply to us? */ if (strcmp(upsname, un) != 0) if (strcmp(un, "*") != 0) return; /* not for us, and not the wildcard */ /* see if the current notify type matches the one from the .conf */ if (strcasecmp(notify_type, ntype) != 0) return; /* if command is valid, send it to the daemon (which may start it) */ if (!strcmp(cmd, "START-TIMER")) { sendcmd("START", ca1, ca2); return; } if (!strcmp(cmd, "CANCEL-TIMER")) { sendcmd("CANCEL", ca1, ca2); return; } if (!strcmp(cmd, "EXECUTE")) { if (ca1 == '\0') { upslogx(LOG_ERR, "Empty EXECUTE command argument"); return; } if (verbose) upslogx(LOG_INFO, "Executing command: %s", ca1); exec_cmd(ca1); return; } upslogx(LOG_ERR, "Invalid command: %s", cmd); }
static int instcmd(const char *cmdname, const char *extra) { int ret = 0; if (!strcasecmp(cmdname, "shutdown.stayoff")) { /* shutdown now (one way) */ /* send_command( CMD_SHUT ); */ sendshut(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { /* liga Saida */ ret = send_command( 3 ); if ( ret < 1 ) upslogx(LOG_ERR, "send_command 3 failed"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.off")) { /* desliga Saida */ ret = send_command( 4 ); if ( ret < 1 ) upslogx(LOG_ERR, "send_command 4 failed"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "bypass.start")) { /* liga Bypass */ ret = send_command( 5 ); if ( ret < 1 ) upslogx(LOG_ERR, "send_command 5 failed"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "bypass.stop")) { /* desliga Bypass */ ret = send_command( 6 ); if ( ret < 1 ) upslogx(LOG_ERR, "send_command 6 failed"); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; }
/* called after SIGHUP */ void conf_reload(void) { upstype_t *upstmp, *upsnext; upslogx(LOG_INFO, "SIGHUP: reloading configuration"); /* see if we can access upsd.conf before blowing away the config */ if (!check_file("upsd.conf")) return; /* reset retain flags on all known UPS entries */ upstmp = firstups; while (upstmp) { upstmp->retain = 0; upstmp = upstmp->next; } /* reload from ups.conf */ read_upsconf(); upsconf_add(1); /* 1 = reloading */ /* now reread upsd.conf */ load_upsdconf(1); /* 1 = reloading */ /* now delete all UPS entries that didn't get reloaded */ upstmp = firstups; while (upstmp) { /* upstmp may be deleted during this pass */ upsnext = upstmp->next; if (upstmp->retain == 0) delete_ups(upstmp); upstmp = upsnext; } /* did they actually delete the last UPS? */ if (firstups == NULL) upslogx(LOG_WARNING, "Warning: no UPSes currently defined!"); /* and also make sure upsd.users can be read... */ if (!check_file("upsd.users")) return; /* delete all users */ user_flush(); /* and finally reread from upsd.users */ user_load(); }
static void set_notifyflag(const char *ntype, char *flags) { int i, pos; char *ptr, *tmp; /* find ntype */ pos = -1; for (i = 0; notifylist[i].name != NULL; i++) { if (!strcasecmp(notifylist[i].name, ntype)) { pos = i; break; } } if (pos == -1) { upslogx(LOG_WARNING, "Warning: invalid notify type [%s]", ntype); return; } ptr = flags; /* zero existing flags */ notifylist[pos].flags = 0; while (ptr) { int newflag; tmp = strchr(ptr, '+'); if (tmp) *tmp++ = '\0'; newflag = 0; if (!strcmp(ptr, "SYSLOG")) newflag = NOTIFY_SYSLOG; if (!strcmp(ptr, "WALL")) newflag = NOTIFY_WALL; if (!strcmp(ptr, "EXEC")) newflag = NOTIFY_EXEC; if (!strcmp(ptr, "IGNORE")) newflag = NOTIFY_IGNORE; if (newflag) notifylist[pos].flags |= newflag; else upslogx(LOG_WARNING, "Invalid notify flag: [%s]", ptr); ptr = tmp; } }
/* change the configuration of an existing UPS (used during reloads) */ static void ups_update(const char *fn, const char *name, const char *desc) { upstype_t *temp; temp = get_ups_ptr(name); if (!temp) { upslogx(LOG_ERR, "UPS %s disappeared during reload", name); return; } /* paranoia */ if (!temp->fn) { upslogx(LOG_ERR, "UPS %s had a NULL filename!", name); /* let's give it something quick to use later */ temp->fn = xstrdup(""); } /* when the filename changes, force a reconnect */ if (strcmp(temp->fn, fn) != 0) { upslogx(LOG_NOTICE, "Redefined UPS [%s]", name); /* release all data */ sstate_infofree(temp); sstate_cmdfree(temp); pconf_finish(&temp->sock_ctx); close(temp->sock_fd); temp->sock_fd = -1; temp->dumpdone = 0; /* now redefine the filename and wrap up */ free(temp->fn); temp->fn = xstrdup(fn); } /* update the description */ free(temp->desc); if (desc) temp->desc = xstrdup(desc); else temp->desc = NULL; /* always set this on reload */ temp->retain = 1; }
/* add valid UPSes from ups.conf to the internal structures */ void upsconf_add(int reloading) { ups_t *tmp = upstable, *next; char statefn[SMALLBUF]; if (!tmp) { upslogx(LOG_WARNING, "Warning: no UPS definitions in ups.conf"); return; } while (tmp) { /* save for later, since we delete as we go along */ next = tmp->next; /* this should always be set, but better safe than sorry */ if (!tmp->upsname) { tmp = tmp->next; continue; } /* don't accept an entry that's missing items */ if ((!tmp->driver) || (!tmp->port)) { upslogx(LOG_WARNING, "Warning: ignoring incomplete configuration for UPS [%s]\n", tmp->upsname); } else { snprintf(statefn, sizeof(statefn), "%s-%s", tmp->driver, tmp->upsname); /* if a UPS exists, update it, else add it as new */ if ((reloading) && (get_ups_ptr(tmp->upsname) != NULL)) ups_update(statefn, tmp->upsname, tmp->desc); else ups_create(statefn, tmp->upsname, tmp->desc); } /* free tmp's resources */ free(tmp->driver); free(tmp->port); free(tmp->desc); free(tmp->upsname); free(tmp); tmp = next; } /* upstable should be completely gone by this point */ upstable = NULL; }
/* see what the status of the UPS is and handle any changes */ static void pollups(utype_t *ups) { char status[SMALLBUF]; /* try a reconnect here */ if (!flag_isset(ups->status, ST_CONNECTED)) if (try_connect(ups) != 1) return; if (upscli_ssl(&ups->conn) == 1) upsdebugx(2, "%s: %s [SSL]", __func__, ups->sys); else upsdebugx(2, "%s: %s", __func__, ups->sys); set_alarm(); if (get_var(ups, "status", status, sizeof(status)) == 0) { clear_alarm(); parse_status(ups, status); return; } /* fallthrough: no communications */ clear_alarm(); /* try to make some of these a little friendlier */ switch (upscli_upserror(&ups->conn)) { case UPSCLI_ERR_UNKNOWNUPS: upslogx(LOG_ERR, "Poll UPS [%s] failed - [%s] " "does not exist on server %s", ups->sys, ups->upsname, ups->hostname); break; default: upslogx(LOG_ERR, "Poll UPS [%s] failed - %s", ups->sys, upscli_strerror(&ups->conn)); break; } /* throw COMMBAD or NOCOMM as conditions may warrant */ ups_is_gone(ups); /* if upsclient lost the connection, clean up things on our side */ if (upscli_fd(&ups->conn) == -1) { drop_connection(ups); return; } }
void upsdrv_updateinfo(void) { static int retry = 0; if (blazer_status(command[proto].status)) { if (retry < MAXTRIES) { upsdebugx(1, "Communications with UPS lost: status read failed!"); retry++; } else if (retry == MAXTRIES) { upslogx(LOG_WARNING, "Communications with UPS lost: status read failed!"); retry++; } else { dstate_datastale(); } return; } if (getval("runtimecal")) { time_t now; time(&now); if (online) { /* OL */ batt.runt.est += batt.runt.nom * difftime(now, lastpoll) / batt.chrg.time; if (batt.runt.est > batt.runt.nom) { batt.runt.est = batt.runt.nom; } } else { /* OB */ batt.runt.est -= load.eff * difftime(now, lastpoll); if (batt.runt.est < 0) { batt.runt.est = 0; } } dstate_setinfo("battery.charge", "%.0f", 100 * batt.runt.est / batt.runt.nom); dstate_setinfo("battery.runtime", "%.0f", batt.runt.est / load.eff); lastpoll = now; } if (retry > MAXTRIES) { upslogx(LOG_NOTICE, "Communications with UPS re-established"); } retry = 0; dstate_dataok(); }
static void reload_conf(void) { utype_t *tmp, *next; upslogx(LOG_INFO, "Reloading configuration"); /* sanity check */ if (!check_file(configfile)) { reload_flag = 0; return; } /* flip through ups list, clear retain value */ tmp = firstups; while (tmp) { tmp->retain = 0; tmp = tmp->next; } /* reset paranoia checker */ totalpv = 0; /* reread upsmon.conf */ loadconfig(); /* go through the utype_t struct again */ tmp = firstups; while (tmp) { next = tmp->next; /* !retain means it wasn't in the .conf this time around */ if (tmp->retain == 0) delete_ups(tmp); tmp = next; } /* see if the user just blew off a foot */ if (totalpv < minsupplies) { upslogx(LOG_CRIT, "Fatal error: total power value (%d) less " "than MINSUPPLIES (%d)", totalpv, minsupplies); fatalx(EXIT_FAILURE, "Impossible power configuation, unable to continue"); } /* finally clear the flag */ reload_flag = 0; }
static void checktimers(void) { ttype_t *tmp, *tmpnext; time_t now; static int emptyctr = 0; /* if the queue is empty we might be ready to exit */ if (!thead) { emptyctr++; /* wait a little while in case someone wants us again */ if (emptyctr < EMPTY_WAIT) return; if (verbose) upslogx(LOG_INFO, "Timer queue empty, exiting"); #ifdef UPSSCHED_RACE_TEST upslogx(LOG_INFO, "triggering race: sleeping 15 sec before exit"); sleep(15); #endif unlink(pipefn); exit(EXIT_SUCCESS); } emptyctr = 0; /* flip through LL, look for activity */ tmp = thead; time(&now); while (tmp) { tmpnext = tmp->next; if (now >= tmp->etime) { if (verbose) upslogx(LOG_INFO, "Event: %s ", tmp->name); exec_cmd(tmp->name); /* delete from queue */ removetimer(tmp); } tmp = tmpnext; } }
void load_upsdconf(int reloading) { char fn[SMALLBUF]; PCONF_CTX_t ctx; snprintf(fn, sizeof(fn), "%s/upsd.conf", confpath()); check_perms(fn); pconf_init(&ctx, upsd_conf_err); if (!pconf_file_begin(&ctx, fn)) { pconf_finish(&ctx); if (!reloading) fatalx(EXIT_FAILURE, "%s", ctx.errmsg); upslogx(LOG_ERR, "Reload failed: %s", ctx.errmsg); return; } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } if (ctx.numargs < 1) continue; if (!parse_upsd_conf_args(ctx.numargs, ctx.arglist)) { unsigned int i; char errmsg[SMALLBUF]; snprintf(errmsg, sizeof(errmsg), "upsd.conf: invalid directive"); for (i = 0; i < ctx.numargs; i++) snprintfcat(errmsg, sizeof(errmsg), " %s", ctx.arglist[i]); upslogx(LOG_WARNING, "%s", errmsg); } } pconf_finish(&ctx); }
static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.id")) { set_identification(val); get_identification(); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "input.transfer.low")) { set_transfer_voltage_low(atoi(val)); get_transfer_voltage_low(); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "input.transfer.high")) { set_transfer_voltage_high(atoi(val)); get_transfer_voltage_high(); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "input.sensitivity")) { set_sensitivity(val); get_sensitivity(); return STAT_SET_HANDLED; } upslogx(LOG_NOTICE, "setvar: unknown var [%s]", varname); return STAT_SET_UNKNOWN; }
static int is_ups_critical(utype_t *ups) { time_t now; /* FSD = the master is forcing a shutdown */ if (flag_isset(ups->status, ST_FSD)) return 1; /* not OB or not LB = not critical yet */ if ((!flag_isset(ups->status, ST_ONBATT)) || (!flag_isset(ups->status, ST_LOWBATT))) return 0; /* must be OB+LB now */ /* if we're a master, declare it critical so we set FSD on it */ if (flag_isset(ups->status, ST_MASTER)) return 1; /* must be a slave now */ /* FSD isn't set, so the master hasn't seen it yet */ time(&now); /* give the master up to HOSTSYNC seconds before shutting down */ if ((now - ups->lastnoncrit) > hostsync) { upslogx(LOG_WARNING, "Giving up on the master for UPS [%s]", ups->sys); return 1; } /* there's still time left */ return 0; }
/* add another UPS for monitoring from ups.conf */ static void ups_create(const char *fn, const char *name, const char *desc) { upstype_t *temp; for (temp = firstups; temp != NULL; temp = temp->next) { if (!strcasecmp(temp->name, name)) { upslogx(LOG_ERR, "UPS name [%s] is already in use!", name); return; } } /* grab some memory and add the info */ temp = xcalloc(1, sizeof(*temp)); temp->fn = xstrdup(fn); temp->name = xstrdup(name); if (desc) { temp->desc = xstrdup(desc); } temp->stale = 1; temp->retain = 1; temp->sock_fd = sstate_connect(temp); /* preload this to the current time to avoid false staleness */ clock_monotonic(&temp->last_heard); temp->next = firstups; firstups = temp; num_ups++; }
static void conn_del(conn_t *target) { conn_t *tmp, *last = NULL; tmp = connhead; while (tmp) { if (tmp == target) { if (last) last->next = tmp->next; else connhead = tmp->next; pconf_finish(&tmp->ctx); free(tmp); return; } last = tmp; tmp = tmp->next; } upslogx(LOG_ERR, "Tried to delete a bogus state connection"); }
void upsdrv_shutdown(void) { int retry; /* Stop pending shutdowns */ for (retry = 1; retry <= MAXTRIES; retry++) { if (blazer_instcmd("shutdown.stop", NULL) != STAT_INSTCMD_HANDLED) { continue; } break; } if (retry > MAXTRIES) { upslogx(LOG_NOTICE, "No shutdown pending"); } /* Shutdown */ for (retry = 1; retry <= MAXTRIES; retry++) { if (blazer_instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED) { continue; } fatalx(EXIT_SUCCESS, "Shutting down in %d seconds", offdelay); } fatalx(EXIT_FAILURE, "Shutdown failed!"); }
/* * The battery voltage will quickly return to at least the nominal value after * discharging them. For overlapping battery.voltage.low/high ranges therefor * choose the one with the highest multiplier. */ static double blazer_packs(const char *ptr, char **endptr) { const double packs[] = { 120, 100, 80, 60, 48, 36, 30, 24, 18, 12, 8, 6, 4, 3, 2, 1, 0.5, -1 }; const char *val; int i; val = dstate_getinfo("battery.voltage.nominal"); batt.volt.nom = strtod(val ? val : ptr, endptr); for (i = 0; packs[i] > 0; i++) { if (packs[i] * batt.volt.act > 1.2 * batt.volt.nom) { continue; } if (packs[i] * batt.volt.act < 0.8 * batt.volt.nom) { upslogx(LOG_INFO, "Can't autodetect number of battery packs [%.0f/%.2f]", batt.volt.nom, batt.volt.act); break; } batt.packs = packs[i]; break; } return batt.volt.nom; }
/* close ttys and become a daemon */ void background(void) { int pid; if ((pid = fork()) < 0) fatal_with_errno(EXIT_FAILURE, "Unable to enter background"); xbit_set(&upslog_flags, UPSLOG_SYSLOG); xbit_clear(&upslog_flags, UPSLOG_STDERR); close(0); close(1); close(2); if (pid != 0) _exit(EXIT_SUCCESS); /* parent */ /* child */ /* make fds 0-2 point somewhere defined */ if (open("/dev/null", O_RDWR) != 0) fatal_with_errno(EXIT_FAILURE, "open /dev/null"); if (dup(0) == -1) fatal_with_errno(EXIT_FAILURE, "dup"); if (dup(0) == -1) fatal_with_errno(EXIT_FAILURE, "dup"); #ifdef HAVE_SETSID setsid(); /* make a new session to dodge signals */ #endif upslogx(LOG_INFO, "Startup successful"); }
/* open the ups.conf, parse it, and call back do_upsconf_args() */ void read_upsconf(void) { char fn[SMALLBUF]; PCONF_CTX_t ctx; ups_section = NULL; snprintf(fn, sizeof(fn), "%s/ups.conf", confpath()); pconf_init(&ctx, upsconf_err); if (!pconf_file_begin(&ctx, fn)) fatalx(EXIT_FAILURE, "Can't open %s: %s", fn, ctx.errmsg); while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } conf_args(ctx.numargs, ctx.arglist); } pconf_finish(&ctx); free(ups_section); }
int state_setaux(st_tree_t *root, const char *var, const char *auxs) { st_tree_t *sttmp; int aux; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { upslogx(LOG_ERR, "state_addenum: base variable (%s) " "does not exist", var); return -1; /* failed */ } aux = strtol(auxs, (char **) NULL, 10); /* silently ignore matches */ if (sttmp->aux == aux) { return 0; } sttmp->aux = aux; return 1; }
static int upsc_getvalue(const char *cmd, const char *param, const char *resp, const char *nutvar, char *ret) { char var[UPSC_BUFLEN]; char val[UPSC_BUFLEN]; upsdebugx(2, "Request value: %s %s", cmd, param ? param : "\"\""); upscsend(cmd); if (param) upscsend(param); upscrecv(var); upscrecv(val); upsdebugx(2, "Got value: %s %s", var, val); if (strcmp(var, resp)) { upslogx(LOG_ERR, "Bad response to %s %s: %s %s", cmd, param ? param : "\"\"", var, val); return 0; } else { if (nutvar) dstate_setinfo(nutvar, "%s", val); if (ret) strcpy(ret, val); } return 1; }
void upsdrv_initinfo(void) { if (!upsc_commandlist()) { upslogx(LOG_ERR, "No contact with UPS, delaying init."); status = UPSC_STAT_NOTINIT; return; } else { status = 0; } upsc_getbaseinfo(); if (can_upda) { upsc_flush_input(); upscsend("UPDA"); } if (can_upid) { upsc_getvalue("UPID", NULL, "ACID", "ups.id", NULL); } if (can_uppm) { check_uppm(); } /* make sure we have some sensible defaults */ setvar("ups.delay.shutdown", "10"); setvar("ups.delay.reboot", "60"); upsh.instcmd = instcmd; upsh.setvar = setvar; }
static void removetimer(ttype_t *tfind) { ttype_t *tmp, *last; last = NULL; tmp = thead; while (tmp) { if (tmp == tfind) { /* found it */ if (last == NULL) /* deleting first */ thead = tmp->next; else last->next = tmp->next; free(tmp->name); free(tmp); return; } last = tmp; tmp = tmp->next; } /* this one should never happen */ upslogx(LOG_ERR, "removetimer: failed to locate target at %p", (void *)tfind); }
/* get limits and parameters */ static int upsc_getparams(const char *cmd, const simple_t *table) { char var[UPSC_BUFLEN]; char val[UPSC_BUFLEN]; int first = 1; upsc_flush_input(); upscsend(cmd); buffer_empty = 0; while (!buffer_empty) { upscrecv(var); if (strlen(var) == 0) { if (first) upscrecv(var); if (strlen(var) == 0) { ser_comm_fail("Empty string from UPS for %s!", cmd); break; } } first = 0; upscrecv(val); if (strlen(val) == 0) { ser_comm_fail("Empty value from UPS for %s %s!", cmd, var); break; } upsdebugx(2, "Parameter %s %s", var, val); if (!upsc_simple(table, var, val)) upslogx(LOG_ERR, "Unknown response to %s: %s %s", cmd, var, val); } return buffer_empty; }
void upsdrv_initups(void) { char *version; version = getval("protocol"); upsfd = ser_open(device_path); ser_set_rts(upsfd, 0); /* * Try to autodetect which UPS is connected. */ for (mode = 0; subdriver[mode] != NULL; mode++) { if ((version != NULL) && strcasecmp(version, subdriver[mode]->version)) { continue; } ser_set_dtr(upsfd, 1); usleep(10000); if (subdriver[mode]->initups() > 0) { upslogx(LOG_INFO, "CyberPower UPS with %s protocol on %s detected", subdriver[mode]->version, device_path); return; } ser_set_dtr(upsfd, 0); usleep(10000); } fatalx(EXIT_FAILURE, "CyberPower UPS not found on %s", device_path); }