/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- dump_fputs
- get_program_name
- syntax
- parse_options
- load_classes
- output_object
- seperate_time_t
- main
1 /* text_export - output RIP database into text files of RPSL objects */
2
3 /*
4 Copyright (c) 2000,2001,2002 RIPE NCC
5
6
7 All Rights Reserved
8
9 Permission to use, copy, modify, and distribute this software and its
10 documentation for any purpose and without fee is hereby granted,
11 provided that the above copyright notice appear in all copies and that
12 both that copyright notice and this permission notice appear in
13 supporting documentation, and that the name of the author not be
14 used in advertising or publicity pertaining to distribution of the
15 software without specific, written prior permission.
16
17 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
19 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
20 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
21 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 /* $Id: text_export.c,v 1.5 2002/04/16 11:53:00 shane Exp $ */
26
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <time.h>
33 #include <assert.h>
34
35 #include "mysql_driver.h"
36 #include "defs.h"
37 #include "memwrap.h"
38 #include "query_instructions.h"
39
40 /* global variables */
41 char *Program_Name;
42 int Verbose = 0;
43 long long Amt_Dumped = 0;
44 int Dump_Short = 0;
45
46 /* structure holding information used to connect to SQL server */
47 struct database_info {
48 char *hostname;
49 int port;
50 char *database;
51 char *user;
52 char *password;
53 };
54
55 /* structure for class */
56 struct class {
57 char *name;
58 FILE *fp;
59 char *short_name;
60 FILE *short_fp;
61 };
62
63 /* output functions which track amount of data written */
64 #define dump_putc(c,stream) (Amt_Dumped++, putc((c),(stream)))
65 void
66 dump_fputs (const char *s, FILE *stream)
/* [<][>][^][v][top][bottom][index][help] */
67 {
68 Amt_Dumped += fputs(s, stream);
69 }
70
71 /* extracts the program name from command-line arguments */
72 void
73 get_program_name (int argc, char **argv)
/* [<][>][^][v][top][bottom][index][help] */
74 {
75 char *p;
76
77 if (argc <= 0) {
78 fprintf(stderr, "ERROR: unable to determine program name\n");
79 exit(1);
80 }
81
82 p = strrchr(argv[0], '/');
83 if (p == NULL) {
84 Program_Name = argv[0];
85 } else {
86 Program_Name = p+1;
87 }
88 }
89
90 void
91 syntax ()
/* [<][>][^][v][top][bottom][index][help] */
92 {
93 fprintf(stderr,
94 "Syntax: %s [-v] [-h hostname] [-P port] [-u user] [-p password] [-s]"
95 "database\n", Program_Name);
96 }
97
98 /* exits on error */
99 void
100 parse_options (int argc, char **argv, struct database_info *db, int *dump_short)
/* [<][>][^][v][top][bottom][index][help] */
101 {
102 int opt;
103
104 /* defaults */
105 db->hostname = "localhost";
106 db->port = 0;
107 db->user = "";
108 db->password = "";
109 *dump_short = 0;
110
111 /* parse command line arguments with the ever-handy getopt() */
112 while ((opt = getopt(argc, argv, "vh:u:p:P:s")) != -1) {
113 switch (opt) {
114 case 'v':
115 Verbose++;
116 break;
117 case 'h':
118 db->hostname = optarg;
119 break;
120 case 'P':
121 db->port = atoi(optarg);
122 break;
123 case 'u':
124 db->user = optarg;
125 break;
126 case 'p':
127 db->password = optarg;
128 break;
129 case 's':
130 *dump_short = 1;
131 break;
132 case '?':
133 syntax();
134 exit(1);
135 }
136 }
137
138 /* check remaining argument count */
139 argc -= optind;
140 argv += optind;
141 if (argc != 1) {
142 syntax();
143 exit(1);
144 }
145
146 /* remaining argument should be database name */
147 db->database = argv[0];
148 }
149
150 int
151 load_classes (struct class **c)
/* [<][>][^][v][top][bottom][index][help] */
152 {
153 char* const *class_names;
154 int num_classes;
155 struct class *tmp;
156 int i;
157 char fname[64];
158
159 class_names = DF_get_class_names();
160 num_classes = 0;
161 while (class_names[num_classes] != NULL) {
162 num_classes++;
163 }
164 wr_malloc((void *)&tmp, sizeof(struct class) * num_classes);
165
166 for (i=0; i<num_classes; i++) {
167 tmp[i].name = class_names[i];
168
169 assert(strlen(tmp[i].name) < 60);
170 strcpy(fname, "db.");
171 strcat(fname, tmp[i].name);
172 tmp[i].fp = fopen(fname, "w+");
173 if (tmp[i].fp == NULL) {
174 fprintf(stderr, "%s: error opening file \"%s\"\n",
175 Program_Name, fname);
176 exit(1);
177 }
178
179 if (Dump_Short) {
180 tmp[i].short_name =
181 DF_get_class_code(DF_class_name2type(class_names[i]));
182 assert(strlen(tmp[i].short_name) < 60);
183 strcpy(fname, "db.");
184 strcat(fname, tmp[i].short_name);
185 tmp[i].short_fp = fopen(fname, "w+");
186 if (tmp[i].short_fp == NULL) {
187 fprintf(stderr, "%s: error opening file \"%s\"\n",
188 Program_Name, fname);
189 exit(1);
190 }
191 } else {
192 tmp[i].short_name = NULL;
193 tmp[i].short_fp = NULL;
194 }
195 }
196
197 *c = tmp;
198 return num_classes;
199 }
200
201 /* outputs the object to the appropriate files */
202 void
203 output_object (char *object, struct class *c, int num_classes)
/* [<][>][^][v][top][bottom][index][help] */
204 {
205 char *p;
206 int i;
207
208 p = strchr(object, ':');
209 if (p == NULL) {
210 fprintf(stderr,
211 "%s: format error in database; no colon in object, \"%s\"\n",
212 Program_Name, object);
213 exit(1);
214 }
215 *p = '\0';
216
217 for (i=0; i<num_classes; i++) {
218 if (strcmp(c[i].name, object) == 0) {
219 *p = ':';
220 dump_fputs(object, c[i].fp);
221 dump_putc('\n', c[i].fp);
222 if (Dump_Short) {
223 p = QI_fast_output(object);
224 dump_fputs(p, c[i].short_fp);
225 free(p);
226 dump_putc('\n', c[i].short_fp);
227 }
228 return;
229 }
230 }
231
232 fprintf(stderr, "%s: unknown class of object found, \"%s\"\n",
233 Program_Name, object);
234 exit(1);
235 }
236
237 void
238 seperate_time_t (int n, int *hours, int *minutes, int *seconds)
/* [<][>][^][v][top][bottom][index][help] */
239 {
240 *hours = n / (60 * 60);
241 n %= (60 * 60);
242 *minutes = n / 60;
243 n %= 60;
244 *seconds = n;
245 }
246
247 /* program entry point */
248 int
249 main (int argc, char **argv)
/* [<][>][^][v][top][bottom][index][help] */
250 {
251 struct database_info db;
252 er_ret_t ret;
253 SQ_connection_t *sql;
254 int num_classes;
255 struct class *classes;
256 SQ_result_set_t *rs;
257 SQ_row_t *row;
258 int num_object;
259 time_t start, end;
260 const struct tm *now;
261 char tmp[64];
262 double runtime;
263 int h, m, s;
264
265 /* turn off output buffering (why isn't this the default?) */
266 setbuf(stdout, NULL);
267
268 /* record our program's name for any future use */
269 get_program_name(argc, argv);
270
271 /* parse our command line */
272 parse_options(argc, argv, &db, &Dump_Short);
273 if (Verbose) {
274 printf("\n");
275 printf("Command line options\n");
276 printf(" database: %s\n", db.database);
277 printf(" hostname: %s\n", db.hostname);
278 if (db.port) {
279 printf(" port: %d\n", db.port);
280 } else {
281 printf(" port: <default>\n");
282 }
283 printf(" user: %s\n", (*db.user == '\0') ? "<default>" : db.user);
284 printf(" password: <hidden>\n");
285 printf(" dump short: %s\n", Dump_Short ? "yes" : "no");
286 }
287
288 /* connect to the server */
289
290 if (Verbose) {
291 printf("\n");
292 printf("Connecting to server...\n");
293 }
294
295 ret = SQ_try_connection(&sql,
296 db.hostname, db.port, db.database, db.user, db.password);
297 if (!NOERR(ret)) {
298 fprintf(stderr, "%s: error connecting to database; %s\n", Program_Name,
299 SQ_error(sql));
300 exit(1);
301 }
302
303 if (Verbose) {
304 printf("Connected.\n");
305 }
306
307
308 /* submit our query */
309 if (Verbose) {
310 printf("\n");
311 printf("Submitting query...\n");
312 }
313
314 if (SQ_execute_query_nostore(sql,
315 "SELECT object FROM last "
316 "WHERE (thread_id=0) AND (object_type<>100) AND (object<>\"\")",
317 &rs) != 0)
318 {
319 fprintf(stderr, "%s: error with query; %s\n", Program_Name,
320 SQ_error(sql));
321 exit(1);
322 }
323
324 if (Verbose) {
325 printf("Submitted.\n");
326 }
327
328
329 /* initialize our class information (also creates output files) */
330 num_classes = load_classes(&classes);
331
332 /* record start time */
333 time(&start);
334
335 if (Verbose) {
336 printf("\n");
337 printf("Loaded %d classes\n", num_classes);
338 printf("Created %d output files\n",
339 Dump_Short ? (num_classes * 2) : num_classes);
340 printf("\n");
341 now = localtime(&start);
342 strftime(tmp, sizeof(tmp), "Dump starting... %Y-%m-%d %H:%M:%S %Z",
343 now);
344 puts(tmp);
345 }
346
347
348 /* read our MySQL data */
349 num_object = 0;
350 while ((row = SQ_row_next(rs)) != NULL) {
351 char *object = SQ_get_column_string_nocopy(rs, row, 0);
352 output_object(object, classes, num_classes);
353 num_object++;
354 }
355
356 /* close up shop */
357 time(&end);
358
359 /* output final results, if any */
360 if (Verbose) {
361 now = localtime(&end);
362 strftime(tmp, sizeof(tmp), "Dump finished... %Y-%m-%d %H:%M:%S %Z",
363 now);
364 puts(tmp);
365 runtime = difftime(end, start);
366 seperate_time_t((int)(runtime + 0.5), &h, &m, &s);
367 printf("Wrote %d objects in %d:%02d:%02d\n", num_object, h, m, s);
368 printf(" %12.2f objects/second\n", num_object/runtime);
369 printf(" %12.2f byte/second\n", Amt_Dumped/runtime);
370 printf("\n");
371 }
372
373 /* assume that 0 outputs is an error */
374 if (num_object == 0) {
375 fprintf(stderr, "No objects dumped, exiting with error\n");
376 exit(1);
377 }
378
379 return 0;
380 }
381