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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <sys/stat.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <ctype.h> 32 #include <locale.h> 33 34 #define MAXLINELEN 4096 35 36 /* 37 * Usage: 38 * sonconfig -f <file> 39 * Reads input from file. The file is structured as 40 * <fam> <type> <protocol> <path|module> 41 * <fam> <type> <protocol> 42 * with the first line registering and the second line 43 * deregistering. 44 * 45 * soconfig <fam> <type> <protocol> <path|module> 46 * registers 47 * 48 * soconfig <fam> <type> <protocol> 49 * deregisters 50 */ 51 52 static int parse_file(char *filename); 53 54 static int split_line(char *line, char *argvec[], int maxargvec); 55 56 static int parse_params(char *famstr, char *typestr, char *protostr, 57 char *path, int line); 58 59 static int parse_int(char *str); 60 61 static void usage(void); 62 63 int 64 main(argc, argv) 65 int argc; 66 char *argv[]; 67 { 68 int ret; 69 70 argc--; argv++; 71 72 (void) setlocale(LC_ALL, ""); 73 #if !defined(TEXT_DOMAIN) 74 #define TEXT_DOMAIN "SYS_TEST" 75 #endif 76 (void) textdomain(TEXT_DOMAIN); 77 78 if (argc == 2 && strcmp(argv[0], "-f") == 0) { 79 ret = parse_file(argv[1]); 80 exit(ret); 81 } 82 if (argc == 3) { 83 ret = parse_params(argv[0], argv[1], argv[2], NULL, -1); 84 exit(ret); 85 } 86 if (argc == 4) { 87 ret = parse_params(argv[0], argv[1], argv[2], argv[3], -1); 88 exit(ret); 89 } 90 usage(); 91 exit(1); 92 /* NOTREACHED */ 93 } 94 95 static void 96 usage(void) 97 { 98 fprintf(stderr, gettext( 99 "Usage: soconfig -f <file>\n" 100 "\tsoconfig <fam> <type> <protocol> <path|module>\n" 101 "\tsoconfig <fam> <type> <protocol>\n")); 102 } 103 104 /* 105 * Open the specified file and parse each line. Skip comments (everything 106 * after a '#'). Return 1 if at least one error was encountered; otherwise 0. 107 */ 108 static int 109 parse_file(char *filename) 110 { 111 char line[MAXLINELEN]; 112 char pline[MAXLINELEN]; 113 int argcount; 114 char *argvec[20]; 115 FILE *fp; 116 int linecount = 0; 117 int numerror = 0; 118 119 fp = fopen(filename, "r"); 120 if (fp == NULL) { 121 perror("soconfig: open"); 122 fprintf(stderr, "\n"); 123 usage(); 124 return (1); 125 } 126 127 while (fgets(line, sizeof (line) - 1, fp) != NULL) { 128 linecount++; 129 strcpy(pline, line); 130 argcount = split_line(pline, argvec, 131 sizeof (argvec) / sizeof (argvec[0])); 132 #ifdef DEBUG 133 { 134 int i; 135 136 printf("scanned %d args\n", argcount); 137 for (i = 0; i < argcount; i++) 138 printf("arg[%d]: %s\n", i, argvec[i]); 139 } 140 #endif /* DEBUG */ 141 switch (argcount) { 142 case 0: 143 /* Empty line - or comment only line */ 144 break; 145 case 3: 146 numerror += parse_params(argvec[0], argvec[1], 147 argvec[2], NULL, linecount); 148 break; 149 case 4: 150 numerror += parse_params(argvec[0], argvec[1], 151 argvec[2], argvec[3], linecount); 152 break; 153 default: 154 numerror++; 155 fprintf(stderr, 156 gettext("Malformed line: <%s>\n"), line); 157 fprintf(stderr, 158 gettext("\ton line %d\n"), linecount); 159 break; 160 } 161 } 162 (void) fclose(fp); 163 164 if (numerror > 0) 165 return (1); 166 else 167 return (0); 168 } 169 170 /* 171 * Parse a line splitting it off at whitspace characters. 172 * Modifies the content of the string by inserting NULLs. 173 */ 174 static int 175 split_line(char *line, char *argvec[], int maxargvec) 176 { 177 int i = 0; 178 char *cp; 179 180 /* Truncate at the beginning of a comment */ 181 cp = strchr(line, '#'); 182 if (cp != NULL) 183 *cp = NULL; 184 185 /* CONSTCOND */ 186 while (1) { 187 /* Skip any whitespace */ 188 while (isspace(*line) && *line != NULL) 189 line++; 190 191 if (i >= maxargvec) 192 return (i); 193 194 argvec[i] = line; 195 if (*line == NULL) 196 return (i); 197 i++; 198 /* Skip until next whitespace */ 199 while (!isspace(*line) && *line != NULL) 200 line++; 201 if (*line != NULL) { 202 /* Break off argument */ 203 *line++ = NULL; 204 } 205 } 206 /* NOTREACHED */ 207 } 208 209 /* 210 * Parse the set of parameters and issues the sockconfig syscall. 211 * If line is not -1 it is assumed to be the line number in the file. 212 */ 213 static int 214 parse_params(char *famstr, char *typestr, char *protostr, char *path, int line) 215 { 216 int fam, type, protocol; 217 218 fam = parse_int(famstr); 219 if (fam == -1) { 220 fprintf(stderr, gettext("Bad family number: %s\n"), famstr); 221 if (line != -1) 222 fprintf(stderr, 223 gettext("\ton line %d\n"), line); 224 else { 225 fprintf(stderr, "\n"); 226 usage(); 227 } 228 return (1); 229 } 230 231 type = parse_int(typestr); 232 if (type == -1) { 233 fprintf(stderr, 234 gettext("Bad socket type number: %s\n"), typestr); 235 if (line != -1) 236 fprintf(stderr, 237 gettext("\ton line %d\n"), line); 238 else { 239 fprintf(stderr, "\n"); 240 usage(); 241 } 242 return (1); 243 } 244 245 protocol = parse_int(protostr); 246 if (protocol == -1) { 247 fprintf(stderr, 248 gettext("Bad protocol number: %s\n"), protostr); 249 if (line != -1) 250 fprintf(stderr, 251 gettext("\ton line %d\n"), line); 252 else { 253 fprintf(stderr, "\n"); 254 usage(); 255 } 256 return (1); 257 } 258 259 260 if (path != NULL) { 261 struct stat stats; 262 263 if (strncmp(path, "/dev", strlen("/dev")) == 0 && 264 stat(path, &stats) == -1) { 265 perror(path); 266 if (line != -1) 267 fprintf(stderr, 268 gettext("\ton line %d\n"), line); 269 else { 270 fprintf(stderr, "\n"); 271 usage(); 272 } 273 return (1); 274 } 275 } 276 277 #ifdef DEBUG 278 printf("not calling sockconfig(%d, %d, %d, %s)\n", 279 fam, type, protocol, path == NULL ? "(null)" : path); 280 #else 281 if (_sockconfig(fam, type, protocol, path) == -1) { 282 perror("sockconfig"); 283 return (1); 284 } 285 #endif 286 return (0); 287 } 288 289 static int 290 parse_int(char *str) 291 { 292 char *end; 293 int res; 294 295 res = strtol(str, &end, 0); 296 if (end == str) 297 return (-1); 298 return (res); 299 } 300