1 /* $NetBSD: services_mkdb.c,v 1.13 2008/03/09 01:29:34 dholland Exp $ */
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn and Christos Zoulas.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: services_mkdb.c,v 1.13 2008/03/09 01:29:34 dholland Exp $");
37 #include <sys/param.h>
51 #include <stringlist.h>
53 static char tname
[MAXPATHLEN
];
58 extern void uniq(const char *);
60 static void add(DB
*, StringList
*, size_t, const char *, size_t *, int);
61 static StringList
***parseservices(const char *, StringList
*);
62 static void cleanup(void);
63 static void store(DB
*, DBT
*, DBT
*, int);
64 static void killproto(DBT
*);
65 static char *getstring(const char *, size_t, char **, const char *);
66 static size_t getprotoindex(StringList
*, const char *);
67 static const char *getprotostr(StringList
*, size_t);
68 static const char *mkaliases(StringList
*, char *, size_t);
69 static void usage(void) __dead
;
71 const HASHINFO hinfo
= {
82 main(int argc
, char *argv
[])
86 const char *fname
= _PATH_SERVICES
;
87 const char *dbname
= _PATH_SERVICES_DB
;
92 StringList
*sl
, ***svc
;
97 while ((ch
= getopt(argc
, argv
, "qo:u")) != -1)
118 if (argc
> 1 || (unique
&& otherflag
))
126 svc
= parseservices(fname
, sl
= sl_init());
129 err(1, "Cannot install exit handler");
131 (void)snprintf(tname
, sizeof(tname
), "%s.tmp", dbname
);
132 db
= dbopen(tname
, O_RDWR
| O_CREAT
| O_EXCL
,
133 (S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
), DB_HASH
, &hinfo
);
135 err(1, "Error opening temporary database `%s'", tname
);
138 for (port
= 0; port
< PMASK
+ 1; port
++) {
139 if (svc
[port
] == NULL
)
142 for (proto
= 0; proto
< PROTOMAX
; proto
++) {
144 if ((s
= svc
[port
][proto
]) == NULL
)
146 add(db
, s
, port
, getprotostr(sl
, proto
), &cnt
, warndup
);
156 err(1, "Error closing temporary database `%s'", tname
);
158 if (rename(tname
, dbname
) == -1)
159 err(1, "Cannot rename `%s' to `%s'", tname
, dbname
);
165 add(DB
*db
, StringList
*sl
, size_t port
, const char *proto
, size_t *cnt
,
169 char keyb
[BUFSIZ
], datab
[BUFSIZ
], abuf
[BUFSIZ
];
175 (void)printf("add %s %zu %s [ ", sl
->sl_str
[0], port
, proto
);
176 for (i
= 1; i
< sl
->sl_cur
; i
++)
177 (void)printf("%s ", sl
->sl_str
[i
]);
181 /* key `indirect key', data `full line' */
182 data
.size
= snprintf(datab
, sizeof(datab
), "%zu", (*cnt
)++) + 1;
183 key
.size
= snprintf(keyb
, sizeof(keyb
), "%s %zu/%s %s",
184 sl
->sl_str
[0], port
, proto
, mkaliases(sl
, abuf
, sizeof(abuf
))) + 1;
185 store(db
, &data
, &key
, warndup
);
187 /* key `\377port/proto', data = `indirect key' */
188 key
.size
= snprintf(keyb
, sizeof(keyb
), "\377%zu/%s",
190 store(db
, &key
, &data
, warndup
);
192 /* key `\377port', data = `indirect key' */
194 store(db
, &key
, &data
, warndup
);
196 /* add references for service and all aliases */
197 for (i
= 0; i
< sl
->sl_cur
; i
++) {
198 /* key `\376service/proto', data = `indirect key' */
199 key
.size
= snprintf(keyb
, sizeof(keyb
), "\376%s/%s",
200 sl
->sl_str
[i
], proto
) + 1;
201 store(db
, &key
, &data
, warndup
);
203 /* key `\376service', data = `indirect key' */
205 store(db
, &key
, &data
, warndup
);
210 static StringList
***
211 parseservices(const char *fname
, StringList
*sl
)
213 size_t len
, line
, pindex
;
215 StringList
***svc
, *s
;
218 if ((fp
= fopen(fname
, "r")) == NULL
)
219 err(1, "Cannot open `%s'", fname
);
222 svc
= ecalloc(PMASK
+ 1, sizeof(StringList
**));
224 /* XXX: change NULL to "\0\0#" when fparseln fixed */
225 for (; (p
= fparseln(fp
, &len
, &line
, NULL
, 0)) != NULL
; free(p
)) {
226 char *name
, *port
, *proto
, *aliases
, *cp
, *alias
;
232 for (cp
= p
; *cp
&& isspace((unsigned char)*cp
); cp
++)
235 if (*cp
== '\0' || *cp
== '#')
238 if ((name
= getstring(fname
, line
, &cp
, "name")) == NULL
)
241 if ((port
= getstring(fname
, line
, &cp
, "port")) == NULL
)
245 for (aliases
= cp
; *cp
&& *cp
!= '#'; cp
++)
253 proto
= strchr(port
, '/');
254 if (proto
== NULL
|| proto
[1] == '\0') {
255 warnx("%s, %zu: no protocol found", fname
, line
);
261 pnum
= strtoul(port
, &ep
, 0);
262 if (*port
== '\0' || *ep
!= '\0') {
263 warnx("%s, %zu: invalid port `%s'", fname
, line
, port
);
266 if ((errno
== ERANGE
&& pnum
== ULONG_MAX
) || pnum
> PMASK
) {
267 warnx("%s, %zu: port too big `%s'", fname
, line
, port
);
271 if (svc
[pnum
] == NULL
)
272 svc
[pnum
] = ecalloc(PROTOMAX
, sizeof(StringList
*));
274 pindex
= getprotoindex(sl
, proto
);
275 if (svc
[pnum
][pindex
] == NULL
)
276 s
= svc
[pnum
][pindex
] = sl_init();
278 s
= svc
[pnum
][pindex
];
280 /* build list of aliases */
281 if (sl_find(s
, name
) == NULL
)
282 (void)sl_add(s
, estrdup(name
));
285 while ((alias
= strsep(&aliases
, " \t")) != NULL
) {
286 if (alias
[0] == '\0')
288 if (sl_find(s
, alias
) == NULL
)
289 (void)sl_add(s
, estrdup(alias
));
298 * cleanup(): Remove temporary files upon exit
308 getstring(const char *fname
, size_t line
, char **cp
, const char *tag
)
312 while ((str
= strsep(cp
, " \t")) != NULL
&& *str
== '\0')
316 warnx("%s, %zu: no %s found", fname
, line
, tag
);
324 char *p
, *d
= key
->data
;
326 if ((p
= strchr(d
, '/')) == NULL
)
333 store(DB
*db
, DBT
*key
, DBT
*data
, int warndup
)
336 int k
= key
->size
- 1;
337 int d
= data
->size
- 1;
338 (void)printf("store [%*.*s] [%*.*s]\n",
339 k
, k
, (char *)key
->data
+ 1,
340 d
, d
, (char *)data
->data
+ 1);
342 switch ((db
->put
)(db
, key
, data
, R_NOOVERWRITE
)) {
347 warnx("duplicate service `%s'",
348 &((char *)key
->data
)[1]);
360 getprotoindex(StringList
*sl
, const char *str
)
364 for (i
= 0; i
< sl
->sl_cur
; i
++)
365 if (strcmp(sl
->sl_str
[i
], str
) == 0)
369 errx(1, "Ran out of protocols adding `%s';"
370 " recompile with larger PROTOMAX", str
);
371 (void)sl_add(sl
, estrdup(str
));
376 getprotostr(StringList
*sl
, size_t i
)
378 assert(i
< sl
->sl_cur
);
379 return sl
->sl_str
[i
];
383 mkaliases(StringList
*sl
, char *buf
, size_t len
)
388 for (i
= 1, pos
= 0; i
< sl
->sl_cur
; i
++) {
389 nc
= strlcpy(buf
+ pos
, sl
->sl_str
[i
], len
);
394 nc
= strlcpy(buf
+ pos
, " ", len
);
402 warn("aliases for `%s' truncated", sl
->sl_str
[0]);
409 (void)fprintf(stderr
, "Usage:\t%s [-q] [-o <db>] [<servicefile>]\n"
410 "\t%s -u [<servicefile>]\n", getprogname(), getprogname());