]>
Commit | Line | Data |
---|---|---|
793bd4d9 UD |
1 | /* Create simple DB database from textual input. |
2 | Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. | |
3 | This file is part of the GNU C Library. | |
4 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
793bd4d9 UD |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
793bd4d9 | 15 | |
41bdb6e2 AJ |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | 02111-1307 USA. */ | |
793bd4d9 UD |
20 | |
21 | #include <argp.h> | |
22 | #include <ctype.h> | |
23 | #include <dlfcn.h> | |
24 | #include <errno.h> | |
25 | #include <error.h> | |
26 | #include <fcntl.h> | |
27 | #include <libintl.h> | |
28 | #include <locale.h> | |
29 | #include <stdio.h> | |
30 | #include <stdint.h> | |
31 | #include <stdlib.h> | |
32 | #include <string.h> | |
33 | #include <sys/stat.h> | |
34 | #include "nss_db/dummy-db.h" | |
35 | ||
36 | /* Get libc version number. */ | |
37 | #include "../version.h" | |
38 | ||
39 | #define PACKAGE _libc_intl_domainname | |
40 | ||
41 | /* If non-zero convert key to lower case. */ | |
42 | static int to_lowercase; | |
43 | ||
44 | /* If non-zero print content of input file, one entry per line. */ | |
45 | static int do_undo; | |
46 | ||
47 | /* If non-zero do not print informational messages. */ | |
48 | static int be_quiet; | |
49 | ||
50 | /* Name of output file. */ | |
51 | static const char *output_name; | |
52 | ||
793bd4d9 UD |
53 | /* Name and version of program. */ |
54 | static void print_version (FILE *stream, struct argp_state *state); | |
55 | void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; | |
56 | ||
57 | /* Definitions of arguments for argp functions. */ | |
58 | static const struct argp_option options[] = | |
59 | { | |
60 | { "fold-case", 'f', NULL, 0, N_("Convert key to lower case") }, | |
61 | { "output", 'o', N_("NAME"), 0, N_("Write output to file NAME") }, | |
62 | { "quiet", 'q', NULL, 0, | |
63 | N_("Do not print messages while building database") }, | |
64 | { "undo", 'u', NULL, 0, | |
65 | N_("Print content of database file, one entry a line") }, | |
66 | { NULL, 0, NULL, 0, NULL } | |
67 | }; | |
68 | ||
69 | /* Short description of program. */ | |
70 | static const char doc[] = N_("Create simple DB database from textual input."); | |
71 | ||
72 | /* Strings for arguments in help texts. */ | |
73 | static const char args_doc[] = N_("\ | |
74 | INPUT-FILE OUTPUT-FILE\n-o OUTPUT-FILE INPUT-FILE\n-u INPUT-FILE"); | |
75 | ||
76 | /* Prototype for option handler. */ | |
cbc85992 | 77 | static error_t parse_opt (int key, char *arg, struct argp_state *state); |
793bd4d9 UD |
78 | |
79 | /* Function to print some extra text in the help message. */ | |
cbc85992 | 80 | static char *more_help (int key, const char *text, void *input); |
793bd4d9 UD |
81 | |
82 | /* Data structure to communicate with argp functions. */ | |
83 | static struct argp argp = | |
84 | { | |
85 | options, parse_opt, args_doc, doc, NULL, more_help | |
86 | }; | |
87 | ||
88 | ||
89 | /* Prototypes for local functions. */ | |
cbc85992 UD |
90 | static int process_input (FILE *input, const char *inname, NSS_DB *output, |
91 | int to_lowercase, int be_quiet); | |
92 | static int print_database (NSS_DB *db); | |
793bd4d9 UD |
93 | |
94 | ||
95 | int | |
cbc85992 | 96 | main (int argc, char *argv[]) |
793bd4d9 UD |
97 | { |
98 | const char *input_name; | |
99 | FILE *input_file; | |
100 | NSS_DB *db_file; | |
101 | int status; | |
102 | int remaining; | |
103 | int mode = 0666; | |
104 | ||
105 | /* Set locale via LC_ALL. */ | |
106 | setlocale (LC_ALL, ""); | |
107 | ||
108 | /* Set the text message domain. */ | |
109 | textdomain (_libc_intl_domainname); | |
110 | ||
111 | /* Initialize local variables. */ | |
112 | input_name = NULL; | |
113 | ||
114 | /* Parse and process arguments. */ | |
115 | argp_parse (&argp, argc, argv, 0, &remaining, NULL); | |
116 | ||
117 | /* Determine file names. */ | |
118 | if (do_undo || output_name != NULL) | |
119 | { | |
120 | if (remaining + 1 != argc) | |
121 | { | |
122 | wrong_arguments: | |
123 | error (0, 0, gettext ("wrong number of arguments")); | |
124 | argp_help (&argp, stdout, ARGP_HELP_SEE, | |
125 | program_invocation_short_name); | |
126 | exit (1); | |
127 | } | |
128 | input_name = argv[remaining]; | |
129 | } | |
130 | else | |
131 | { | |
132 | if (remaining + 2 != argc) | |
133 | goto wrong_arguments; | |
134 | ||
135 | input_name = argv[remaining++]; | |
136 | output_name = argv[remaining]; | |
137 | } | |
138 | ||
9d8525f2 UD |
139 | /* First load the shared object to initialize version dependend |
140 | variables. */ | |
247c8869 | 141 | if (load_db () != NSS_STATUS_SUCCESS) |
9d8525f2 UD |
142 | error (EXIT_FAILURE, 0, gettext ("No usable database library found.")); |
143 | ||
793bd4d9 UD |
144 | /* Special handling if we are asked to print the database. */ |
145 | if (do_undo) | |
146 | { | |
9d8525f2 | 147 | dbopen (input_name, db_rdonly, 0666, &db_file); |
793bd4d9 UD |
148 | if (db_file == NULL) |
149 | error (EXIT_FAILURE, 0, gettext ("cannot open database file `%s': %s"), | |
150 | input_name, | |
151 | (errno == EINVAL ? gettext ("incorrectly formatted file") | |
152 | : strerror (errno))); | |
153 | ||
154 | status = print_database (db_file); | |
155 | ||
156 | db_file->close (db_file->db, 0); | |
157 | ||
158 | return status; | |
159 | } | |
160 | ||
161 | /* Open input file. */ | |
162 | if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0) | |
163 | input_file = stdin; | |
164 | else | |
165 | { | |
166 | struct stat st; | |
167 | ||
168 | input_file = fopen (input_name, "r"); | |
169 | if (input_file == NULL) | |
170 | error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"), | |
171 | input_name); | |
172 | ||
173 | /* Get the access rights from the source file. The output file should | |
174 | have the same. */ | |
175 | if (fstat (fileno (input_file), &st) >= 0) | |
176 | mode = st.st_mode & ACCESSPERMS; | |
177 | } | |
178 | ||
179 | /* Open output file. This must not be standard output so we don't | |
180 | handle "-" and "/dev/stdout" special. */ | |
9d8525f2 | 181 | dbopen (output_name, DB_CREATE | db_truncate, mode, &db_file); |
793bd4d9 UD |
182 | if (db_file == NULL) |
183 | error (EXIT_FAILURE, errno, gettext ("cannot open output file `%s'"), | |
184 | output_name); | |
185 | ||
186 | /* Start the real work. */ | |
187 | status = process_input (input_file, input_name, db_file, to_lowercase, | |
188 | be_quiet); | |
189 | ||
190 | /* Close files. */ | |
191 | if (input_file != stdin) | |
192 | fclose (input_file); | |
193 | db_file->close (db_file->db, 0); | |
194 | ||
195 | return status; | |
196 | } | |
197 | ||
198 | ||
199 | /* Handle program arguments. */ | |
200 | static error_t | |
201 | parse_opt (int key, char *arg, struct argp_state *state) | |
202 | { | |
203 | switch (key) | |
204 | { | |
205 | case 'f': | |
206 | to_lowercase = 1; | |
207 | break; | |
208 | case 'o': | |
209 | output_name = arg; | |
210 | break; | |
211 | case 'q': | |
212 | be_quiet = 1; | |
213 | break; | |
214 | case 'u': | |
215 | do_undo = 1; | |
216 | break; | |
217 | default: | |
218 | return ARGP_ERR_UNKNOWN; | |
219 | } | |
220 | return 0; | |
221 | } | |
222 | ||
223 | ||
224 | static char * | |
225 | more_help (int key, const char *text, void *input) | |
226 | { | |
227 | switch (key) | |
228 | { | |
229 | case ARGP_KEY_HELP_EXTRA: | |
230 | /* We print some extra information. */ | |
231 | return strdup (gettext ("\ | |
232 | Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n")); | |
233 | default: | |
234 | break; | |
235 | } | |
236 | return (char *) text; | |
237 | } | |
238 | ||
239 | /* Print the version information. */ | |
240 | static void | |
241 | print_version (FILE *stream, struct argp_state *state) | |
242 | { | |
243 | fprintf (stream, "makedb (GNU %s) %s\n", PACKAGE, VERSION); | |
244 | fprintf (stream, gettext ("\ | |
245 | Copyright (C) %s Free Software Foundation, Inc.\n\ | |
246 | This is free software; see the source for copying conditions. There is NO\n\ | |
247 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ | |
248 | "), "2000"); | |
249 | fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); | |
250 | } | |
251 | ||
252 | ||
253 | static int | |
254 | process_input (input, inname, output, to_lowercase, be_quiet) | |
255 | FILE *input; | |
256 | const char *inname; | |
257 | NSS_DB *output; | |
258 | int to_lowercase; | |
259 | int be_quiet; | |
260 | { | |
261 | char *line; | |
262 | size_t linelen; | |
263 | int status; | |
264 | size_t linenr; | |
265 | ||
266 | line = NULL; | |
267 | linelen = 0; | |
268 | status = EXIT_SUCCESS; | |
269 | linenr = 0; | |
270 | ||
271 | while (!feof (input)) | |
272 | { | |
273 | DBT key; | |
274 | DBT val; | |
275 | char *cp; | |
276 | int n; | |
277 | ||
278 | n = getline (&line, &linelen, input); | |
279 | if (n < 0) | |
280 | /* This means end of file or some bug. */ | |
281 | break; | |
282 | if (n == 0) | |
283 | /* Short read. Probably interrupted system call. */ | |
284 | continue; | |
285 | ||
286 | ++linenr; | |
287 | ||
288 | if (line[n - 1] == '\n') | |
289 | /* Remove trailing newline. */ | |
290 | line[--n] = '\0'; | |
291 | ||
292 | cp = line; | |
293 | while (isspace (*cp)) | |
294 | ++cp; | |
295 | ||
296 | if (*cp == '#') | |
297 | /* First non-space character in line '#': it's a comment. */ | |
298 | continue; | |
299 | ||
300 | key.data = cp; | |
301 | while (*cp != '\0' && !isspace (*cp)) | |
302 | { | |
303 | if (to_lowercase) | |
304 | *cp = tolower (*cp); | |
305 | ++cp; | |
306 | } | |
307 | ||
308 | if (key.data == cp) | |
309 | /* It's an empty line. */ | |
310 | continue; | |
311 | ||
312 | key.size = cp - (char *) key.data; | |
313 | key.flags = 0; | |
314 | ||
315 | while (isspace (*cp)) | |
316 | ++cp; | |
317 | ||
318 | val.data = cp; | |
319 | val.size = (&line[n] - cp) + 1; | |
320 | val.flags = 0; | |
321 | ||
322 | /* Store the value. */ | |
323 | status = output->put (output->db, NULL, &key, &val, db_nooverwrite); | |
324 | if (status != 0) | |
325 | { | |
9d8525f2 | 326 | if (status == db_keyexist) |
793bd4d9 UD |
327 | { |
328 | if (!be_quiet) | |
329 | error_at_line (0, 0, inname, linenr, | |
330 | gettext ("duplicate key")); | |
331 | /* This is no real error. Just give a warning. */ | |
332 | status = 0; | |
333 | continue; | |
334 | } | |
335 | else | |
336 | error (0, status, gettext ("while writing database file")); | |
337 | ||
338 | status = EXIT_FAILURE; | |
339 | ||
340 | clearerr (input); | |
341 | break; | |
342 | } | |
343 | } | |
344 | ||
345 | if (ferror (input)) | |
346 | { | |
347 | error (0, 0, gettext ("problems while reading `%s'"), inname); | |
348 | status = EXIT_FAILURE; | |
349 | } | |
350 | ||
351 | return status; | |
352 | } | |
353 | ||
354 | ||
355 | static int | |
356 | print_database (db) | |
357 | NSS_DB *db; | |
358 | { | |
359 | DBT key; | |
360 | DBT val; | |
361 | NSS_DBC *cursor; | |
362 | int status; | |
363 | ||
364 | status = db->cursor (db->db, NULL, &cursor); | |
365 | if (status != 0) | |
366 | { | |
367 | error (0, status, gettext ("while reading database")); | |
368 | return EXIT_FAILURE; | |
369 | } | |
370 | ||
371 | key.flags = 0; | |
372 | val.flags = 0; | |
373 | status = cursor->c_get (cursor->cursor, &key, &val, db_first); | |
374 | while (status == 0) | |
375 | { | |
376 | printf ("%.*s %s\n", (int) key.size, (char *) key.data, | |
377 | (char *) val.data); | |
378 | ||
379 | status = cursor->c_get (cursor->cursor, &key, &val, db_next); | |
380 | } | |
381 | ||
9d8525f2 | 382 | if (status != db_notfound) |
793bd4d9 UD |
383 | { |
384 | error (0, status, gettext ("while reading database")); | |
385 | return EXIT_FAILURE; | |
386 | } | |
387 | ||
388 | return EXIT_SUCCESS; | |
389 | } |