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 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <sys/wait.h>
28
29 #include <unistd.h>
30 #include <signal.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <errno.h>
35
36 #include "conf.h"
37
38 #define CF_DEFSIZE 32 /* Starting table size */
39 #define CF_GROW 2 /* Table size multiplier on grow */
40
41 static FILE *
open_conf_pipe(const char * cmd,char * argv[],pid_t * pidp)42 open_conf_pipe(const char *cmd, char *argv[], pid_t *pidp)
43 {
44 int pfds[2];
45 pid_t pid;
46 struct sigaction act;
47
48 /* Create a pipe and fork a child process to run the command */
49
50 if (pipe(pfds) == -1) {
51 logerror("failed to create pipe");
52 return (NULL);
53 }
54
55 if ((pid = fork1()) == -1) {
56 logerror("failed to fork1");
57 goto err;
58 }
59
60 /* If we're in the child, run the command and output to the pipe */
61
62 if (pid == 0) {
63 /*
64 * We must set up to ignore these signals, which may be
65 * propogated from the calling process.
66 */
67
68 act.sa_handler = SIG_IGN;
69
70 (void) sigaction(SIGHUP, &act, NULL);
71 (void) sigaction(SIGALRM, &act, NULL);
72 (void) sigaction(SIGUSR1, &act, NULL);
73
74 (void) close(pfds[0]);
75 (void) close(STDOUT_FILENO);
76
77 if (dup2(pfds[1], STDOUT_FILENO) == -1) {
78 logerror("failed to dup to stdout");
79 (void) close(pfds[1]);
80 _exit(127);
81 }
82
83 (void) execvp(cmd, argv);
84 logerror("failed to parse configuration file");
85 _exit(127);
86 /*NOTREACHED*/
87 }
88
89 /* If we're in the parent, open the read end of the pipe and return */
90
91 *pidp = pid;
92 (void) close(pfds[1]);
93 return (fdopen(pfds[0], "r"));
94
95 err:
96 (void) close(pfds[0]);
97 (void) close(pfds[1]);
98 return (NULL);
99 }
100
101 static void
close_conf_pipe(FILE * fp,pid_t pid)102 close_conf_pipe(FILE *fp, pid_t pid)
103 {
104 int status;
105
106 while (waitpid(pid, &status, 0) == -1) {
107 if (errno != EINTR)
108 break;
109 }
110
111 (void) fclose(fp);
112 }
113
114 static int
grow_conf_file(conf_t * cf)115 grow_conf_file(conf_t *cf)
116 {
117 int ndsize = cf->cf_dsize ? cf->cf_dsize * CF_GROW : CF_DEFSIZE;
118 void *ndtab = realloc(cf->cf_dtab, sizeof (char *) * ndsize);
119
120 register char *p;
121 int odsize, lines, i;
122
123 if (ndtab == NULL) {
124 logerror("failed to allocate config file table");
125 return (-1);
126 }
127
128 lines = ndsize - cf->cf_dsize;
129 odsize = cf->cf_dsize;
130
131 cf->cf_dtab = (char **)ndtab;
132 cf->cf_dsize = ndsize;
133
134 for (i = 0; i < lines; i++) {
135 if ((p = (char *)malloc(BUFSIZ)) == NULL) {
136 logerror("failed to allocate config file buffer");
137 return (-1);
138 }
139
140 cf->cf_dtab[odsize + i] = p;
141 }
142
143 return (0);
144 }
145
146 int
conf_open(conf_t * cf,const char * cmd,char * argv[])147 conf_open(conf_t *cf, const char *cmd, char *argv[])
148 {
149 char *line, *p;
150 pid_t pid;
151 FILE *fp;
152
153 (void) memset(cf, 0, sizeof (conf_t));
154
155 if ((fp = open_conf_pipe(cmd, argv, &pid)) == NULL)
156 return (-1);
157
158 for (;;) {
159 /* If we need to grow the table, do so now */
160
161 if (cf->cf_lines >= cf->cf_dsize) {
162 if (grow_conf_file(cf) == -1)
163 goto err;
164 }
165
166 line = cf->cf_dtab[cf->cf_lines];
167
168 /* Read the next line, and break out if we're done */
169
170 if (fgets(line, BUFSIZ, fp) == NULL)
171 break;
172
173 /* Strip newline and bump line counter */
174
175 if ((p = strchr(line, '\n')) != NULL)
176 *p = '\0';
177
178 cf->cf_lines++;
179 }
180
181 close_conf_pipe(fp, pid);
182 return (0);
183
184 err:
185 close_conf_pipe(fp, pid);
186 return (-1);
187 }
188
189 void
conf_rewind(conf_t * cf)190 conf_rewind(conf_t *cf)
191 {
192 cf->cf_ptr = 0;
193 }
194
195 char *
conf_read(conf_t * cf)196 conf_read(conf_t *cf)
197 {
198 if (cf->cf_ptr < cf->cf_lines)
199 return (cf->cf_dtab[cf->cf_ptr++]);
200
201 return (NULL);
202 }
203
204 void
conf_close(conf_t * cf)205 conf_close(conf_t *cf)
206 {
207 int i;
208
209 if (cf->cf_dtab != NULL) {
210 for (i = 0; i < cf->cf_dsize; i++)
211 free(cf->cf_dtab[i]);
212 free(cf->cf_dtab);
213 }
214 }
215