No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / iscsi / dist / src / lib / conffile.c
blob05028e5b4b4f81d3b35c8604e2f91271934ddf0a
1 /* $NetBSD: conffile.c,v 1.7 2009/01/25 14:25:27 lukem Exp $ */
3 /*
4 * Copyright © 2006 Alistair Crooks. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
42 #include "conffile.h"
44 /* start of split routines */
46 /* open a file */
47 int
48 conffile_open(conffile_t *sp, const char *f, const char *mode, const char *sep, const char *comment)
50 (void) memset(sp, 0x0, sizeof(*sp));
51 if ((sp->fp = fopen(f, mode)) == NULL) {
52 (void) fprintf(stderr, "can't open `%s' `%s' (%s)\n", f, mode, strerror(errno));
53 return 0;
55 (void) strlcpy(sp->name, f, sizeof(sp->name));
56 sp->sep = sep;
57 sp->comment = comment;
58 sp->readonly = (strcmp(mode, "r") == 0);
59 return 1;
62 /* close a file */
63 void
64 conffile_close(conffile_t *sp)
66 (void) fclose(sp->fp);
69 /* read the next line from the file */
70 static char *
71 read_line(conffile_t *sp, ent_t *ep)
73 char *from;
75 if (fgets(ep->buf, sizeof(ep->buf), sp->fp) == NULL) {
76 return NULL;
78 sp->lineno += 1;
79 for (from = ep->buf ; *from && isspace((unsigned int)*from) ; from++) {
81 return from;
84 /* return 1 if this line contains no entry */
85 static int
86 iscomment(conffile_t *sp, char *from)
88 return (*from == 0x0 || *from == '\n' || strchr(sp->comment, *from) != NULL);
91 /* split the entry up into fields */
92 int
93 conffile_split(conffile_t *sp, ent_t *ep, char *from)
95 FILE *fp;
96 const char *seps;
97 char *to;
98 char was;
99 int sepseen;
100 int cc;
102 seps = (sp == NULL) ? " \t" : sp->sep;
103 fp = (sp == NULL) ? stdin : sp->fp;
104 for (ep->sv.c = 0 ; *from && *from != '\n' ; ) {
105 for (to = from, sepseen = 0 ; *to && *to != '\n' && strchr(seps, *to) == NULL ; to++) {
106 if (*to == '\\') {
107 if (*(to + 1) == '\n') {
108 cc = (int)(to - ep->buf);
109 if (fgets(&ep->buf[cc], (int)(sizeof(ep->buf) - cc), fp) != NULL) {
110 if (sp != NULL) {
111 sp->lineno += 1;
114 } else {
115 sepseen = 1;
116 to++;
120 ALLOC(char *, ep->sv.v, ep->sv.size, ep->sv.c, 14, 14, "conffile_getent", exit(EXIT_FAILURE));
121 ep->sv.v[ep->sv.c++] = from;
122 was = *to;
123 *to = 0x0;
124 if (sepseen) {
125 char *cp;
127 for (cp = from ; *cp ; cp++) {
128 if (strchr(seps, *cp) != NULL) {
129 (void) strcpy(cp - 1, cp);
133 if (was == 0x0 || was == '\n') {
134 break;
136 for (from = to + 1 ; *from && *from != '\n' && strchr(seps, *from) != NULL ; from++) {
139 return 1;
142 /* get the next entry */
144 conffile_getent(conffile_t *sp, ent_t *ep)
146 char *from;
148 for (;;) {
149 if ((from = read_line(sp, ep)) == NULL) {
150 return 0;
152 if (iscomment(sp, from)) {
153 continue;
155 return conffile_split(sp, ep, from);
159 /* return the line number */
161 conffile_get_lineno(conffile_t *sp)
163 return sp->lineno;
166 /* return the name */
167 char *
168 conffile_get_name(conffile_t *sp)
170 return sp->name;
173 /* return the entry based upon the contents of field `f' */
175 conffile_get_by_field(conffile_t *sp, ent_t *ep, int f, char *val)
177 while (conffile_getent(sp, ep)) {
178 if (ep->sv.c > (uint32_t)f && strcmp(ep->sv.v[f], val) == 0) {
179 return 1;
182 return 0;
185 /* check that we wrote `cc' chars of `buf' to `fp' */
186 static int
187 safe_write(FILE *fp, char *buf, unsigned cc)
189 return fwrite(buf, sizeof(char), cc, fp) == cc;
192 #if 0
193 /* check that we wrote the entry correctly */
194 static int
195 safe_write_ent(FILE *fp, conffile_t *sp, ent_t *ep)
197 char buf[BUFSIZ];
198 int cc;
199 int i;
201 for (cc = i = 0 ; i < ep->sv.c ; i++) {
202 cc += snprintf(&buf[cc], sizeof(buf) - cc, "%s%1.1s", ep->sv.v[i], (i == ep->sv.c - 1) ? "\n" : sp->sep);
204 return safe_write(fp, buf, cc);
206 #endif
208 /* report an error and clear up */
209 static int
210 report_error(FILE *fp, char *name, const char *fmt, ...)
212 va_list vp;
214 va_start(vp, fmt);
215 (void) vfprintf(stderr, fmt, vp);
216 va_end(vp);
217 if (fp)
218 (void) fclose(fp);
219 (void) unlink(name);
220 return 0;
223 /* put the new entry (in place of ent[f] == val, if val is non-NULL) */
225 conffile_putent(conffile_t *sp, int f, char *val, char *newent)
227 ent_t e;
228 FILE *fp;
229 char name[MAXPATHLEN];
230 char *from;
231 int fd;
233 (void) strlcpy(name, "/tmp/split.XXXXXX", sizeof(name));
234 if ((fd = mkstemp(name)) < 0) {
235 (void) fprintf(stderr, "can't mkstemp `%s' (%s)\n", name, strerror(errno));
236 return 0;
238 fp = fdopen(fd, "w");
239 (void) memset(&e, 0x0, sizeof(e));
240 for (;;) {
241 if ((from = read_line(sp, &e)) == NULL) {
242 break;
244 if (iscomment(sp, from)) {
245 if (!safe_write(fp, e.buf, strlen(e.buf))) {
246 return report_error(fp, name, "Short write 1 to `%s' (%s)\n", name, strerror(errno));
249 (void) conffile_split(sp, &e, from);
250 if (val != NULL && (uint32_t)f < e.sv.c && strcmp(val, e.sv.v[f]) == 0) {
251 /* replace it */
252 if (!safe_write(fp, newent, strlen(newent))) {
253 return report_error(fp, name, "Short write 2 to `%s' (%s)\n", name, strerror(errno));
255 } else {
256 if (!safe_write(fp, e.buf, strlen(e.buf))) {
257 return report_error(fp, name, "Short write 3 to `%s' (%s)\n", name, strerror(errno));
261 if (val == NULL && !safe_write(fp, newent, strlen(newent))) {
262 return report_error(fp, name, "Short write 4 to `%s' (%s)\n", name, strerror(errno));
264 (void) fclose(fp);
265 if (rename(name, sp->name) < 0) {
266 return report_error(NULL, name, "can't rename %s to %s (%s)\n", name, sp->name, strerror(errno));
268 return 1;
271 /* print the entry on stdout */
272 void
273 conffile_printent(ent_t *ep)
275 uint32_t i;
277 for (i = 0 ; i < ep->sv.c ; i++) {
278 printf("(%d `%s') ", i, ep->sv.v[i]);
280 printf("\n");