/* * $Id: apc.c,v 2.0.1.5 1996/06/26 18:39:38 alexis Exp alexis $ * * UPS Daemon * The Wild Wind Communications, 1995, 1996 * * See file LICENSE for the distribution terms of this software. */ #include "upsd.h" #include "apc.h" char apc_SmartWriteBuffer[MAXAPCWRITEBUFFER]; /* * Polls APC SmartUPS value. * * Returns -1 on error, 1 if timed out or 0 if succeeded. */ int apc_poll(val) struct ups_val *val; { register int s; char *t; struct ups_reg *r; if((r = REGISTERID(val->id)) == NULL) { syslog(LOG_ERR, "apc_poll: incorrect register id"); return -1; } if((t = alloca(POLLBUFLEN)) == NULL) { syslog(LOG_ERR, "apc_poll: alloca failed: %m"); return -1; } for(;;) { flushport(); if((s = writeport(r->cmd_data, r->cmd_size)) != r->cmd_size) { return -1; /* Can't write to the port. */ } if(r->size == 0) { return 0; /* We don't expect anything back. */ } if((s = readport(t, r->size, 1)) == -1) { return -1; /* Can't read the port. */ }; if(s != r->size) { return 1; /* Timed out on readport. */ }; switch(r->type) { case T_BINARY: bcopy(t, val->val.binary, (size_t) r->size - r->prec); ((char *)val->val.binary)[r->size - r->prec] = '\0'; /* XXX: correct? */ return 0; /* NOTREACHED */ case T_HEX: val->val.number = (double)strtol(t, (char **)NULL, 16); return 0; /* NOTREACHED */ case T_DEC: val->val.number = (double)strtol(t, (char **)NULL, 10); return 0; /* NOTREACHED */ case T_OCT: val->val.number = (double)strtol(t, (char **)NULL, 8); return 0; /* NOTREACHED */ case T_NUMBER: val->val.number = strtod(t, (char **)NULL); return 0; /* NOTREACHED */ default: syslog(LOG_ERR, "apc_poll: incorrect value type"); return -1; /* NOTREACHED */ } /* NOTREACHED */ } /* NOTREACHED */ return -1; } /* * Tunes the value of APC SmartUPS. * * Returns -1 upon error, 1 if the string was not toggled, and zero * if succeeded. */ int apc_tune(val) struct ups_val *val; { register struct ups_reg *r, *tr; struct ups_val v0, v1, t; if((r = REGISTERID(val->id)) == NULL) { syslog(LOG_ERR, "apc_tune: incorrect value id to tune"); return -1; } switch(r->mode) { case APC_TOGGLE: t.id = SMART_MODIFY; if((tr = REGISTERID(t.id)) == NULL) { syslog(LOG_ERR, "apc_tune: cannot find modify register"); return -1; } if((t.val.binary = alloca(tr->size)) == NULL) { syslog(LOG_ERR, "apc_tune: cannot allocate memory in stack for modifier: %m"); return -1; } v0.id = v1.id = r->id; if((r->type & T_TYPE) == T_BINARY) { if(((v0.val.binary = alloca(r->size)) == NULL) || ((v1.val.binary = alloca(r->size)) == NULL)) { syslog(LOG_ERR, "apc_tune: cannot allocate memory in stack for new values: %m"); return -1; } } switch(apc_poll(&v0)) { case 1: return 1; case -1: return -1; } if((r->type & T_TYPE) == T_BINARY) { bcopy(v0.val.binary, v1.val.binary, r->size); } else { v1.val.number = v0.val.number; } for(;;) { if((r->type & T_TYPE) == T_BINARY) { if(!bcmp(val->val.binary, v1.val.binary, r->size)) { return 0; } } else { if(val->val.number == v1.val.number) { return 0; } } switch(apc_poll(&t)) { case 1: return 1; case -1: return -1; } if(bcmp(t.val.binary, apc_SmartUPS_OK, 2)) { syslog(LOG_ERR, "apc_tune: negative response: %*s", r->size, t.val.binary); return 1; } switch(apc_poll(&v1)) { case 1: return 1; case -1: return -1; } if((r->type & T_TYPE) == T_BINARY) { if(!bcmp(v1.val.binary, v0.val.binary, r->size)) { syslog(LOG_WARNING, "apc_tune: toggle wraparound register %s", r->name); return 1; } } else { if(v1.val.number == v0.val.number) { syslog(LOG_WARNING, "apc_tune: toggle wraparound register %s", r->name); return 1; } } } /* NOTREACHED */ break; /* APC_TOGGLE */ case APC_WRITE: if((r->type & T_TYPE) != T_BINARY) { syslog(LOG_ERR, "apc_tune: only binary values can be overwritten"); return -1; } t.id = SMART_WRITE; if((tr = REGISTERID(t.id)) == NULL) { syslog(LOG_ERR, "apc_tune: cannot find write register"); return -1; } if((t.val.binary = alloca(tr->size)) == NULL) { syslog(LOG_ERR, "apc_tune: cannot allocate memory in stack for modifier: %m"); return -1; } v0.id = r->id; if((v0.val.binary = alloca(r->size)) == NULL) { syslog(LOG_ERR, "apc_tune: cannot allocate memory in stack for new value: %m"); return -1; } switch(apc_poll(&v0)) { case 1: return 1; case -1: return -1; } if(!bcmp(v0.val.binary, val->val.binary, r->size - r->prec)) { return 0; } apc_SmartWriteBuffer[0] = '-'; bcopy(val->val.binary, &apc_SmartWriteBuffer[1], r->size); tr->cmd_size = r->size - r->prec + 1; switch(apc_poll(&t)) { case 1: return 1; case -1: return -1; } if(bcmp(t.val.binary, apc_SmartUPS_OK, 2)) { syslog(LOG_ERR, "apc_tune: negative response"); return 1; /* the response was not OK */ } { struct timeval wd = APCWRITEDELAY; (void) select(0, NULL, NULL, NULL, &wd); } return 0; /* NOTREACHED */ break; /* MTHD_WRITE */ default: syslog(LOG_ERR, "apc_tune: this register cannot be modified"); return -1; /* NOTREACHED */ } /* NOTREACHED */ return -1; }