1 /*
2  * Client test program for apcnisd to be used
3  * as a base for the new master/slave code.
4  *
5  * Build it with: cc upsapm.c ../lib/libapc.a -o newclient
6  *
7  * Execute: ./upsapm [host[:port]]
8  *
9  * The two commands currently (Apr 2001) accepted by the
10  * server are "status" and "events".
11  *
12  *  Format of /proc/apm is when online and no apm:
13  *   1.14 1.2 0x03 0x01 0xff 0x80 -1% -1 ?
14  *
15  *   1.14 = kernel driver version
16  *   1.2  = apm_major_version.apm_minor_version
17  *   0x03 = apm_flags
18  *   0x01 = on_line_status
19  *	    0 = off line
20  *	    1 = on line
21  *	    2 = on back
22  *   0xff = battery status
23  *	   ff = (none?)
24  *	    0 = high
25  *	    1 = low
26  *	    2 = crit
27  *	    3 = charg
28  *   0x80 = battery_flags
29  *    -1% = battery percentage
30  *     -1 = battery time
31  *	? = (if min battery minutes otherwise seconds)
32  *
33  *
34  */
35 
36 #include "apc.h"
37 
38 #ifdef HAVE_NISLIB
39 
40 /* Default values, can be changed on command line */
41 #define SERV_TCP_PORT 3551
42 #define SERV_HOST_ADDR "127.0.0.1"
43 
44 #define BIGBUF 4096
45 char statbuf[BIGBUF];
46 int statlen = BIGBUF;
47 
48 /* List of variables that can be read by getupsvar()
49  * First field is that name given to getupsvar(),
50  * Second field is our internal name as produced by the STATUS
51  *   output from apcupsd.
52  * Third field, if 0 returns everything to the end of the
53  *    line, and if 1 returns only to first space (e.g. integers,
54  *    and floating point values.
55  */
56 static struct {
57    const char *request;
58    const char *upskeyword;
59    int nfields;
60 } cmdtrans[] = {
61    {"date",       "DATE",     0},
62    {"battcap",    "BCHARGE",  1},
63    {"mbattchg",   "MBATTCHG", 1},
64    {"status",     "STATFLAG", 1},
65    {"runtime",    "TIMELEFT", 1},
66    {"battpct",    "BCHARGE",  1},
67    {NULL, NULL}
68 };
69 
70 int fetch_data(char *host, int port);
71 int getupsvar(char *host, int port, const char *request, char *answer, int anslen);
72 int fill_buffer(int sockfd);
73 
74 extern int net_errno;
75 
error_abort(const char * msg)76 void error_abort(const char *msg)
77 {
78    fprintf(stderr, msg);
79    exit(1);
80 }
81 
main(int argc,char * argv[])82 int main(int argc, char *argv[])
83 {
84    int port;
85    char host[200];
86    char msg[200], *p;
87    long stat_flag;
88    int battchg;
89    int runtime;
90 
91    strcpy(host, SERV_HOST_ADDR);
92    port = SERV_TCP_PORT;
93 
94    if (argc > 1) {
95       strcpy(host, argv[1]); /* get host from command line */
96       p = strchr(host, ':');
97       if (p) {
98 	 *p++ = 0;
99 	 port = atoi(p);
100       }
101    }
102 
103    /* make sure we are communicating */
104    if (getupsvar(host, port, "date", msg, sizeof(msg)) <= 0) {
105        printf("1.14 1.2 0x03 0x01 0xff 0x80 -1%% -1 ? : Cannot get date\n");
106        exit(1);
107    }
108 
109    if (getupsvar(host, port, "status", msg, sizeof(msg)) <= 0) {
110        printf("1.14 1.2 0x03 0x01 0xff 0x80 -1%% -1 ? : Cannot get status\n");
111        exit(1);
112    }
113    stat_flag = strtol(msg, NULL, 16);
114 
115    if (getupsvar(host, port, "battcap", msg, sizeof(msg)) <= 0) {
116        printf("1.14 1.2 0x03 0x01 0xff 0x80 -1%% -1 ? : Cannot get battcap\n");
117        exit(1);
118    }
119 
120    battchg = (int)strtod(msg, NULL);
121 
122    if (getupsvar(host, port, "runtime", msg, sizeof(msg)) <= 0) {
123        printf("1.14 1.2 0x03 0x01 0xff 0x80 -1%% -1 ? : Cannot get runtime\n");
124        exit(1);
125    }
126 
127    runtime = (int)strtod(msg, NULL);
128 
129    if (stat_flag & 0x8) {
130       printf("1.14 1.2 0x03 0x01 0x03 0x09 %d%% -1 ?\n", battchg);
131    } else {
132       printf("1.14 1.2 0x03 0x00 0x00 0x01 %d%% %d min\n", battchg, runtime);
133    }
134 
135    exit(0);
136 }
137 
138 
139 /*
140  * Read data into memory buffer to be used by getupsvar()
141  * Returns 0 on error
142  * Returns 1 if data fetched
143  */
fetch_data(char * host,int port)144 int fetch_data(char *host, int port)
145 {
146    int sockfd;
147    int stat;
148 
149    if ((sockfd = net_open(host, NULL, port)) < 0) {
150       printf("fetch_data: tcp_open failed for %s port %d", host, port);
151       return 0;
152    }
153 
154    stat = fill_buffer(sockfd);		     /* fill statbuf */
155    net_close(sockfd);
156    return stat;
157 
158 }
159 
160 /*
161  *
162  * Returns 1 if var found
163  *   answer has var
164  * Returns 0 if variable name not found
165  *   answer has "Not found" is variable name not found
166  *   answer may have "N/A" if the UPS does not support this
167  *	 feature
168  * Returns -1 if network problem
169  *   answer has "N/A" if host is not available or network error
170  */
getupsvar(char * host,int port,const char * request,char * answer,int anslen)171 int getupsvar(char *host, int port, const char *request, char *answer, int anslen)
172 {
173     int i;
174     const char *stat_match = NULL;
175     char *find;
176     int nfields = 0;
177 
178     if (!fetch_data(host, port)) {
179         strcpy(answer, "N/A");
180 	return -1;
181     }
182 
183     for (i=0; cmdtrans[i].request; i++)
184 	if (!(strcmp(cmdtrans[i].request, request))) {
185 	     stat_match = cmdtrans[i].upskeyword;
186 	     nfields = cmdtrans[i].nfields;
187 	}
188 
189     if (stat_match != NULL) {
190 	if ((find=strstr(statbuf, stat_match)) != NULL) {
191 	     if (nfields == 1)	/* get one field */
192                  sscanf (find, "%*s %*s %s", answer);
193 	     else {		/* get everything to eol */
194 		 i = 0;
195 		 find += 11;  /* skip label */
196                  while (*find != '\n')
197 		     answer[i++] = *find++;
198 		 answer[i] = 0;
199 	     }
200              if (strcmp(answer, "N/A") == 0)
201 		 return 0;
202 	     return 1;
203 	}
204     }
205 
206     strcpy(answer, "Not found");
207     return 0;
208 }
209 
210 #define MAXLINE 512
211 
212 /* Fill buffer with data from UPS network daemon
213  * Returns 0 on error
214  * Returns 1 if OK
215  */
fill_buffer(int sockfd)216 int fill_buffer(int sockfd)
217 {
218    int n, stat = 1;
219    char buf[1000];
220 
221    statbuf[0] = 0;
222    statlen = 0;
223    if (net_send(sockfd, "status", 6) != 6) {
224       printf("fill_buffer: write error on socket\n");
225       return 0;
226    }
227 
228    while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) {
229       buf[n] = 0;
230       strcat(statbuf, buf);
231    }
232    if (n < 0)
233       stat = 0;
234 
235    statlen = strlen(statbuf);
236    return stat;
237 
238 }
239 
240 #else /* HAVE_NISLIB */
241 
main(int argc,char * argv[])242 int main(int argc, char *argv[]) {
243     printf("Sorry, NIS code is not compiled in apcupsd.\n");
244     return 1;
245 }
246 
247 #endif /* HAVE_NISLIB */
248