xref: /illumos-gate/usr/src/cmd/vscan/vscanadm/vscanadm.c (revision 924db11bd45e384ed350190cc9fc0f9ea85e21dd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 
28 #include <stdio.h>
29 #include <strings.h>
30 #include <limits.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <arpa/inet.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <libintl.h>
41 #include <libvscan.h>
42 
43 
44 /* Property Names */
45 #define	VS_ADM_MAXSIZE		"max-size"
46 #define	VS_ADM_MAXSIZE_ACTION	"max-size-action"
47 #define	VS_ADM_TYPES		"types"
48 
49 /* Scan Engine Property Names */
50 #define	VS_ADM_SE_ENABLE	"enable"
51 #define	VS_ADM_SE_HOST		"host"
52 #define	VS_ADM_SE_PORT		"port"
53 #define	VS_ADM_SE_MAXCONN	"max-connection"
54 
55 /* Property Values */
56 #define	VS_ADM_ON		"on"
57 #define	VS_ADM_OFF		"off"
58 #define	VS_ADM_ALLOW		"allow"
59 #define	VS_ADM_DENY		"deny"
60 
61 
62 /*
63  * Print buffer length: used for sizing buffers that are filled with
64  * user-readable strings for property values. Define a number that
65  * accounts for some pre-value information, and won't (likely)
66  * wrap an 80-column display
67  */
68 #define	VS_ADM_PRINT_BUF_LEN	4096
69 
70 /* Program exit codes */
71 #define	VS_ADM_EXIT_SUCCESS	0
72 #define	VS_ADM_EXIT_ERROR	1
73 #define	VS_ADM_EXIT_USAGE	2
74 
75 
76 /*
77  * vscanadm property definition. Maps the property ids to a
78  * property name, and includes functions to convert to and from
79  * input strings and native data.
80  */
81 typedef struct vs_adm_property {
82 	const char *vap_name;
83 	uint64_t vap_id;
84 	int (*vap_parse)(const char *, void *);
85 	int (*vap_unparse)(const void *, char *, size_t);
86 } vs_adm_property_t;
87 
88 
89 /* usage/help information for subcommnds */
90 #define	VS_ADM_HELP_GET		("[-p property]...\n" \
91 	"\tdisplay vscan properties")
92 #define	VS_ADM_HELP_SET		("-p property=value [-p property=value]...\n" \
93 	"\tset values of vscan properties")
94 #define	VS_ADM_HELP_GET_ENG	("[-p property] [engine_id]\n" \
95 	"\tdisplay values of scan engine properties")
96 #define	VS_ADM_HELP_ADD_ENG	("[-p property=value]... engine_id\n" \
97 	"\tadd scan engine")
98 #define	VS_ADM_HELP_SET_ENG	("-p property=value [-p property=value]" \
99 	"... engine_id\n\tset values of scan engine properties")
100 #define	VS_ADM_HELP_REM_ENG	("engine_id\n" \
101 	"\tremove scan engine")
102 #define	VS_ADM_HELP_SHOW	("\n\tdisplay the values of all vscan " \
103 	"service and scan engine properties")
104 #define	VS_ADM_HELP_STATS	("[-z]\n\tdisplay vscan service statistics")
105 #define	VS_ADM_HELP_IMPORT	("-p property filename\n" \
106 	"\timport property from file")
107 #define	VS_ADM_HELP_EXPORT	("-p property filename\n" \
108 	"\texport property to file")
109 #define	VS_ADM_HELP_VALIDATE	("-p property filename\n" \
110 	"\tvalidate property in file")
111 
112 
113 /*
114  * vscanadm command structure. Encapsulates the vscanadm
115  * subcommand name, pointer to the subcommand implementation
116  * function, and a help id to get usage/help information.
117  */
118 typedef struct vs_adm_cmd {
119 	int (*vac_func)(int, char *[]);
120 	const char *vac_name;
121 	char *vac_helpid;
122 }
123 vs_adm_cmd_t;
124 
125 
126 /* Subcommand implementation functions */
127 static int vs_adm_set(int, char **);
128 static int vs_adm_get(int, char **);
129 static int vs_adm_set_engine(int, char **);
130 static int vs_adm_get_engine(int, char **);
131 static int vs_adm_rem_engine(int, char **);
132 static int vs_adm_show(int, char **);
133 static int vs_adm_stats(int, char **);
134 static int vs_adm_import(int, char **);
135 static int vs_adm_export(int, char **);
136 static int vs_adm_validate(int, char **);
137 
138 
139 /*
140  * Parse routines to transform libvscan API data into user-readable strings
141  */
142 static int vs_adm_parse_maxsize(const char *, void *);
143 static int vs_adm_parse_maxsize_action(const char *, void *);
144 static int vs_adm_parse_types(const char *, void *);
145 static int vs_adm_parse_enable(const char *, void *);
146 static int vs_adm_parse_host(const char *, void *);
147 static int vs_adm_parse_port(const char *, void *);
148 static int vs_adm_parse_maxconn(const char *, void *);
149 
150 
151 /*
152  * Unparse routines to transform strings from the user input into
153  * API native data.
154  *
155  * While some value validation is performed in the course of unparsing
156  * string data, complete value validation is left to libvscan.
157  * Values that are in unacceptable form, out of range, or otherwise
158  * violate rules for a given property will be rejected
159  */
160 static int vs_adm_unparse_maxsize(const void *, char *, size_t);
161 static int vs_adm_unparse_maxsize_action(const void *, char *, size_t);
162 static int vs_adm_unparse_types(const void *, char *, size_t);
163 static int vs_adm_unparse_enable(const void *, char *, size_t);
164 static int vs_adm_unparse_host(const void *, char *, size_t);
165 static int vs_adm_unparse_port(const void *, char *, size_t);
166 static int vs_adm_unparse_maxconn(const void *, char *, size_t);
167 
168 
169 /*
170  * The properties table includes a vscanadm property entry, specifying
171  * the property nane, property id, parse amd inparse methods,
172  * for each vscanadm property.
173  */
174 static const vs_adm_property_t vs_adm_props_all[] = {
175 	{ VS_ADM_MAXSIZE, VS_PROPID_MAXSIZE,
176 		vs_adm_parse_maxsize, vs_adm_unparse_maxsize },
177 	{ VS_ADM_MAXSIZE_ACTION, VS_PROPID_MAXSIZE_ACTION,
178 		vs_adm_parse_maxsize_action, vs_adm_unparse_maxsize_action },
179 	{ VS_ADM_TYPES, VS_PROPID_TYPES,
180 		vs_adm_parse_types, vs_adm_unparse_types },
181 	{ VS_ADM_SE_ENABLE, VS_PROPID_SE_ENABLE,
182 		vs_adm_parse_enable, vs_adm_unparse_enable },
183 	{ VS_ADM_SE_HOST, VS_PROPID_SE_HOST,
184 		vs_adm_parse_host, vs_adm_unparse_host },
185 	{ VS_ADM_SE_PORT, VS_PROPID_SE_PORT,
186 		vs_adm_parse_port, vs_adm_unparse_port },
187 	{ VS_ADM_SE_MAXCONN, VS_PROPID_SE_MAXCONN,
188 		vs_adm_parse_maxconn, vs_adm_unparse_maxconn },
189 	{ NULL, 0, NULL, NULL }
190 };
191 
192 
193 /*
194  * The subcommand table.  Used to find the subcommand specified
195  * by the user and dispatch the processing for the subcommand.
196  * Also used to display usage information for each subcommand.
197  */
198 static const vs_adm_cmd_t vs_adm_cmds[] =
199 {
200 	{ vs_adm_get, "get", VS_ADM_HELP_GET },
201 	{ vs_adm_set, "set", VS_ADM_HELP_SET },
202 	{ vs_adm_get_engine, "get-engine", VS_ADM_HELP_GET_ENG },
203 	{ vs_adm_set_engine, "set-engine", VS_ADM_HELP_SET_ENG },
204 	{ vs_adm_set_engine, "add-engine", VS_ADM_HELP_ADD_ENG },
205 	{ vs_adm_rem_engine, "remove-engine", VS_ADM_HELP_REM_ENG },
206 	{ vs_adm_import, "import", VS_ADM_HELP_IMPORT },
207 	{ vs_adm_export, "export", VS_ADM_HELP_EXPORT },
208 	{ vs_adm_validate, "validate", VS_ADM_HELP_VALIDATE },
209 	{ vs_adm_show, "show", VS_ADM_HELP_SHOW },
210 	{ vs_adm_stats, "stats", VS_ADM_HELP_STATS },
211 	{ NULL, NULL, NULL }
212 };
213 
214 
215 static const char *vs_adm_cmd;
216 static const char *vs_adm_subcmd;
217 
218 static int vs_adm_usage(FILE *);
219 static int vs_adm_props_from_input(int, char **, vs_props_t *, uint64_t *);
220 static void vs_adm_output_getcmd(uint64_t, const void *);
221 static void vs_adm_output_stats(vs_stats_t *);
222 static const vs_adm_property_t *vs_adm_prop_by_name(const char *);
223 static const vs_adm_property_t *vs_adm_prop_by_id(const uint64_t);
224 static int vs_adm_parse(const vs_adm_property_t *, const char *, void *);
225 static void vs_adm_unparse(const vs_adm_property_t *, const void *,
226     char *, size_t);
227 
228 static int vs_adm_file_read(char *, char *, int);
229 static int vs_adm_file_write(char *, char *);
230 static int vs_adm_file_usage(int argc, char **argv);
231 
232 /*
233  * main
234  */
235 int
236 main(int argc, char **argv)
237 {
238 	const vs_adm_cmd_t *cp;
239 	const char *p;
240 	int i, err;
241 
242 	/* executable and subcommand names */
243 	if ((p = strrchr(argv[0], '/')) == NULL)
244 		vs_adm_cmd = argv[0];
245 	else
246 		vs_adm_cmd = p + 1;
247 
248 	vs_adm_subcmd = argv[1];
249 
250 	/* require at least command and sub-command */
251 	if (argc < 2)
252 		return (vs_adm_usage(stdout));
253 
254 	/* Check for the "-?" help switch */
255 	for (i = 1; i < argc; i++) {
256 		if (strcmp(argv[i], "-?") == 0)
257 			return (vs_adm_usage(stdout));
258 	}
259 
260 	/* Locate the specified subcommand */
261 	for (cp = vs_adm_cmds; cp->vac_name != NULL; cp++) {
262 		if (strcmp(cp->vac_name, vs_adm_subcmd) == 0)
263 			break;
264 	}
265 
266 	if (cp->vac_name == NULL) {
267 		(void) fprintf(stderr, "%s: %s -- %s\n",
268 		    gettext("invalid subcommand"),
269 		    vs_adm_cmd, vs_adm_subcmd);
270 		return (vs_adm_usage(stderr));
271 	}
272 
273 	/* invoke sub-command handler */
274 	err = cp->vac_func(argc, argv);
275 
276 	return (err == VS_ADM_EXIT_USAGE ? vs_adm_usage(stderr) : err);
277 }
278 
279 
280 /*
281  * vs_adm_usage
282  */
283 static int
284 vs_adm_usage(FILE *fp)
285 {
286 	const vs_adm_cmd_t *cp;
287 
288 	for (cp = vs_adm_cmds; cp->vac_name != NULL; cp++) {
289 		(void) fprintf(fp, "%s %s", vs_adm_cmd, cp->vac_name);
290 		if (cp->vac_helpid != NULL)
291 			(void) fprintf(fp, " %s\n", cp->vac_helpid);
292 	}
293 
294 	return (VS_ADM_EXIT_USAGE);
295 }
296 
297 
298 /*
299  * vs_adm_get
300  *
301  * Gets and displays general vscan service configuration properties.
302  */
303 static int
304 vs_adm_get(int argc, char **argv)
305 {
306 	uint64_t propids;
307 	int i, rc;
308 	vs_props_t vp;
309 	const vs_adm_property_t *vap;
310 
311 	(void) memset(&vp, 0, sizeof (vp));
312 
313 	if (argc <= 2) {
314 		propids = VS_PROPID_GEN_ALL;
315 	} else {
316 		propids = 0LL;
317 		for (i = 2; i < argc; i++) {
318 			/* the "-p" specifier is optional */
319 			if (strcmp(argv[i], "-p") == 0) {
320 				if (++i >= argc)
321 					return (VS_ADM_EXIT_USAGE);
322 			}
323 
324 			if ((vap = vs_adm_prop_by_name(argv[i])) == NULL) {
325 				(void) fprintf(stderr, "%s '%s'\n",
326 				    gettext("invalid property"), argv[i]);
327 				return (VS_ADM_EXIT_ERROR);
328 			}
329 
330 			propids |= vap->vap_id;
331 		}
332 	}
333 
334 	rc = vs_props_get(&vp, propids);
335 	if (rc != VS_ERR_NONE) {
336 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
337 		return (VS_ADM_EXIT_ERROR);
338 	}
339 
340 	vs_adm_output_getcmd(propids, &vp);
341 
342 	return (VS_ADM_EXIT_SUCCESS);
343 }
344 
345 
346 /*
347  * vs_adm_set
348  *
349  * Sets values for general vscan service configuration properties
350  *
351  * Calls a common function used by the set, add, and remove
352  * subcommands to modify general property values.
353  */
354 static int
355 vs_adm_set(int argc, char **argv)
356 {
357 	vs_props_t vp;
358 	uint64_t propids;
359 	int rc;
360 
361 	if (argc < 3)
362 		return (VS_ADM_EXIT_USAGE);
363 
364 	rc = vs_adm_props_from_input(argc, argv, &vp, &propids);
365 	if (rc != VS_ADM_EXIT_SUCCESS)
366 		return (rc);
367 
368 	rc = vs_props_set(&vp, propids);
369 	if (rc != VS_ERR_NONE) {
370 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
371 		return (VS_ADM_EXIT_ERROR);
372 	}
373 
374 	return (VS_ADM_EXIT_SUCCESS);
375 }
376 
377 
378 /*
379  * vs_adm_get_engine
380  *
381  * Gets and displays scan engine configuration properties for
382  * one or more scan engines.
383  */
384 static int
385 vs_adm_get_engine(int argc, char **argv)
386 {
387 	int i, rc;
388 	uint64_t propids;
389 	char *engid = NULL;
390 	const vs_adm_property_t *vap;
391 	vs_props_all_t va;
392 
393 	propids = 0LL;
394 	for (i = 2; i < argc; i++) {
395 		/* if not preceded by -p, must be engine id and must be last */
396 		if (strcmp(argv[i], "-p") != 0) {
397 			if (i != (argc - 1))
398 				return (VS_ADM_EXIT_USAGE);
399 
400 			engid = argv[i];
401 			if (strlen(engid) > VS_SE_NAME_LEN) {
402 				(void) fprintf(stderr, "%s\n",
403 				    gettext("invalid scan engine"));
404 				return (VS_ADM_EXIT_ERROR);
405 			}
406 		} else {
407 			/* property should follow the -p */
408 			if (++i >= argc)
409 				return (VS_ADM_EXIT_USAGE);
410 
411 			if ((vap = vs_adm_prop_by_name(argv[i])) == NULL) {
412 				(void) fprintf(stderr, "%s '%s'\n",
413 				    gettext("invalid property"), argv[i]);
414 				return (VS_ADM_EXIT_ERROR);
415 			}
416 
417 			propids |= vap->vap_id;
418 		}
419 	}
420 
421 	if (propids == 0LL)
422 		propids = VS_PROPID_SE_ALL;
423 
424 	/* get properties for specified engine */
425 	if (engid) {
426 		rc = vs_props_se_get(engid, &va.va_se[0], propids);
427 		if (rc != VS_ERR_NONE) {
428 			(void) fprintf(stderr, "%s\n", vs_strerror(rc));
429 			return (VS_ADM_EXIT_ERROR);
430 		}
431 		vs_adm_output_getcmd(propids, &va.va_se[0]);
432 		return (VS_ADM_EXIT_SUCCESS);
433 	}
434 
435 	/* get properties for all engines */
436 	if ((rc = vs_props_get_all(&va)) != VS_ERR_NONE) {
437 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
438 		return (VS_ADM_EXIT_ERROR);
439 	}
440 
441 	for (i = 0; i < VS_SE_MAX; i++) {
442 		if (*(va.va_se[i].vep_engid) == 0)
443 			break;
444 		vs_adm_output_getcmd(propids, &va.va_se[i]);
445 	}
446 	if (i == 0) {
447 		(void) fprintf(stdout, "%s\n",
448 		    gettext("no scan engines configured"));
449 	}
450 
451 	return (VS_ADM_EXIT_SUCCESS);
452 }
453 
454 
455 /*
456  * vs_adm_set_engine
457  *
458  * Sets one or more scan engine configuration properties for a
459  * single scan engine.
460  */
461 static int
462 vs_adm_set_engine(int argc, char **argv)
463 {
464 	const vs_adm_property_t *vap;
465 	vs_props_se_t sep;
466 	char *val;
467 	uint64_t propids;
468 	int i, rc;
469 	char *engid;
470 	int add = (strcmp(vs_adm_subcmd, "add-engine") == 0) ? 1 : 0;
471 
472 
473 	if ((argc < 3) || ((!add) && (argc < 4)))
474 		return (VS_ADM_EXIT_USAGE);
475 
476 	/* Get the engine id */
477 	engid = argv[argc - 1];
478 	if (strchr(engid, '=') || strcmp(argv[argc - 2], "-p") == 0) {
479 		return (VS_ADM_EXIT_USAGE);
480 	}
481 
482 	if (strlen(engid) > VS_SE_NAME_LEN) {
483 		(void) fprintf(stderr, "%s\n",
484 		    gettext("invalid scan engine"));
485 		return (VS_ADM_EXIT_ERROR);
486 	}
487 
488 	propids = 0LL;
489 
490 	for (i = 2; i < (argc - 1); i++) {
491 		/* The "-p" is optional */
492 		if (strcmp(argv[i], "-p") == 0) {
493 			if (++i >= argc)
494 				return (VS_ADM_EXIT_USAGE);
495 		}
496 
497 		if ((val = strchr(argv[i], '=')) == NULL)
498 			return (VS_ADM_EXIT_USAGE);
499 
500 		*val = 0;
501 		val++;
502 
503 		/* Find the SE property pointer from the SE property name */
504 		if ((vap = vs_adm_prop_by_name(argv[i])) == NULL) {
505 			(void) fprintf(stderr, "%s '%s'\n",
506 			    gettext("invalid property"), argv[i]);
507 			return (VS_ADM_EXIT_ERROR);
508 		}
509 
510 		propids |= vap->vap_id;
511 
512 		if ((vs_adm_parse(vap, val, &sep)) != 0) {
513 			(void) fprintf(stderr, "%s '%s'\n",
514 			    gettext("invalid property value"), val);
515 			return (VS_ADM_EXIT_ERROR);
516 		}
517 	}
518 
519 	if (add)
520 		rc = vs_props_se_create(engid, &sep, propids);
521 	else
522 		rc = vs_props_se_set(engid, &sep, propids);
523 
524 	if (rc != VS_ERR_NONE) {
525 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
526 		return (VS_ADM_EXIT_ERROR);
527 	}
528 
529 	return (VS_ADM_EXIT_SUCCESS);
530 }
531 
532 
533 /*
534  * vs_adm_rem_engine
535  */
536 /* ARGSUSED */
537 static int
538 vs_adm_rem_engine(int argc, char **argv)
539 {
540 	int rc;
541 	char *engid;
542 
543 	if (argc != 3)
544 		return (VS_ADM_EXIT_USAGE);
545 
546 	engid = argv[2];
547 
548 	if (strlen(engid) > VS_SE_NAME_LEN) {
549 		(void) fprintf(stderr, "%s\n",
550 		    gettext("invalid scan engine"));
551 		return (VS_ADM_EXIT_ERROR);
552 	}
553 
554 	if ((rc = vs_props_se_delete(engid)) != VS_ERR_NONE) {
555 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
556 		return (rc);
557 	}
558 
559 	return (VS_ADM_EXIT_SUCCESS);
560 }
561 
562 
563 /*
564  * vs_adm_import
565  */
566 static int
567 vs_adm_import(int argc, char **argv)
568 {
569 	int rc;
570 	vs_props_t vp;
571 	uint64_t propids;
572 	char *filename;
573 
574 	if ((rc = vs_adm_file_usage(argc, argv)) != VS_ADM_EXIT_SUCCESS)
575 		return (rc);
576 
577 	filename = argv[argc - 1];
578 	rc = vs_adm_file_read(filename, vp.vp_types, sizeof (vp.vp_types));
579 	if (rc != VS_ADM_EXIT_SUCCESS)
580 		return (rc);
581 
582 	propids = VS_PROPID_TYPES;
583 	rc = vs_props_set(&vp, propids);
584 	if (rc != VS_ERR_NONE) {
585 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
586 		return (VS_ADM_EXIT_ERROR);
587 	}
588 
589 	return (VS_ADM_EXIT_SUCCESS);
590 }
591 
592 
593 /*
594  * vs_adm_validate
595  */
596 static int
597 vs_adm_validate(int argc, char **argv)
598 {
599 	int rc;
600 	vs_props_t vp;
601 	char *filename;
602 
603 	if ((rc = vs_adm_file_usage(argc, argv)) != VS_ADM_EXIT_SUCCESS)
604 		return (rc);
605 
606 	filename = argv[argc - 1];
607 	rc = vs_adm_file_read(filename, vp.vp_types, sizeof (vp.vp_types));
608 	if (rc != VS_ADM_EXIT_SUCCESS)
609 		return (rc);
610 
611 	if (vs_props_validate(&vp, VS_PROPID_TYPES) != VS_ERR_NONE) {
612 		(void) fprintf(stderr, "%s: %s\n", filename, vs_strerror(rc));
613 		return (VS_ADM_EXIT_ERROR);
614 	}
615 
616 	(void) fprintf(stdout, "%s: valid\n", filename);
617 	return (VS_ADM_EXIT_SUCCESS);
618 }
619 
620 
621 /*
622  * vs_adm_export
623  */
624 static int
625 vs_adm_export(int argc, char **argv)
626 {
627 	int rc;
628 	vs_props_t vp;
629 	uint64_t propids;
630 	char *filename;
631 
632 	if ((rc = vs_adm_file_usage(argc, argv)) != VS_ADM_EXIT_SUCCESS)
633 		return (rc);
634 
635 	filename = argv[argc - 1];
636 	(void) memset(&vp, 0, sizeof (vs_props_t));
637 	propids = VS_PROPID_TYPES;
638 	if ((rc = vs_props_get(&vp, propids)) != VS_ERR_NONE) {
639 		(void) fprintf(stderr, "%s: %s\n", filename, vs_strerror(rc));
640 		return (VS_ADM_EXIT_ERROR);
641 	}
642 
643 	rc = vs_adm_file_write(filename, vp.vp_types);
644 	if (rc != VS_ADM_EXIT_SUCCESS)
645 		return (rc);
646 
647 	return (VS_ADM_EXIT_SUCCESS);
648 }
649 
650 
651 /*
652  * vs_adm_file_usage
653  *
654  * import, export and validate - VS_PROPID_TYPES only
655  */
656 static int
657 vs_adm_file_usage(int argc, char **argv)
658 {
659 	const vs_adm_property_t *vap;
660 	char *prop;
661 
662 	if (argc < 4)
663 		return (VS_ADM_EXIT_USAGE);
664 
665 	/* -p optional */
666 	if (strcmp(argv[2], "-p") == 0) {
667 		if (argc != 5)
668 			return (VS_ADM_EXIT_USAGE);
669 	} else if (argc != 4)
670 		return (VS_ADM_EXIT_USAGE);
671 
672 	/* only VS_PROPID_TYPES supported */
673 	prop = argv[argc - 2];
674 	vap = vs_adm_prop_by_name(prop);
675 	if ((vap == NULL) || (vap->vap_id != VS_PROPID_TYPES)) {
676 		(void) fprintf(stderr, "%s '%s'\n",
677 		    gettext("invalid property"), prop);
678 		return (VS_ADM_EXIT_USAGE);
679 	}
680 
681 	return (VS_ADM_EXIT_SUCCESS);
682 }
683 
684 
685 /*
686  * vs_adm_file_read
687  */
688 static int
689 vs_adm_file_read(char *filename, char *buf, int len)
690 {
691 	FILE *fp;
692 
693 	if ((fp = fopen(filename, "r")) == NULL) {
694 		(void) fprintf(stderr, "%s: %s\n", filename,
695 		    vs_strerror(VS_ERR_SYS));
696 		return (VS_ADM_EXIT_ERROR);
697 	}
698 
699 	(void) memset(buf, 0, len);
700 	if (fgets(buf, len, fp) == NULL) {
701 		(void) fprintf(stderr, "%s: %s\n", filename,
702 		    gettext("invalid property value"));
703 		(void) fclose(fp);
704 		return (VS_ADM_EXIT_ERROR);
705 	}
706 
707 	(void) fclose(fp);
708 
709 	/* remove newline */
710 	if (buf[strlen(buf) - 1] == '\n')
711 		buf[strlen(buf) - 1] = '\0';
712 
713 	return (VS_ADM_EXIT_SUCCESS);
714 }
715 
716 
717 /*
718  * vs_adm_file_write
719  */
720 static int
721 vs_adm_file_write(char *filename, char *buf)
722 {
723 	FILE *fp;
724 	int bytes;
725 
726 	if ((fp = fopen(filename, "w")) == NULL) {
727 		(void) fprintf(stderr, "%s: %s\n", filename,
728 		    vs_strerror(VS_ERR_SYS));
729 		return (VS_ADM_EXIT_ERROR);
730 	}
731 
732 	bytes = fprintf(fp, "%s\n", buf);
733 	if ((bytes < 0) || (bytes != strlen(buf) + 1)) {
734 		(void) fprintf(stderr, "%s: %s\n", filename,
735 		    vs_strerror(VS_ERR_SYS));
736 		(void) fclose(fp);
737 		return (VS_ADM_EXIT_ERROR);
738 	}
739 
740 	(void) fclose(fp);
741 	return (VS_ADM_EXIT_SUCCESS);
742 }
743 
744 
745 /*
746  * vs_adm_show
747  *
748  * Gets and displays all general properties and all scan engine
749  * properties.
750  */
751 /* ARGSUSED */
752 static int
753 vs_adm_show(int argc, char **argv)
754 {
755 	if (argc > 2)
756 		return (VS_ADM_EXIT_USAGE);
757 
758 	(void) vs_adm_get(argc, argv);
759 	(void) vs_adm_get_engine(argc, argv);
760 
761 	return (VS_ADM_EXIT_SUCCESS);
762 }
763 
764 
765 /*
766  * vs_adm_stats
767  *
768  * Gets and displays vscan service statistics.
769  */
770 /* ARGSUSED */
771 static int
772 vs_adm_stats(int argc, char **argv)
773 {
774 	int rc;
775 	vs_stats_t stats;
776 
777 	/* get statistics */
778 	if (argc == 2) {
779 		if ((rc = vs_statistics(&stats)) == VS_ERR_NONE) {
780 			vs_adm_output_stats(&stats);
781 			return (VS_ADM_EXIT_SUCCESS);
782 		} else {
783 			(void) fprintf(stdout, "%s\n", vs_strerror(rc));
784 			return (VS_ADM_EXIT_ERROR);
785 		}
786 	}
787 
788 	/* reset statistics */
789 	if (argc == 3 && strcmp(argv[2], "-z") == 0) {
790 		if ((rc = vs_statistics_reset()) == VS_ERR_NONE) {
791 			return (VS_ADM_EXIT_SUCCESS);
792 		} else {
793 			(void) fprintf(stdout, "%s\n", vs_strerror(rc));
794 			return (VS_ADM_EXIT_ERROR);
795 		}
796 	}
797 
798 	/* usage error */
799 	return (vs_adm_usage(stdout));
800 }
801 
802 
803 /*
804  * vs_adm_output_stats
805  */
806 static void
807 vs_adm_output_stats(vs_stats_t *stats)
808 {
809 	int i;
810 	char *engid;
811 
812 	if (stats == NULL)
813 		return;
814 
815 	(void) fprintf(stdout, "scanned=%lld\n", stats->vss_scanned);
816 	(void) fprintf(stdout, "infected=%lld\n", stats->vss_infected);
817 	if (stats->vss_cleaned > 0)
818 		(void) printf("cleaned=%lld\n", stats->vss_cleaned);
819 	(void) fprintf(stdout, "failed=%lld\n", stats->vss_failed);
820 
821 	for (i = 0; i < VS_SE_MAX; i++) {
822 		engid = stats->vss_eng[i].vss_engid;
823 		if (*engid == 0)
824 			break;
825 		(void) fprintf(stdout, "%s:errors=%lld\n", engid,
826 		    stats->vss_eng[i].vss_errors);
827 	}
828 }
829 
830 
831 /*
832  * vs_adm_props_from_input
833  */
834 static int
835 vs_adm_props_from_input(int argc, char **argv, vs_props_t *vsprops,
836     uint64_t *propids)
837 {
838 	const vs_adm_property_t *vap;
839 	char *val;
840 	int i;
841 
842 	(void) memset(vsprops, 0, sizeof (vs_props_t));
843 
844 	*propids = 0LL;
845 	for (i = 2; i < argc; i++) {
846 		/* The "-p" is optional */
847 		if (strcmp(argv[i], "-p") == 0) {
848 			if (++i >= argc)
849 				return (VS_ADM_EXIT_USAGE);
850 		}
851 
852 		if ((val = strchr(argv[i], '=')) == NULL)
853 			return (VS_ADM_EXIT_USAGE);
854 
855 		/* Find the vscanadm property pointer from the property name */
856 		*val = '\0';
857 		val++;
858 		if ((vap = vs_adm_prop_by_name(argv[i])) == NULL) {
859 			(void) fprintf(stderr, "%s '%s'\n",
860 			    gettext("invalid property"), argv[i]);
861 			return (VS_ADM_EXIT_ERROR);
862 		}
863 
864 		/* Add in the property id and parse the property value */
865 		*propids |= vap->vap_id;
866 		if ((vs_adm_parse(vap, val, vsprops)) != 0) {
867 			(void) fprintf(stderr, "%s '%s'\n",
868 			    gettext("invalid property value"), val);
869 			return (VS_ADM_EXIT_ERROR);
870 		}
871 	}
872 
873 	return (VS_ADM_EXIT_SUCCESS);
874 }
875 
876 
877 /*
878  * vs_adm_output_getcmd
879  *
880  * Prints the results of a get command; both the get for general
881  * configuration properties as well as the get for an engine
882  * properties.
883  *
884  */
885 static void
886 vs_adm_output_getcmd(uint64_t propids, const void *props)
887 {
888 	char value[VS_ADM_PRINT_BUF_LEN];
889 	uint64_t propid;
890 	const vs_adm_property_t *vap;
891 	char *label = NULL;
892 
893 	if (VS_PROPID_IS_SE(propids))
894 		label = ((vs_props_se_t *)props)->vep_engid;
895 
896 	/*
897 	 * Unparse values from the property structure into readable strings
898 	 * and print them.
899 	 */
900 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
901 		if ((propids & propid) == 0)
902 			continue;
903 
904 		if ((vap = vs_adm_prop_by_id(propid)) == NULL)
905 			continue;
906 
907 		*value = '\0';
908 		vs_adm_unparse(vap, props, value, sizeof (value));
909 
910 		if (label)
911 			(void) fprintf(stdout, "%s:", label);
912 		(void) fprintf(stdout, "%s=%s\n", vap->vap_name, value);
913 	}
914 
915 	(void) fprintf(stdout, "\n");
916 }
917 
918 
919 /*
920  * vs_adm_prop_by_name
921  *
922  * Finds and returns a pointer to a vscan property structure from the
923  * property table by property name.
924  */
925 static const vs_adm_property_t *
926 vs_adm_prop_by_name(const char *propname)
927 {
928 	const vs_adm_property_t *p;
929 
930 	for (p = vs_adm_props_all; p->vap_name != NULL; p++) {
931 		if (strcmp(propname, p->vap_name) == 0)
932 			return (p);
933 	}
934 
935 	return (NULL);
936 }
937 
938 
939 /*
940  * vs_adm_prop_by_id
941  *
942  * Finds and returns a pointer to a vscan property structure from the
943  * property table by property name.
944  */
945 static const vs_adm_property_t *
946 vs_adm_prop_by_id(const uint64_t propid)
947 {
948 	const vs_adm_property_t *p;
949 
950 	for (p = vs_adm_props_all; p->vap_id != 0; p++) {
951 		if (propid == p->vap_id)
952 			return (p);
953 	}
954 
955 	return (NULL);
956 }
957 
958 
959 /*
960  * vs_adm_parse
961  *
962  * Entry point for parsing the user input strings into a data structure
963  * used for setting values. Dispatches the actual parsing to the parse
964  * routine for the specified vscanadm property.
965  *
966  * This function is used to dispatch parsing for values supplied by the
967  * user for all subcommands; both the general configuration as well as
968  * scan engine configuration. The structure pointer is therefore typed
969  * as a void pointer, and cast appropriately in the parse routine for
970  * the vscanadm property.
971  */
972 static int
973 vs_adm_parse(const vs_adm_property_t *vap, const char *valvap_name,
974 	void *vp)
975 {
976 	return ((vap->vap_parse)(valvap_name, vp));
977 }
978 
979 
980 /*
981  * vs_adm_parse_maxsize
982  *
983  * Parses a user-supplied string into a maxsize (decimal) value for
984  * the general vscan configuration properties.
985  */
986 static int
987 vs_adm_parse_maxsize(const char *valstr, void *vp)
988 {
989 	vs_props_t *svcp = vp;
990 
991 	uint64_t maxsize;
992 	char *end;
993 
994 	errno = 0;
995 	maxsize = strtoll(valstr, &end, 10);
996 	if (errno != 0)
997 		return (-1);
998 	(void) snprintf(svcp->vp_maxsize, sizeof (svcp->vp_maxsize),
999 	    "%llu%s", maxsize, end);
1000 
1001 	return (0);
1002 }
1003 
1004 
1005 /*
1006  * vs_adm_parse_maxsize_action
1007  *
1008  * Parses a user-supplied string into a maxsize action value for the
1009  * general vscan configuration properties.
1010  *
1011  * Returns: 0 success
1012  *         -1 failure
1013  */
1014 static int
1015 vs_adm_parse_maxsize_action(const char *valstr, void *vp)
1016 {
1017 	vs_props_t *svcp = vp;
1018 
1019 	if (strcmp(valstr, VS_ADM_ALLOW) == 0) {
1020 		svcp->vp_maxsize_action = B_TRUE;
1021 		return (0);
1022 	}
1023 
1024 	if (strcmp(valstr, VS_ADM_DENY) == 0) {
1025 		svcp->vp_maxsize_action = B_FALSE;
1026 		return (0);
1027 	}
1028 
1029 	return (-1);
1030 }
1031 
1032 
1033 /*
1034  * vs_adm_parse_types
1035  *
1036  * Returns: 0 success
1037  *         -1 on failure.
1038  */
1039 static int
1040 vs_adm_parse_types(const char *valstr, void *vp)
1041 {
1042 	vs_props_t *svcp = vp;
1043 
1044 	if (strlen(valstr) >= sizeof (svcp->vp_types))
1045 		return (-1);
1046 
1047 	if (strlcpy(svcp->vp_types, valstr, sizeof (svcp->vp_types))
1048 	    >= sizeof (svcp->vp_types))
1049 		return (-1);
1050 
1051 	return (0);
1052 }
1053 
1054 
1055 /*
1056  * vs_adm_parse_enable
1057  *
1058  * Parses a user-supplied string into an enable value for the
1059  * properties of a scan engine.
1060  *
1061  * Returns: 0 success
1062  *         -1 on failure.
1063  */
1064 static int
1065 vs_adm_parse_enable(const char *valstr, void *vp)
1066 {
1067 	vs_props_se_t *sep = vp;
1068 
1069 	if (strcmp(valstr, VS_ADM_ON) == 0) {
1070 		sep->vep_enable = B_TRUE;
1071 		return (0);
1072 	}
1073 
1074 	if (strcmp(valstr, VS_ADM_OFF) == 0) {
1075 		sep->vep_enable = B_FALSE;
1076 		return (0);
1077 	}
1078 
1079 	return (-1);
1080 }
1081 
1082 
1083 /*
1084  * vs_adm_parse_host
1085  *
1086  * Parses a user-supplied string into an ip address value for the
1087  * properties of a scan engine.
1088  */
1089 static int
1090 vs_adm_parse_host(const char *valstr, void *vp)
1091 {
1092 	vs_props_se_t *sep = vp;
1093 
1094 	if (strlen(valstr) >= sizeof (sep->vep_host))
1095 		return (-1);
1096 
1097 	if (strlcpy(sep->vep_host, valstr, sizeof (sep->vep_host)) >=
1098 	    sizeof (sep->vep_host))
1099 		return (-1);
1100 
1101 	return (0);
1102 }
1103 
1104 
1105 /*
1106  * vs_adm_parse_port
1107  *
1108  * Parses a user-supplied string into a port value for the properties of
1109  * a scan engine. The port is an unsigned short int, but the conversion
1110  * must be done on a word-sized int. Casting the converted int into the
1111  * port member of the property structure can result in a valid but
1112  * unintended value, so the range is checked first for validity.
1113  *
1114  * Returns: 0 success
1115  *         -1 on failure.
1116  */
1117 static int
1118 vs_adm_parse_port(const char *valstr, void *vp)
1119 {
1120 	vs_props_se_t *sep = vp;
1121 	unsigned long port;
1122 	char *end;
1123 
1124 	end = 0;
1125 	port = strtoul(valstr, &end, 0);
1126 	if (port > UINT16_MAX || (end < (valstr + strlen(valstr))))
1127 		return (-1);
1128 
1129 	sep->vep_port = port;
1130 
1131 	return (0);
1132 }
1133 
1134 
1135 /*
1136  * vs_adm_parse_maxconn
1137  *
1138  * Parses a user-supplied string into a max connections (decimal) value
1139  * for the properties of a scan engine.
1140  *
1141  * Returns: 0 success
1142  *         -1 on failure.
1143  */
1144 static int
1145 vs_adm_parse_maxconn(const char *valstr, void *vp)
1146 {
1147 	vs_props_se_t *sep = vp;
1148 	char *end;
1149 
1150 	sep->vep_maxconn = strtoll(valstr, &end, 10);
1151 	if (end < valstr + strlen(valstr))
1152 		return (-1);
1153 
1154 	return (0);
1155 }
1156 
1157 
1158 /*
1159  * vs_adm_unparse
1160  *
1161  * Entry point for unparsing native data into a readable string
1162  * used for display to the user. Dispatches the actual unparsing to
1163  * the unparse routine for the specified vscanadm property.
1164  *
1165  * This function is used to dispatch unparsing for all subcommands.
1166  * The structure pointer is therefore typed as a void pointer, and
1167  * cast appropriately in the unparse routine for the vscanadm property.
1168  */
1169 static void
1170 vs_adm_unparse(const vs_adm_property_t *vap, const void *vp,
1171 	char *buf, size_t len)
1172 {
1173 	if ((vap->vap_unparse)(vp, buf, len) != 0)
1174 		(void) snprintf(buf, len, gettext(" (error) "));
1175 }
1176 
1177 
1178 /*
1179  *  vs_adm_unparse_maxsize
1180  *
1181  * Unparses a max fsize value in native data form into a
1182  * user-readable string.
1183  */
1184 /* ARGSUSED */
1185 static int
1186 vs_adm_unparse_maxsize(const void *vp, char *buf, size_t len)
1187 {
1188 	const vs_props_t *svcp = vp;
1189 
1190 	(void) snprintf(buf, len, "%s", svcp->vp_maxsize);
1191 
1192 	return (0);
1193 }
1194 
1195 
1196 /*
1197  * vs_adm_unparse_maxsize_action
1198  *
1199  * Unparses a max fsize action value in native data form into a
1200  * user-readable string.
1201  */
1202 /* ARGSUSED */
1203 static int
1204 vs_adm_unparse_maxsize_action(const void *vp, char *buf, size_t len)
1205 {
1206 	const vs_props_t *svcp = vp;
1207 
1208 	(void) snprintf(buf, len, "%s",
1209 	    svcp->vp_maxsize_action ?  VS_ADM_ALLOW : VS_ADM_DENY);
1210 
1211 	return (0);
1212 }
1213 
1214 
1215 /*
1216  * vs_adm_unparse_types
1217  *
1218  * Returns: 0 success
1219  *         -1 on failure.
1220  */
1221 static int
1222 vs_adm_unparse_types(const void *vp, char *buf, size_t len)
1223 {
1224 	const vs_props_t *svcp = vp;
1225 
1226 	(void) strlcpy(buf, svcp->vp_types, len);
1227 
1228 	return (0);
1229 }
1230 
1231 
1232 /*
1233  * vs_adm_unparse_enable
1234  *
1235  * Unparses the enable value for a scan engine in native data
1236  * form into a user-readable string.
1237  */
1238 /* ARGSUSED */
1239 static int
1240 vs_adm_unparse_enable(const void *vp, char *buf, size_t len)
1241 {
1242 	const vs_props_se_t *sep = vp;
1243 
1244 	(void) snprintf(buf, len, "%s",
1245 	    sep->vep_enable ?  VS_ADM_ON : VS_ADM_OFF);
1246 
1247 	return (0);
1248 }
1249 
1250 
1251 /*
1252  * vs_adm_unparse_host
1253  *
1254  * Unparses an ip address for a scan engine in native data
1255  * form into a user-readable string.
1256  *
1257  * Returns: 0 success
1258  *         -1 on failure.
1259  */
1260 /* ARGSUSED */
1261 static int
1262 vs_adm_unparse_host(const void *vp, char *buf, size_t len)
1263 {
1264 	const vs_props_se_t *sep = vp;
1265 
1266 	(void) strlcpy(buf, sep->vep_host, len);
1267 
1268 	return (0);
1269 }
1270 
1271 
1272 /*
1273  * vs_adm_unparse_port
1274  *
1275  * Unparses a port value for a scan engine in native data
1276  * form into a user-readable string.
1277  */
1278 /* ARGSUSED */
1279 static int
1280 vs_adm_unparse_port(const void *vp, char *buf, size_t len)
1281 {
1282 	const vs_props_se_t *sep = vp;
1283 
1284 	(void) snprintf(buf, len, "%hu", sep->vep_port);
1285 
1286 	return (0);
1287 }
1288 
1289 
1290 /*
1291  * vs_adm_unparse_maxconn
1292  *
1293  * Unparses a max connecctions for a scan engine in native data
1294  * form into a user-readable string.
1295  *
1296  */
1297 /* ARGSUSED */
1298 static int
1299 vs_adm_unparse_maxconn(const void *vp, char *buf, size_t len)
1300 {
1301 	const vs_props_se_t *sep = vp;
1302 
1303 	(void) snprintf(buf, len, "%lld", sep->vep_maxconn);
1304 
1305 	return (0);
1306 }
1307