]>
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 ("\ | |
d40eb37a UD |
232 | For bug reporting instructions, please see:\n\ |
233 | <http://www.gnu.org/software/libc/bugs.html>.\n")); | |
793bd4d9 UD |
234 | default: |
235 | break; | |
236 | } | |
237 | return (char *) text; | |
238 | } | |
239 | ||
240 | /* Print the version information. */ | |
241 | static void | |
242 | print_version (FILE *stream, struct argp_state *state) | |
243 | { | |
244 | fprintf (stream, "makedb (GNU %s) %s\n", PACKAGE, VERSION); | |
245 | fprintf (stream, gettext ("\ | |
246 | Copyright (C) %s Free Software Foundation, Inc.\n\ | |
247 | This is free software; see the source for copying conditions. There is NO\n\ | |
248 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ | |
249 | "), "2000"); | |
250 | fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); | |
251 | } | |
252 | ||
253 | ||
254 | static int | |
255 | process_input (input, inname, output, to_lowercase, be_quiet) | |
256 | FILE *input; | |
257 | const char *inname; | |
258 | NSS_DB *output; | |
259 | int to_lowercase; | |
260 | int be_quiet; | |
261 | { | |
262 | char *line; | |
263 | size_t linelen; | |
264 | int status; | |
265 | size_t linenr; | |
266 | ||
267 | line = NULL; | |
268 | linelen = 0; | |
269 | status = EXIT_SUCCESS; | |
270 | linenr = 0; | |
271 | ||
272 | while (!feof (input)) | |
273 | { | |
274 | DBT key; | |
275 | DBT val; | |
276 | char *cp; | |
277 | int n; | |
278 | ||
279 | n = getline (&line, &linelen, input); | |
280 | if (n < 0) | |
281 | /* This means end of file or some bug. */ | |
282 | break; | |
283 | if (n == 0) | |
284 | /* Short read. Probably interrupted system call. */ | |
285 | continue; | |
286 | ||
287 | ++linenr; | |
288 | ||
289 | if (line[n - 1] == '\n') | |
290 | /* Remove trailing newline. */ | |
291 | line[--n] = '\0'; | |
292 | ||
293 | cp = line; | |
294 | while (isspace (*cp)) | |
295 | ++cp; | |
296 | ||
297 | if (*cp == '#') | |
298 | /* First non-space character in line '#': it's a comment. */ | |
299 | continue; | |
300 | ||
301 | key.data = cp; | |
302 | while (*cp != '\0' && !isspace (*cp)) | |
303 | { | |
304 | if (to_lowercase) | |
305 | *cp = tolower (*cp); | |
306 | ++cp; | |
307 | } | |
308 | ||
309 | if (key.data == cp) | |
310 | /* It's an empty line. */ | |
311 | continue; | |
312 | ||
313 | key.size = cp - (char *) key.data; | |
314 | key.flags = 0; | |
315 | ||
316 | while (isspace (*cp)) | |
317 | ++cp; | |
318 | ||
319 | val.data = cp; | |
320 | val.size = (&line[n] - cp) + 1; | |
321 | val.flags = 0; | |
322 | ||
323 | /* Store the value. */ | |
324 | status = output->put (output->db, NULL, &key, &val, db_nooverwrite); | |
325 | if (status != 0) | |
326 | { | |
9d8525f2 | 327 | if (status == db_keyexist) |
793bd4d9 UD |
328 | { |
329 | if (!be_quiet) | |
330 | error_at_line (0, 0, inname, linenr, | |
331 | gettext ("duplicate key")); | |
332 | /* This is no real error. Just give a warning. */ | |
333 | status = 0; | |
334 | continue; | |
335 | } | |
336 | else | |
337 | error (0, status, gettext ("while writing database file")); | |
338 | ||
339 | status = EXIT_FAILURE; | |
340 | ||
341 | clearerr (input); | |
342 | break; | |
343 | } | |
344 | } | |
345 | ||
346 | if (ferror (input)) | |
347 | { | |
348 | error (0, 0, gettext ("problems while reading `%s'"), inname); | |
349 | status = EXIT_FAILURE; | |
350 | } | |
351 | ||
352 | return status; | |
353 | } | |
354 | ||
355 | ||
356 | static int | |
357 | print_database (db) | |
358 | NSS_DB *db; | |
359 | { | |
360 | DBT key; | |
361 | DBT val; | |
362 | NSS_DBC *cursor; | |
363 | int status; | |
364 | ||
365 | status = db->cursor (db->db, NULL, &cursor); | |
366 | if (status != 0) | |
367 | { | |
368 | error (0, status, gettext ("while reading database")); | |
369 | return EXIT_FAILURE; | |
370 | } | |
371 | ||
372 | key.flags = 0; | |
373 | val.flags = 0; | |
374 | status = cursor->c_get (cursor->cursor, &key, &val, db_first); | |
375 | while (status == 0) | |
376 | { | |
377 | printf ("%.*s %s\n", (int) key.size, (char *) key.data, | |
378 | (char *) val.data); | |
379 | ||
380 | status = cursor->c_get (cursor->cursor, &key, &val, db_next); | |
381 | } | |
382 | ||
9d8525f2 | 383 | if (status != db_notfound) |
793bd4d9 UD |
384 | { |
385 | error (0, status, gettext ("while reading database")); | |
386 | return EXIT_FAILURE; | |
387 | } | |
388 | ||
389 | return EXIT_SUCCESS; | |
390 | } |