1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * httxt2dbm.c: simple program for converting RewriteMap text files to DBM
19 * Rewrite databases for the Apache HTTP server
20 *
21 */
22
23#include "apr.h"
24#include "apr_lib.h"
25#include "apr_strings.h"
26#include "apr_file_io.h"
27#include "apr_file_info.h"
28#include "apr_pools.h"
29#include "apr_getopt.h"
30#include "apu.h"
31#include "apr_dbm.h"
32
33#if APR_HAVE_STDLIB_H
34#include <stdlib.h> /* for atexit() */
35#endif
36
37static const char *input;
38static const char *output;
39static const char *format;
40static const char *shortname;
41static apr_file_t *errfile;
42static int verbose;
43
44/* From mod_rewrite.c */
45#ifndef REWRITE_MAX_TXT_MAP_LINE
46#define REWRITE_MAX_TXT_MAP_LINE 1024
47#endif
48
49#define NL APR_EOL_STR
50
51#define AVAIL "available"
52#define UNAVAIL "unavailable"
53
54static void usage(void)
55{
56    const char *have_sdbm;
57    const char *have_gdbm;
58    const char *have_ndbm;
59    const char *have_db;
60
61#if APU_HAVE_SDBM
62    have_sdbm = AVAIL;
63#else
64    have_sdbm = UNAVAIL;
65#endif
66#if APU_HAVE_GDBM
67    have_gdbm = AVAIL;
68#else
69    have_gdbm = UNAVAIL;
70#endif
71#if APU_HAVE_NDBM
72    have_ndbm = AVAIL;
73#else
74    have_ndbm = UNAVAIL;
75#endif
76#if APU_HAVE_DB
77    have_db = AVAIL;
78#else
79    have_db = UNAVAIL;
80#endif
81
82    apr_file_printf(errfile,
83    "%s -- Program to Create DBM Files for use by RewriteMap" NL
84    "Usage: %s [-v] [-f format] -i SOURCE_TXT -o OUTPUT_DBM" NL
85    NL
86    "Options: " NL
87    " -v    More verbose output" NL
88    NL
89    " -i    Source Text File. If '-', use stdin." NL
90    NL
91    " -o    Output DBM." NL
92    NL
93    " -f    DBM Format.  If not specified, will use the APR Default." NL
94    "           GDBM for GDBM files (%s)" NL
95    "           SDBM for SDBM files (%s)" NL
96    "           DB   for berkeley DB files (%s)" NL
97    "           NDBM for NDBM files (%s)" NL
98    "           default for the default DBM type" NL
99    NL,
100    shortname,
101    shortname,
102    have_gdbm,
103    have_sdbm,
104    have_db,
105    have_ndbm);
106}
107
108
109static apr_status_t to_dbm(apr_dbm_t *dbm, apr_file_t *fp, apr_pool_t *pool)
110{
111    apr_status_t rv = APR_SUCCESS;
112    char line[REWRITE_MAX_TXT_MAP_LINE + 1]; /* +1 for \0 */
113    apr_datum_t dbmkey;
114    apr_datum_t dbmval;
115    apr_pool_t* p;
116
117    apr_pool_create(&p, pool);
118
119    while (apr_file_gets(line, sizeof(line), fp) == APR_SUCCESS) {
120        char *c, *value;
121
122        if (*line == '#' || apr_isspace(*line)) {
123            continue;
124        }
125
126        c = line;
127
128        while (*c && !apr_isspace(*c)) {
129            ++c;
130        }
131
132        if (!*c) {
133            /* no value. solid line of data. */
134            continue;
135        }
136
137        dbmkey.dptr = apr_pstrmemdup(p, line,  c - line);
138        dbmkey.dsize = (c - line);
139
140        while (apr_isspace(*c)) {
141            ++c;
142        }
143
144        if (!*c) {
145            apr_pool_clear(p);
146            continue;
147        }
148
149        value = c;
150
151        while (*c && !apr_isspace(*c)) {
152            ++c;
153        }
154
155        dbmval.dptr = apr_pstrmemdup(p, value,  c - value);
156        dbmval.dsize = (c - value);
157
158        if (verbose) {
159            apr_file_printf(errfile, "    '%s' -> '%s'" NL,
160                            dbmkey.dptr, dbmval.dptr);
161        }
162
163        rv = apr_dbm_store(dbm, dbmkey, dbmval);
164
165        apr_pool_clear(p);
166
167        if (rv != APR_SUCCESS) {
168            break;
169        }
170    }
171
172    return rv;
173}
174
175int main(int argc, const char *const argv[])
176{
177    apr_pool_t *pool;
178    apr_status_t rv = APR_SUCCESS;
179    apr_getopt_t *opt;
180    const char *opt_arg;
181    char ch;
182    apr_file_t *infile;
183    apr_dbm_t *outdbm;
184
185    apr_app_initialize(&argc, &argv, NULL);
186    atexit(apr_terminate);
187
188    verbose = 0;
189    format = NULL;
190    input = NULL;
191    output = NULL;
192
193    apr_pool_create(&pool, NULL);
194
195    if (argc) {
196        shortname = apr_filepath_name_get(argv[0]);
197    }
198    else {
199        shortname = "httxt2dbm";
200    }
201
202    apr_file_open_stderr(&errfile, pool);
203    rv = apr_getopt_init(&opt, pool, argc, argv);
204
205    if (rv != APR_SUCCESS) {
206        apr_file_printf(errfile, "Error: apr_getopt_init failed." NL NL);
207        return 1;
208    }
209
210    if (argc <= 1) {
211        usage();
212        return 1;
213    }
214
215    while ((rv = apr_getopt(opt, "vf::i::o::", &ch, &opt_arg)) == APR_SUCCESS) {
216        switch (ch) {
217        case 'v':
218            if (verbose) {
219                apr_file_printf(errfile, "Error: -v can only be passed once" NL NL);
220                usage();
221                return 1;
222            }
223            verbose = 1;
224            break;
225        case 'f':
226            if (format) {
227                apr_file_printf(errfile, "Error: -f can only be passed once" NL NL);
228                usage();
229                return 1;
230            }
231            format = apr_pstrdup(pool, opt_arg);
232            break;
233        case 'i':
234            if (input) {
235                apr_file_printf(errfile, "Error: -i can only be passed once" NL NL);
236                usage();
237                return 1;
238            }
239            input = apr_pstrdup(pool, opt_arg);
240            break;
241        case 'o':
242            if (output) {
243                apr_file_printf(errfile, "Error: -o can only be passed once" NL NL);
244                usage();
245                return 1;
246            }
247            output = apr_pstrdup(pool, opt_arg);
248            break;
249        }
250    }
251
252    if (rv != APR_EOF) {
253        apr_file_printf(errfile, "Error: Parsing Arguments Failed" NL NL);
254        usage();
255        return 1;
256    }
257
258    if (!input) {
259        apr_file_printf(errfile, "Error: No input file specified." NL NL);
260        usage();
261        return 1;
262    }
263
264    if (!output) {
265        apr_file_printf(errfile, "Error: No output DBM specified." NL NL);
266        usage();
267        return 1;
268    }
269
270    if (!format) {
271        format = "default";
272    }
273
274    if (verbose) {
275        apr_file_printf(errfile, "DBM Format: %s" NL, format);
276    }
277
278    if (!strcmp(input, "-")) {
279        rv = apr_file_open_stdin(&infile, pool);
280    }
281    else {
282        rv = apr_file_open(&infile, input, APR_READ|APR_BUFFERED,
283                           APR_OS_DEFAULT, pool);
284    }
285
286    if (rv != APR_SUCCESS) {
287        apr_file_printf(errfile,
288                        "Error: Cannot open input file '%s': (%d) %pm" NL NL,
289                         input, rv, &rv);
290        return 1;
291    }
292
293    if (verbose) {
294        apr_file_printf(errfile, "Input File: %s" NL, input);
295    }
296
297    rv = apr_dbm_open_ex(&outdbm, format, output, APR_DBM_RWCREATE,
298                    APR_OS_DEFAULT, pool);
299
300    if (APR_STATUS_IS_ENOTIMPL(rv)) {
301        apr_file_printf(errfile,
302                        "Error: The requested DBM Format '%s' is not available." NL NL,
303                         format);
304        return 1;
305    }
306
307    if (rv != APR_SUCCESS) {
308        apr_file_printf(errfile,
309                        "Error: Cannot open output DBM '%s': (%d) %pm" NL NL,
310                         output, rv, &rv);
311        return 1;
312    }
313
314    if (verbose) {
315        apr_file_printf(errfile, "DBM File: %s" NL, output);
316    }
317
318    rv = to_dbm(outdbm, infile, pool);
319
320    if (rv != APR_SUCCESS) {
321        apr_file_printf(errfile,
322                        "Error: Converting to DBM: (%d) %pm" NL NL,
323                         rv, &rv);
324        return 1;
325    }
326
327    apr_dbm_close(outdbm);
328
329    if (verbose) {
330        apr_file_printf(errfile, "Conversion Complete." NL);
331    }
332
333    return 0;
334}
335
336