summaryrefslogtreecommitdiff
path: root/usr/src/common/definit/definit.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/common/definit/definit.c')
-rw-r--r--usr/src/common/definit/definit.c188
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);
+}