📄 apcsmart.c
字号:
intAPC_get_smallest_delay(int upsfd, const char *cmd, char *smdelay){ char resp[MAX_DELAY_STRING]; char orig[MAX_DELAY_STRING]; int delay, smallest; int rc; if (Debug) { LOG(PIL_DEBUG, "%s: called.", __FUNCTION__); } if (((rc = APC_enter_smartmode(upsfd)) != S_OK) || ((rc = APC_send_cmd(upsfd, cmd)) != S_OK) || ((rc = APC_recv_rsp(upsfd, orig)) != S_OK)) { return (rc); } smallest = atoi(orig); strcpy(smdelay, orig); *resp = '\0'; /* search for smallest delay; need to loop through all possible * values so that we leave delay the way we found it */ while (strcmp(resp, orig) != 0) { if (((rc = APC_send_cmd(upsfd, SWITCH_TO_NEXT_VAL)) != S_OK) || ((rc = APC_recv_rsp(upsfd, resp)) != S_OK)) { return (rc); } if (((rc = APC_enter_smartmode(upsfd)) != S_OK) || ((rc = APC_send_cmd(upsfd, cmd)) != S_OK) || ((rc = APC_recv_rsp(upsfd, resp)) != S_OK)) { return (rc); } if ((delay = atoi(resp)) < smallest) { smallest = delay; strcpy(smdelay, resp); } } return (S_OK);}/* * Initialize the ups */intAPC_init( struct APCDevice *ad ){ int upsfd; char value[MAX_DELAY_STRING];#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif /* if ad->upsfd != -1 device has already been configured. */ /* Just enter smart mode again because otherwise a SmartUPS-1000 */ /* has been observed to sometimes not respond. */ if(ad->upsfd != -1) { if(APC_enter_smartmode(ad->upsfd) != S_OK) return(S_OOPS); return( S_OK ); } /* open serial port and store the fd in ad->upsfd */ if ((upsfd = APC_open_serialport(ad->upsdev, B2400)) == -1) { return (S_OOPS); } /* switch into smart mode */ if(APC_enter_smartmode(upsfd) != S_OK) { APC_close_serialport(upsfd); return( S_OOPS ); } /* get the smallest possible delays for this particular hardware */ if (APC_get_smallest_delay(upsfd, CMD_SHUTDOWN_DELAY , ad->shutdown_delay) != S_OK || APC_get_smallest_delay(upsfd, CMD_WAKEUP_DELAY , ad->wakeup_delay) != S_OK) { APC_close_serialport(upsfd); return S_OOPS; } /* get the old settings and store them */ strcpy(value, ad->shutdown_delay); if (APC_set_ups_var(upsfd, CMD_SHUTDOWN_DELAY, value) != S_OK) { APC_close_serialport(upsfd); return (S_OOPS); } strcpy(ad->old_shutdown_delay, value); strcpy(value, ad->wakeup_delay); if (APC_set_ups_var(upsfd, CMD_WAKEUP_DELAY, value) != S_OK) { APC_close_serialport(upsfd); return (S_OOPS); } strcpy(ad->old_wakeup_delay, value); ad->upsfd = upsfd; return( S_OK );}/* * Restore original settings and close the port */voidAPC_deinit( struct APCDevice *ad ){ APC_enter_smartmode( ad->upsfd ); APC_set_ups_var(ad->upsfd, CMD_SHUTDOWN_DELAY, ad->old_shutdown_delay); APC_set_ups_var(ad->upsfd, CMD_WAKEUP_DELAY, ad->old_wakeup_delay); /* close serial port */ APC_close_serialport(ad->upsfd);}/* * Parse config */intAPC_parse_config_info(struct APCDevice *ad, const char *info ){ char hostname[MAX_STRING]; static char devicename[MAX_STRING]; char **hl;#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (ad->hostcount >= 0) { return(S_OOPS); } if ((hl = (char **)MALLOC((MAX_DEVICES+1)*sizeof(char*))) == NULL) { syslog(LOG_ERR, "%s: out of memory!", __FUNCTION__); return S_OOPS; } memset(hl, 0, (MAX_DEVICES+1)*sizeof(char*)); if (sscanf(info, "%s %s", devicename, hostname) == 2) { g_strdown(hostname); if(( hl[0] = STRDUP(hostname)) == NULL ) { apcsmart_free_hostlist(hl); hl = NULL; return( S_OOPS ); } ad->hostlist = hl; ad->hostcount = MAX_DEVICES+1; ad->upsdev = devicename; return(S_OK); } return(S_BADCONFIG);} /* * return the status for this device */static intapcsmart_status(Stonith * s){ struct APCDevice *ad; char resp[MAX_STRING]; int rc;#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (S_INVAL); } if( !ISCONFIGED(s)) { syslog(LOG_ERR, "%s: device is UNCONFIGURED!", __FUNCTION__ ); return( S_OOPS ); } ad = (struct APCDevice *) s->pinfo; rc = APC_init(ad); /* get status */ if (((rc = APC_init( ad )) == S_OK) && ((rc = APC_send_cmd(ad->upsfd, CMD_GET_STATUS)) == S_OK) && ((rc = APC_recv_rsp(ad->upsfd, resp)) == S_OK)) return (S_OK); /* everything ok. */#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: failed, rc=%d.", __FUNCTION__, rc);#endif return (rc);}/* * return the list of hosts configured for this device */static char **apcsmart_hostlist(Stonith * s){ int numhosts; char **hl; struct APCDevice *ad; int j;#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (NULL); } if( !ISCONFIGED(s)) { syslog(LOG_ERR, "%s: device is UNCONFIGURED!", __FUNCTION__ ); return( NULL ); } ad = (struct APCDevice *) s->pinfo; numhosts = ad->hostcount; if (( hl = (char **)MALLOC(numhosts * sizeof(char *))) == NULL) { syslog(LOG_ERR, "%s: out of memory.", __FUNCTION__); return (hl); } memset(hl, 0, numhosts * sizeof(char *)); for (j = 0; j < numhosts -1; ++j) { if ((hl[j] = STRDUP(ad->hostlist[j])) == NULL) { apcsmart_free_hostlist(hl); hl = NULL; return (hl); } } return (hl);}/* * free the hostlist */static voidapcsmart_free_hostlist(char **hlist){ char **hl = hlist;#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (hl == NULL) return; while (*hl) { FREE(*hl); *hl = NULL; ++hl; } FREE(hlist); hlist = NULL;}static gbooleanapcsmart_RegisterBitsSet(struct APCDevice * ad, int nreg, unsigned bits, gboolean* waserr){ const char* reqregs[4] = {"?", "~", "'", "8"}; unsigned regval; char resp[MAX_STRING]; if (Debug) { LOG(PIL_DEBUG, "%s: called.", __FUNCTION__); } if (APC_enter_smartmode(ad->upsfd) != S_OK || APC_send_cmd(ad->upsfd, reqregs[nreg]) != S_OK || APC_recv_rsp(ad->upsfd, resp) != S_OK || (sscanf(resp, "%02x", ®val) != 1)) { if (waserr){ *waserr = TRUE; } return FALSE; } if (waserr){ *waserr = FALSE; } return ((regval & bits) == bits);}#define apcsmart_ResetHappening(ad,err) apcsmart_RegisterBitsSet(ad,3,0x08,err)/* * reset the host */static intapcsmart_reset_req(Stonith * s, int request, const char *host){ struct APCDevice *ad; char resp[MAX_STRING]; int rc; int i; char **hl; char *shost; int b_found=FALSE;#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (S_INVAL); } if( !ISCONFIGED(s)) { syslog(LOG_ERR, "%s: device is UNCONFIGURED!", __FUNCTION__ ); return( S_OOPS ); } if (host == NULL) { syslog(LOG_ERR, "%s: invalid hostname argument.", __FUNCTION__); return (S_INVAL); } shost = strdup(host); if (shost == NULL) { syslog(LOG_ERR, "%s: strdup failed.", __FUNCTION__); return (S_INVAL); } g_strdown(shost); ad = (struct APCDevice *) s->pinfo; /* look through the hostlist */ hl = ad->hostlist; while (*hl && !b_found ) { if( strcmp( *hl, shost ) == 0 ) { b_found = TRUE; break; } else ++hl; } /* host not found in hostlist */ if( !b_found ) { syslog(LOG_ERR, "%s: host '%s' not in hostlist.", __FUNCTION__, host); rc = S_BADHOST; goto out; } /* send reset command(s) */ if (((rc = APC_init(ad)) == S_OK) && ((rc = APC_send_cmd(ad->upsfd, CMD_RESET)) == S_OK)) { if (((rc = APC_recv_rsp(ad->upsfd, resp)) == S_OK) && (strcmp(resp, RSP_RESET) == 0 || strcmp(resp, RSP_RESET2) == 0)) { /* first kind of reset command was accepted */ } else if (((rc = APC_send_cmd(ad->upsfd, CMD_RESET2)) == S_OK) && ((rc = APC_recv_rsp(ad->upsfd, resp)) == S_OK) && (strcmp(resp, RSP_RESET) == 0 || strcmp(resp, RSP_RESET2) == 0)) { /* second kind of command was accepted */ } else { rc = S_RESETFAIL; } } if (rc == S_OK) { /* we wait grace period + up to 10 seconds after shutdown */ int maxdelay = atoi(ad->shutdown_delay)+10; for (i=0; i < maxdelay; ++i) { gboolean err; if (apcsmart_ResetHappening(ad, &err)) { if (err) { break; }else{ rc = S_OK; goto out; } } sleep(1); } rc = S_RESETFAIL; } /* reset failed */ syslog(LOG_ERR, "%s: resetting host '%s' failed.", __FUNCTION__, host); rc = S_RESETFAIL;out: free(shost); return rc;}/* * parse the information in the given configuration file, * and stash it away... */static intapcsmart_set_config_file(Stonith * s, const char *configname){ FILE *cfgfile; char confline[MAX_STRING]; struct APCDevice *ad; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (S_INVAL); } ad = (struct APCDevice *) s->pinfo; if ((cfgfile = fopen(configname, "r")) == NULL) { syslog(LOG_ERR, "Cannot open %s", configname); return(S_BADCONFIG); } while (fgets(confline, sizeof(confline), cfgfile) != NULL) { if (*confline == '#' || *confline == '\n' || *confline == EOS) continue; return(APC_parse_config_info(ad, confline)); } return(S_BADCONFIG);}/* * Parse the config information in the given string, and stash it away... */static intapcsmart_set_config_info(Stonith * s, const char *info){ struct APCDevice *ad;#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: info: '%s'.", __FUNCTION__, info );#endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (S_INVAL); } ad = (struct APCDevice *) s->pinfo; return(APC_parse_config_info(ad, info));}/* * get info about the stonith device */static const char *apcsmart_getinfo(Stonith * s, int reqtype){ struct APCDevice *ad; const char *ret;#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return NULL; } ad = (struct APCDevice *) s->pinfo; switch (reqtype) { case ST_DEVICEID: ret = ad->APCid; break; case ST_CONF_INFO_SYNTAX: ret = _("devicename hostname\n" "The hostname and devicename are white-space delimited."); break; case ST_CONF_FILE_SYNTAX: ret = _("devicename hostname\n" "The hostname and devicename are white-space delimited.\n" "Both items must be on one line.\n" "Blank lines and lines beginning with # are ignored."); break; case ST_DEVICEDESCR: ret = _("APC Smart UPS (via serial port - model must be >= Smart-UPS 750)"); break; case ST_DEVICEURL: ret = "http://www.apc.com/"; break; default: ret = NULL; break; } return (ret);}/* * APC Stonith destructor... */static voidapcsmart_destroy(Stonith * s){ struct APCDevice *ad;#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return; } ad = (struct APCDevice *) s->pinfo; APC_deinit( ad ); ad->APCid = NOTapcID; if (ad->hostlist) { apcsmart_free_hostlist(ad->hostlist); ad->hostlist = NULL; } ad->hostcount = -1; ad->upsfd = -1; FREE(ad);}/* * Create a new APC Stonith device. Too bad this function can't be * static */static void *apcsmart_new(void){ struct APCDevice *ad = MALLOCT(struct APCDevice);#ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif if (ad == NULL) { syslog(LOG_ERR, "%s: out of memory.", __FUNCTION__); return (NULL); } memset(ad, 0, sizeof(*ad)); ad->APCid = APCid; ad->hostlist = NULL; ad->hostcount = -1; ad->upsfd = -1; return ((void *) ad);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -