~iheino+ub/+junk/nut-upsconf-docfix

1 by Laurent Bigonville
Import upstream version 2.7.2
1
/* upscmd - simple "client" to test instant commands via upsd
2
3
   Copyright (C) 2000  Russell Kroll <rkroll@exploits.org>
4
5
   This program is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; either version 2 of the License, or
8
   (at your option) any later version.
9
10
   This program is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU General Public License for more details.
14
15
   You should have received a copy of the GNU General Public License
16
   along with this program; if not, write to the Free Software
17
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
*/
19
20
#include "common.h"
21
#include "nut_platform.h"
22
23
#include <pwd.h>
24
#include <netdb.h>
25
#include <sys/types.h>
26
#include <netinet/in.h>
27
#include <sys/socket.h>
28
29
#include "upsclient.h"
30
31
static char		*upsname = NULL, *hostname = NULL;
32
static UPSCONN_t	*ups = NULL;
33
34
struct list_t {
35
	char	*name;
36
	struct list_t	*next;
37
};
38
39
static void usage(const char *prog)
40
{
41
	printf("Network UPS Tools upscmd %s\n\n", UPS_VERSION);
42
	printf("usage: %s [-h]\n", prog);
43
	printf("       %s [-l <ups>]\n", prog);
44
	printf("       %s [-u <username>] [-p <password>] <ups> <command> [<value>]\n\n", prog);
45
	printf("Administration program to initiate instant commands on UPS hardware.\n");
46
	printf("\n");
47
	printf("  -h		display this help text\n");
48
	printf("  -l <ups>	show available commands on UPS <ups>\n");
49
	printf("  -u <username>	set username for command authentication\n");
50
	printf("  -p <password>	set password for command authentication\n");
51
	printf("\n");
52
	printf("  <ups>		UPS identifier - <upsname>[@<hostname>[:<port>]]\n");
53
	printf("  <command>	Valid instant command - test.panel.start, etc.\n");
54
	printf("  [<value>]	Additional data for command - number of seconds, etc.\n");
55
}
56
57
static void print_cmd(char *cmdname)
58
{
59
	int		ret;
60
	unsigned int	numq, numa;
61
	const char	*query[4];
62
	char		**answer;
63
64
	query[0] = "CMDDESC";
65
	query[1] = upsname;
66
	query[2] = cmdname;
67
	numq = 3;
68
69
	ret = upscli_get(ups, numq, query, &numa, &answer);
70
71
	if ((ret < 0) || (numa < numq)) {
72
		printf("%s\n", cmdname);
73
		return;
74
	}
75
76
	/* CMDDESC <upsname> <cmdname> <desc> */
77
	printf("%s - %s\n", cmdname, answer[3]);
78
}
79
80
static void listcmds(void)
81
{
82
	int		ret;
83
	unsigned int	numq, numa;
84
	const char	*query[4];
85
	char		**answer;
86
	struct list_t	*lhead = NULL, *llast = NULL, *ltmp, *lnext;
87
88
	query[0] = "CMD";
89
	query[1] = upsname;
90
	numq = 2;
91
92
	ret = upscli_list_start(ups, numq, query);
93
94
	if (ret < 0) {
95
96
		/* old upsd = no way to continue */
97
		if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) {
98
			fatalx(EXIT_FAILURE, "Error: upsd is too old to support this query");
99
		}
100
101
		fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups));
102
	}
103
104
	while (upscli_list_next(ups, numq, query, &numa, &answer) == 1) {
105
106
		/* CMD <upsname> <cmdname> */
107
		if (numa < 3) {
108
			fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least 3)", numa);
109
		}
110
111
		/* we must first read the entire list of commands,
112
		   before we can start reading the descriptions */
113
114
		ltmp = xcalloc(1, sizeof(*ltmp));
115
		ltmp->name = xstrdup(answer[2]);
116
117
		if (llast) {
118
			llast->next = ltmp;
119
		} else {
120
			lhead = ltmp;
121
		}
122
123
		llast = ltmp;
124
	}
125
126
	/* walk the list and try to get descriptions, freeing as we go */
127
	printf("Instant commands supported on UPS [%s]:\n\n", upsname);
128
129
	for (ltmp = lhead; ltmp; ltmp = lnext) {
130
		lnext = ltmp->next;
131
132
		print_cmd(ltmp->name);
133
134
		free(ltmp->name);
135
		free(ltmp);
136
	}
