diff options
Diffstat (limited to 'usr/src/common/definit/definit.c')
| -rw-r--r-- | usr/src/common/definit/definit.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/usr/src/common/definit/definit.c b/usr/src/common/definit/definit.c new file mode 100644 index 0000000000..56d77f871d --- /dev/null +++ b/usr/src/common/definit/definit.c @@ -0,0 +1,188 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <definit.h> + +/* Tokens are separated by spaces, tabs and newlines. */ +#define SEPARATORS " \t\n" + +typedef struct definit { + FILE *di_fp; + char *di_line; + char *di_tok; +} definit_t; + +int +definit_open(const char *file, void **statep) +{ + FILE *fp; + int _errno; + definit_t *state = NULL; + + if ((fp = fopen(file, "r")) == NULL) + return (-1); + + if ((state = calloc(1, sizeof (*state))) == NULL) + goto err; + + if ((state->di_line = calloc(DEFINIT_MAXLINE, sizeof (char))) == NULL) + goto err; + + state->di_fp = fp; + *statep = state; + + return (0); + +err: + _errno = errno; + (void) fclose(fp); + if (state != NULL) { + free(state->di_line); + free(state); + } + errno = _errno; + return (-1); +} + +void +definit_close(void *statep) +{ + definit_t *state = statep; + + (void) fclose(state->di_fp); + free(state->di_line); + free(state); +} + +/* + * This parser was written to produce the same output as the ones it replaced + * in init and svc.startd. As such it has some shortcomings: + * - Values may be quoted but the quotes are just stripped and separators such + * as whitespace are not treated specially within quotes; + * - Lines which are longer than DEFINIT_MAXLINE -1 bytes are split. Tokens + * which span a split will be truncated, one way or another. + * - Comments at the end of a line (after a token) are not supported. + * These could be corrected in the future if strict backwards compatibility is + * not required. + */ + +static char * +definit_nextline(definit_t *state) +{ + char *line; + + while ((line = fgets(state->di_line, DEFINIT_MAXLINE, state->di_fp)) + != NULL) { + boolean_t inquotes; + char *p, *bp; + size_t wslength; + + /* + * Ignore blank or comment lines. + */ + if (line[0] == '#' || line[0] == '\0' || + (wslength = strspn(line, SEPARATORS)) == strlen(line) || + line[wslength] == '#') { + continue; + } + + /* + * Make a pass through the line and: + * - Replace any non-quoted semicolons with spaces; + * - Remove any quote characters. + * + * While walking this, 'p' is the current position in the line + * and, if any characters have been found which need to be + * removed, 'bp' tracks the position in the line where + * subsequent characters need to be written in order to close + * the gap; 'bp' trails 'p'. + * If 'bp' is NULL, no characters to remove have been found. + */ + inquotes = B_FALSE; + for (p = line, bp = NULL; *p != '\0'; p++) { + switch (*p) { + case '"': + case '\'': + inquotes = !inquotes; + if (bp == NULL) + bp = p; + break; + case ';': + if (!inquotes) + *p = ' '; + /* FALLTHROUGH */ + default: + if (bp != NULL) + *bp++ = *p; + break; + } + } + if (bp != NULL) + *bp = '\0'; + + /* + * Perform an initial strtok_r() call on the new line. + * definit_token() will repeatedly call strtok_r() until the + * line is consumed, and then call this function again for + * more input. + */ + if ((p = strtok_r(line, SEPARATORS, &state->di_tok)) != NULL) + return (p); + } + + return (NULL); +} + +const char * +definit_token(void *statep) +{ + definit_t *state = statep; + char *tok; + + for (;;) { + tok = NULL; + + if (state->di_tok != NULL) + tok = strtok_r(NULL, SEPARATORS, &state->di_tok); + + if (tok == NULL) + tok = definit_nextline(state); + + if (tok == NULL) + break; + + if (strchr(tok, '=') != NULL && *tok != '=') + return (tok); + } + + return (NULL); +} |
