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