137
}
138
139
static void do_cmd(char **argv, const int argc)
140
{
141
	char	buf[SMALLBUF];
142
143
	if (argc > 1) {
144
		snprintf(buf, sizeof(buf), "INSTCMD %s %s %s\n", upsname, argv[0], argv[1]);
145
	} else {
146
		snprintf(buf, sizeof(buf), "INSTCMD %s %s\n", upsname, argv[0]);
147
	}
148
149
	if (upscli_sendline(ups, buf, strlen(buf)) < 0) {
150
		fatalx(EXIT_FAILURE, "Can't send instant command: %s", upscli_strerror(ups));
151
	}
152
153
	if (upscli_readline(ups, buf, sizeof(buf)) < 0) {
154
		fatalx(EXIT_FAILURE, "Instant command failed: %s", upscli_strerror(ups));
155
	}
156
157
	/* FUTURE: status cookies will tie in here */
158
	if (strncmp(buf, "OK", 2) != 0) {
159
		fatalx(EXIT_FAILURE, "Unexpected response from upsd: %s", buf);
160
	}
161
162
	fprintf(stderr, "%s\n", buf);
163
}
164
165
static void clean_exit(void)
166
{
167
	if (ups) {
168
		upscli_disconnect(ups);
169
	}
170
171
	free(upsname);
172
	free(hostname);
173
	free(ups);
174
}
175
176
int main(int argc, char **argv)
177
{
178
	int	i, ret, port;
179
	int	have_un = 0, have_pw = 0, cmdlist = 0;
180
	char	buf[SMALLBUF], username[SMALLBUF], password[SMALLBUF];
181
	const char	*prog = xbasename(argv[0]);
182
183
	while ((i = getopt(argc, argv, "+lhu:p:V")) != -1) {
184
185
		switch (i)
186
		{
187
		case 'l':
188
			cmdlist = 1;
189
			break;
190
191
		case 'u':
192
			snprintf(username, sizeof(username), "%s", optarg);
193
			have_un = 1;
194
			break;
195
196
		case 'p':
197
			snprintf(password, sizeof(password), "%s", optarg);
198
			have_pw = 1;
199
			break;
200
201
		case 'V':
202
			fatalx(EXIT_SUCCESS, "Network UPS Tools upscmd %s", UPS_VERSION);
203
204
		case 'h':
205
		default:
206
			usage(prog);
207
			exit(EXIT_SUCCESS);
208
		}
209
	}
210
211
	argc -= optind;
212
	argv += optind;
213
214
	if (argc < 1) {
215
		usage(prog);
216
		exit(EXIT_SUCCESS);
217
	}
218
219
	/* be a good little client that cleans up after itself */
220
	atexit(clean_exit);
221
222
	if (upscli_splitname(argv[0], &upsname, &hostname, &port) != 0) {
223
		fatalx(EXIT_FAILURE, "Error: invalid UPS definition.  Required format: upsname[@hostname[:port]]");
224
	}
225
226
	ups = xcalloc(1, sizeof(*ups));
227
228
	if (upscli_connect(ups, hostname, port, 0) < 0) {
229
		fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups));
230
	}
231
232
	if (cmdlist) {
233
		listcmds();
234
		exit(EXIT_SUCCESS);
235
	}
236
237
	if (argc < 2) {
238
		usage(prog);
239
		exit(EXIT_SUCCESS);
240
	}
241
242
	/* also fallback for old command names */
243
	if (!strchr(argv[1], '.')) {
244
		fatalx(EXIT_FAILURE, "Error: old command names are not supported");
245
	}
246
247
	if (!have_un) {
248
		struct passwd	*pw;
249
250
		memset(username, '\0', sizeof(username));
251
		pw = getpwuid(getuid());
252
253
		if (pw) {
254
			printf("Username (%s): ", pw->pw_name);
255
		} else {
256
			printf("Username: ");
257
		}
258
259
		if (!fgets(username, sizeof(username), stdin)) {
260
			fatalx(EXIT_FAILURE, "Error reading from stdin!");
261
		}
262
263
		/* deal with that pesky newline */
264
		if (strlen(username) > 1) {
265
			username[strlen(username) - 1] = '\0';
266
		} else {
267
			if (!pw) {
268
				fatalx(EXIT_FAILURE, "No username available - even tried getpwuid");
269
			}
270
271
			snprintf(username, sizeof(username), "%s", pw->pw_name);
272
		}
273
	}
274
275
	/* getpass leaks slightly - use -p when testing in valgrind */
276
	if (!have_pw) {
277
		/* using getpass or getpass_r might not be a
278
		   good idea here (marked obsolete in POSIX) */
279
		char	*pwtmp = GETPASS("Password: ");
280
281
		if (!pwtmp) {
282
			fatalx(EXIT_FAILURE, "getpass failed: %s", strerror(errno));
283
		}
284
285
		snprintf(password, sizeof(password), "%s", pwtmp);
286
	}
287
288
	snprintf(buf, sizeof(buf), "USERNAME %s\n", username);
289
290
	if (upscli_sendline(ups, buf, strlen(buf)) < 0) {
291
		fatalx(EXIT_FAILURE, "Can't set username: %s", upscli_strerror(ups));
292
	}
293
294
	ret = upscli_readline(ups, buf, sizeof(buf));
295
296
	if (ret < 0) {
297
		if (upscli_upserror(ups) != UPSCLI_ERR_UNKCOMMAND) {
298
			fatalx(EXIT_FAILURE, "Set username failed: %s", upscli_strerror(ups));
299
		}
300
301
		fatalx(EXIT_FAILURE,
302
			"Set username failed due to an unknown command.\n"
303
			"You probably need to upgrade upsd.");
304
	}
305
306
	snprintf(buf, sizeof(buf), "PASSWORD %s\n", password);
307
308
	if (upscli_sendline(ups, buf, strlen(buf)) < 0) {
309
		fatalx(EXIT_FAILURE, "Can't set password: %s", upscli_strerror(ups));
310
	}
311
312
	if (upscli_readline(ups, buf, sizeof(buf)) < 0) {
313
		fatalx(EXIT_FAILURE, "Set password failed: %s", upscli_strerror(ups));
314
	}
315
316
	do_cmd(&argv[1], argc - 1);
317
318
	exit(EXIT_SUCCESS);
319
}
320
321
322
/* Formal do_upsconf_args implementation to satisfy linker on AIX */
323
#if (defined NUT_PLATFORM_AIX)
324
void do_upsconf_args(char *upsname, char *var, char *val) {
325
        fatalx(EXIT_FAILURE, "INTERNAL ERROR: formal do_upsconf_args called");
326
}
327
#endif  /* end of #if (defined NUT_PLATFORM_AIX) */