services_mkdb.c revision 1.3 1 /* $NetBSD: services_mkdb.c,v 1.3 2006/07/27 22:13:38 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __RCSID("$NetBSD: services_mkdb.c,v 1.3 2006/07/27 22:13:38 christos Exp $");
42 #endif /* not lint */
43
44
45 #include <sys/param.h>
46
47 #include <db.h>
48 #include <err.h>
49 #include <fcntl.h>
50 #include <netdb.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <util.h>
56 #include <ctype.h>
57 #include <stringlist.h>
58
59 static char tname[MAXPATHLEN];
60
61 static void cleanup(void);
62 static void usage(void) __attribute__((__noreturn__));
63
64 int
65 main(int argc, char *argv[])
66 {
67 DB *db;
68 FILE *fp;
69 int ch;
70 size_t len, line;
71 char keyb[BUFSIZ], datab[BUFSIZ], *p;
72 const char *fname = _PATH_SERVICES;
73 DBT data, key;
74 const char *dbname = _PATH_SERVICES_DB;
75
76 setprogname(argv[0]);
77
78 while ((ch = getopt(argc, argv, "o:")) != -1)
79 switch (ch) {
80 case 'o':
81 dbname = optarg;
82 break;
83 case '?':
84 default:
85 usage();
86 }
87
88 argc -= optind;
89 argv += optind;
90
91 if (argc > 1)
92 usage();
93 if (argc == 1)
94 fname = argv[0];
95
96 if ((fp = fopen(fname, "r")) == NULL)
97 err(1, "Cannot open `%s'", fname);
98
99 if (atexit(cleanup))
100 err(1, "Cannot install exit handler");
101
102 (void)snprintf(tname, sizeof(tname), "%s.tmp", dbname);
103 db = dbopen(tname, O_RDWR | O_CREAT | O_EXCL,
104 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), DB_HASH, NULL);
105 if (!db)
106 err(1, "Error opening temporary database `%s'", tname);
107
108 key.data = (u_char *)(void *)keyb;
109 data.data = (u_char *)(void *)datab;
110
111 line = 0;
112 /* XXX: change NULL to "\0\0#" when fparseln fixed */
113 for (; (p = fparseln(fp, &len, &line, NULL, 0)) != NULL; free(p)) {
114 char *name, *port, *proto, *aliases, *cp, *alias;
115 StringList *sl;
116 size_t i;
117
118 if (len == 0)
119 continue;
120 cp = p;
121 while ((name = strsep(&cp, " \t")) != NULL && *name == '\0')
122 continue;
123 if (name == NULL) {
124 warnx("%s, %zu: no name found", fname, line);
125 continue;
126 }
127 while ((port = strsep(&cp, " \t")) != NULL && *port == '\0')
128 continue;
129 if (port == NULL) {
130 warnx("%s, %zu: no port found", fname, line);
131 continue;
132 }
133 proto = strchr(port, '/');
134 if (proto == NULL || proto[1] == '\0') {
135 warnx("%s, %zu: no protocol found", fname, line);
136 continue;
137 }
138 *proto++ = '\0';
139 for (aliases = cp; cp && isspace((unsigned char)*aliases);
140 aliases++)
141 continue;
142
143 if ((aliases = strdup(aliases ? aliases : "")) == NULL)
144 err(1, "Cannot copy string");
145
146 /* key `port/proto', data = full line */
147 key.size = snprintf(keyb, sizeof(keyb), "%s/%s",
148 port, proto) + 1;
149 data.size = snprintf(datab, sizeof(datab), "%s %s/%s %s",
150 name, port, proto, aliases) + 1;
151 switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) {
152 case 0:
153 break;
154 case 1:
155 warnx("%s, %zu: duplicate service `%s'",
156 fname, line, keyb);
157 break;
158 case -1:
159 err(1, "put");
160 break;
161 default:
162 abort();
163 break;
164 }
165
166 /* key `\376port', data = full line */
167 key.size = snprintf(keyb, sizeof(keyb), "\376%s", port) + 1;
168 if ((db->put)(db, &key, &data, R_NOOVERWRITE) == -1)
169 err(1, "put");
170
171
172 /* build list of aliases */
173 sl = sl_init();
174 sl_add(sl, name);
175 while ((alias = strsep(&cp, " \t")) != NULL) {
176 if (alias[0] == '\0')
177 continue;
178 sl_add(sl, alias);
179 }
180
181 /* add references for service and all aliases */
182 for (i = 0; i < sl->sl_cur; i++) {
183 /* key `\377service/proto', data = `full line' */
184 key.size = snprintf(keyb, sizeof(keyb), "\377%s/%s",
185 sl->sl_str[i], proto) + 1;
186 data.size = snprintf(datab, sizeof(datab),
187 "%s %s/%s %s",
188 name, port, proto, aliases) + 1;
189 switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) {
190 case 0:
191 break;
192 case 1:
193 warnx("%s, %zu: duplicate service `%s'",
194 fname, line, keyb);
195 break;
196 case -1:
197 err(1, "put");
198 break;
199 default:
200 abort();
201 break;
202 }
203
204 /* key `\377service', data = `full line' */
205 key.size = snprintf(keyb, sizeof(keyb), "\377%s",
206 sl->sl_str[i]) + 1;
207 data.size = snprintf(datab, sizeof(datab),
208 "%s %s/%s %s",
209 name, port, proto, aliases) + 1;
210
211 if ((db->put)(db, &key, &data, R_NOOVERWRITE) == -1)
212 err(1, "put");
213 }
214 sl_free(sl, 0);
215 free(aliases);
216 }
217
218 if ((db->close)(db))
219 err(1, "Error closing temporary database `%s'", tname);
220 if (rename(tname, dbname) == -1)
221 err(1, "Cannot rename `%s' to `%s'", tname, dbname);
222
223 return 0;
224 }
225
226 /*
227 * cleanup(): Remove temporary files upon exit
228 */
229 static void
230 cleanup(void)
231 {
232 if (tname[0])
233 (void)unlink(tname);
234 }
235
236 static void
237 usage(void)
238 {
239 (void)fprintf(stderr, "Usage: %s [-o <db>] [<servicefile>]\n",
240 getprogname());
241 exit(1);
242 }
243