/* 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); }
static void conn_add(int sockfd) { int acc, ret; conn_t *tmp, *last; struct sockaddr_un saddr; #if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED) int salen; #else socklen_t salen; #endif salen = sizeof(saddr); acc = accept(sockfd, (struct sockaddr *) &saddr, &salen); if (acc < 0) { upslog_with_errno(LOG_ERR, "accept on unix fd failed"); return; } /* enable nonblocking I/O */ ret = fcntl(acc, F_GETFL, 0); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl get on unix fd failed"); close(acc); return; } ret = fcntl(acc, F_SETFL, ret | O_NDELAY); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl set O_NDELAY on unix fd failed"); close(acc); return; } tmp = last = connhead; while (tmp) { last = tmp; tmp = tmp->next; } tmp = xmalloc(sizeof(conn_t)); tmp->fd = acc; tmp->next = NULL; if (last) last->next = tmp; else connhead = tmp; upsdebugx(3, "new connection on fd %d", acc); pconf_init(&tmp->ctx, NULL); }
static void sock_connect(int sock) { int fd, ret; conn_t *conn; struct sockaddr_un sa; #if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED) int salen; #else socklen_t salen; #endif salen = sizeof(sa); fd = accept(sock, (struct sockaddr *) &sa, &salen); if (fd < 0) { upslog_with_errno(LOG_ERR, "accept on unix fd failed"); return; } /* enable nonblocking I/O */ if (!do_synchronous) { ret = fcntl(fd, F_GETFL, 0); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl get on unix fd failed"); close(fd); return; } ret = fcntl(fd, F_SETFL, ret | O_NDELAY); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl set O_NDELAY on unix fd failed"); close(fd); return; } } conn = xcalloc(1, sizeof(*conn)); conn->fd = fd; pconf_init(&conn->ctx, NULL); if (connhead) { conn->next = connhead; connhead->prev = conn; } connhead = conn; upsdebugx(3, "new connection on fd %d", fd); }
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 void loadconfig(void) { PCONF_CTX_t ctx; pconf_init(&ctx, upsmon_err); if (!pconf_file_begin(&ctx, configfile)) { pconf_finish(&ctx); if (reload_flag == 1) { upslog_with_errno(LOG_ERR, "Reload failed: %s", ctx.errmsg); return; } fatalx(EXIT_FAILURE, "%s", ctx.errmsg); } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", configfile, ctx.linenum, ctx.errmsg); continue; } if (ctx.numargs < 1) continue; if (!parse_conf_arg(ctx.numargs, ctx.arglist)) { unsigned int i; char errmsg[SMALLBUF]; snprintf(errmsg, sizeof(errmsg), "%s line %d: invalid directive", configfile, ctx.linenum); 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 sstate_connect(void) { int ret, fd; const char *dumpcmd = "DUMPALL\n"; struct sockaddr_un sa; memset(&sa, '\0', sizeof(sa)); sa.sun_family = AF_UNIX; snprintf(sa.sun_path, sizeof(sa.sun_path), "%s/%s", dflt_statepath(), device_path); fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { upslog_with_errno(LOG_ERR, "Can't create socket for UPS [%s]", device_path); return -1; } ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa)); if (ret < 0) { time_t now; close(fd); /* rate-limit complaints - don't spam the syslog */ time(&now); if (difftime(now, last_connfail) < 60) { return -1; } last_connfail = now; upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s]", device_path); return -1; } ret = fcntl(fd, F_GETFL, 0); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl get on UPS [%s] failed", device_path); close(fd); return -1; } ret = fcntl(fd, F_SETFL, ret | O_NDELAY); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl set O_NDELAY on UPS [%s] failed", device_path); close(fd); return -1; } /* get a dump started so we have a fresh set of data */ ret = write(fd, dumpcmd, strlen(dumpcmd)); if (ret != (int)strlen(dumpcmd)) { upslog_with_errno(LOG_ERR, "Initial write to UPS [%s] failed", device_path); close(fd); return -1; } pconf_init(&sock_ctx, NULL); time(&last_heard); dumpdone = 0; /* set ups.status to "WAIT" while waiting for the driver response to dumpcmd */ dstate_setinfo("ups.status", "WAIT"); upslogx(LOG_INFO, "Connected to UPS [%s]", device_path); return fd; }
/* for dummy mode * parse the definition file and process its content */ static int parse_data_file(int upsfd) { char fn[SMALLBUF]; char *ptr, var_value[MAX_STRING_SIZE]; int value_args = 0, counter; time_t now; time(&now); upsdebugx(1, "entering parse_data_file()"); if (now < next_update) { upsdebugx(1, "leaving (paused)..."); return 1; } /* initialise everything, to loop back at the beginning of the file */ if (ctx == NULL) { ctx = (PCONF_CTX_t *)xmalloc(sizeof(PCONF_CTX_t)); if (device_path[0] == '/') snprintf(fn, sizeof(fn), "%s", device_path); else snprintf(fn, sizeof(fn), "%s/%s", confpath(), device_path); pconf_init(ctx, upsconf_err); if (!pconf_file_begin(ctx, fn)) fatalx(EXIT_FAILURE, "Can't open dummy-ups definition file %s: %s", fn, ctx->errmsg); } /* Reset the next call time, so that we can loop back on the file * if there is no blocking action (ie TIMER) until the end of the file */ next_update = -1; /* Now start or continue parsing... */ while (pconf_file_next(ctx)) { if (pconf_parse_error(ctx)) { upsdebugx(2, "Parse error: %s:%d: %s", fn, ctx->linenum, ctx->errmsg); continue; } /* Check if we have something to process */ if (ctx->numargs < 1) continue; /* Process actions (only "TIMER" ATM) */ if (!strncmp(ctx->arglist[0], "TIMER", 5)) { /* TIMER <seconds> will wait "seconds" before * continuing the parsing */ int delay = atoi (ctx->arglist[1]); time(&next_update); next_update += delay; upsdebugx(1, "suspending execution for %i seconds...", delay); break; } /* Remove ":" suffix, after the variable name */ if ((ptr = strchr(ctx->arglist[0], ':')) != NULL) *ptr = '\0'; upsdebugx(3, "parse_data_file: variable \"%s\" with %d args", ctx->arglist[0], (int)ctx->numargs); /* Skip the driver.* collection data */ if (!strncmp(ctx->arglist[0], "driver.", 7)) { upsdebugx(2, "parse_data_file: skipping %s", ctx->arglist[0]); continue; } /* From there, we get varname in arg[0], and values in other arg[1...x] */ /* special handler for status */ if (!strncmp( ctx->arglist[0], "ups.status", 10)) { status_init(); for (counter = 1, value_args = ctx->numargs ; counter < value_args ; counter++) { status_set(ctx->arglist[counter]); } status_commit(); } else { for (counter = 1, value_args = ctx->numargs ; counter < value_args ; counter++) { if (counter == 1) /* don't append the first space separator */ snprintf(var_value, sizeof(var_value), "%s", ctx->arglist[counter]); else snprintfcat(var_value, sizeof(var_value), " %s", ctx->arglist[counter]); } if (setvar(ctx->arglist[0], var_value) == STAT_SET_UNKNOWN) { upsdebugx(2, "parse_data_file: can't add \"%s\" with value \"%s\"\nError: %s", ctx->arglist[0], var_value, ctx->errmsg); } else { upsdebugx(3, "parse_data_file: added \"%s\" with value \"%s\"", ctx->arglist[0], var_value); } } } /* Cleanup parseconf if there is no pending action */ if (next_update == -1) { pconf_finish(ctx); free(ctx); ctx=NULL; } return 1; }
int upscli_connect(UPSCONN *ups, const char *host, int port, int flags) { struct sockaddr_in local, server; struct hostent *serv; unsigned long numericIPAddr=INADDR_NONE; /* clear out any lingering junk */ ups->fd = INVALID_SOCKET; ups->host = NULL; ups->flags = 0; ups->upserror = 0; ups->syserrno = 0; ups->upsclient_magic = UPSCLIENT_MAGIC; ups->pc_ctx = malloc(sizeof(PCONF_CTX)); if (!ups->pc_ctx) { ups->upserror = UPSCLI_ERR_NOMEM; return -1; } pconf_init(ups->pc_ctx, NULL); ups->ssl_ctx = NULL; ups->ssl = NULL; if (!host) { ups->upserror = UPSCLI_ERR_NOSUCHHOST; return -1; } memset(&local, '\0', sizeof(struct sockaddr_in)); local.sin_family = AF_INET; local.sin_port = htons(INADDR_ANY); memset(&server, '\0', sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons((u_short)port); //Windows is brain dead when it comes to gethostbyname and numeric ip addresses. GRRrrrr numericIPAddr = inet_addr(host); if(numericIPAddr != INADDR_NONE) { /* the string is a numeric IP address, just set it on the server addr struct */ server.sin_addr.s_addr = numericIPAddr; } else if((serv = gethostbyname(host)) != (struct hostent *) NULL) { /* the string is a DNS name, we resolved and stored it to the serv structure so now set it on the server struct */ memcpy (&server.sin_addr, serv->h_addr, serv->h_length); } else /* could not resolve name or IP */ { ups->upserror = UPSCLI_ERR_NOSUCHHOST; ups->syserrno = errno = WSAGetLastError(); return (-1); } if ((ups->fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { ups->upserror = UPSCLI_ERR_SOCKFAILURE; ups->syserrno = errno = WSAGetLastError(); return -1; } if (bind(ups->fd, (struct sockaddr *) &local, sizeof(struct sockaddr_in)) == -1) { ups->upserror = UPSCLI_ERR_BINDFAILURE; ups->syserrno = errno; close(ups->fd); ups->fd = INVALID_SOCKET; return -1; } if (connect(ups->fd, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) == -1) { ups->upserror = UPSCLI_ERR_CONNFAILURE; ups->syserrno = errno; close(ups->fd); ups->fd = INVALID_SOCKET; return -1; } /* don't use xstrdup for cleaner linking (fewer dependencies) */ ups->host = strdup(host); if (!ups->host) { close(ups->fd); ups->fd = INVALID_SOCKET; ups->upserror = UPSCLI_ERR_NOMEM; return -1; } ups->port = port; if (flags & UPSCLI_CONN_TRYSSL) { upscli_sslinit(ups); /* see if something made us die inside sslinit */ if (ups->upserror != 0) return -1; } if (flags & UPSCLI_CONN_REQSSL) { if (upscli_sslinit(ups) != 1) { ups->upserror = UPSCLI_ERR_SSLFAIL; upscli_closefd(ups); return -1; } } return 0; }
int upscli_tryconnect(UPSCONN_t *ups, const char *host, int port, int flags,struct timeval * timeout) { int sock_fd; struct addrinfo hints, *res, *ai; char sport[NI_MAXSERV]; int v; fd_set wfds; int error; socklen_t error_size; long fd_flags; if (!ups) { return -1; } /* clear out any lingering junk */ memset(ups, 0, sizeof(*ups)); ups->upsclient_magic = UPSCLIENT_MAGIC; ups->fd = -1; if (!host) { ups->upserror = UPSCLI_ERR_NOSUCHHOST; return -1; } snprintf(sport, sizeof(sport), "%hu", (unsigned short int)port); memset(&hints, 0, sizeof(hints)); if (flags & UPSCLI_CONN_INET6) { hints.ai_family = AF_INET6; } else if (flags & UPSCLI_CONN_INET) { hints.ai_family = AF_INET; } else { hints.ai_family = AF_UNSPEC; } hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; while ((v = getaddrinfo(host, sport, &hints, &res)) != 0) { switch (v) { case EAI_AGAIN: continue; case EAI_NONAME: ups->upserror = UPSCLI_ERR_NOSUCHHOST; return -1; case EAI_MEMORY: ups->upserror = UPSCLI_ERR_NOMEM; return -1; case EAI_SYSTEM: ups->syserrno = errno; break; } ups->upserror = UPSCLI_ERR_UNKNOWN; return -1; } for (ai = res; ai != NULL; ai = ai->ai_next) { sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock_fd < 0) { switch (errno) { case EAFNOSUPPORT: case EINVAL: break; default: ups->upserror = UPSCLI_ERR_SOCKFAILURE; ups->syserrno = errno; } continue; } /* non blocking connect */ if(timeout != NULL) { fd_flags = fcntl(sock_fd, F_GETFL); fd_flags |= O_NONBLOCK; fcntl(sock_fd, F_SETFL, fd_flags); } while ((v = connect(sock_fd, ai->ai_addr, ai->ai_addrlen)) < 0) { if(errno == EINPROGRESS) { FD_ZERO(&wfds); FD_SET(sock_fd, &wfds); select(sock_fd+1,NULL,&wfds,NULL, timeout); if (FD_ISSET(sock_fd, &wfds)) { error_size = sizeof(error); getsockopt(sock_fd,SOL_SOCKET,SO_ERROR, &error,&error_size); if( error == 0) { /* connect successful */ v = 0; break; } errno = error; } else { /* Timeout */ v = -1; break; } } switch (errno) { case EAFNOSUPPORT: break; case EINTR: case EAGAIN: continue; default: ups->upserror = UPSCLI_ERR_CONNFAILURE; ups->syserrno = errno; } break; } if (v < 0) { close(sock_fd); continue; } /* switch back to blocking operation */ if(timeout != NULL) { fd_flags = fcntl(sock_fd, F_GETFL); fd_flags &= ~O_NONBLOCK; fcntl(sock_fd, F_SETFL, fd_flags); } ups->fd = sock_fd; ups->upserror = 0; ups->syserrno = 0; break; } freeaddrinfo(res); if (ups->fd < 0) { return -1; } pconf_init(&ups->pc_ctx, NULL); ups->host = strdup(host); if (!ups->host) { ups->upserror = UPSCLI_ERR_NOMEM; upscli_disconnect(ups); return -1; } ups->port = port; if (flags & UPSCLI_CONN_TRYSSL) { upscli_sslinit(ups); /* see if something made us die inside sslinit */ if (ups->upserror != 0) { upscli_disconnect(ups); return -1; } } if ((flags & UPSCLI_CONN_REQSSL) && (upscli_sslinit(ups) != 1)) { ups->upserror = UPSCLI_ERR_SSLFAIL; upscli_disconnect(ups); return -1; } return 0; }