source: trunk/athena/bin/discuss/server/recover.c @ 23271

Revision 23271, 11.2 KB checked in by broder, 16 years ago (diff)
Add com_err support for delete and discuss on OS X.
Line 
1/*
2 *
3 *      Copyright (C) 1988, 1989, 1991 by the Massachusetts Institute of
4 *      Technology.
5 *      Developed by the MIT Student Information Processing Board (SIPB).
6 *      For copying information, see the file mit-copyright.h in this release.
7 *
8 */
9/*
10 *
11 * recover -- program to recover a meeting from the transaction file.
12 *            this program is linked to a server so it can use the
13 *            privileged procedures of create_mtg, and the like.
14 *
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/types.h>
21#include <sys/file.h>
22#include <sys/stat.h>
23#if HAVE_FCNTL_H
24#include <fcntl.h>
25#endif
26#include <unistd.h>
27#include <discuss/types.h>
28#include <discuss/dsc_et.h>
29#include <discuss/tfile.h>
30#include <discuss/interface.h>
31#include "mtg.h"
32
33#define min(a, b) (a < b ? a : b)
34
35static trn_base tb;
36static trn_hdr th;
37static int tempf;
38static int trnf;
39static int trnfsize;
40static int num_trns;
41static int current_pos;
42static char *mtg_name, *location, *chairman, *trn_file;
43static int *trn_pos;
44static int found_eof;
45static int do_byteswap;
46static char *temp_dir = "/tmp";
47
48tfile unix_tfile ();
49static fsize(),read_trn_hdr(),read_last_trn(),save_trn();
50
51extern char rpc_caller[];
52extern int has_privs, use_zephyr;
53
54#ifndef __GNUC__
55#define inline
56#endif
57
58static inline short Sshort(P_s)
59        short   P_s;
60{
61    union {
62        short s;
63        char c[2];
64    } x1, x2;
65    x1.s = P_s;
66    x2.c[0] = x1.c[1];
67    x2.c[1] = x1.c[0];
68    return x2.s;
69}
70
71static inline long Slong(P_l)
72        long    P_l;
73{
74    union {
75        long l;
76        char c[4];
77    } x1, x2;
78    x1.l = P_l;
79    x2.c[0] = x1.c[3];
80    x2.c[1] = x1.c[2];
81    x2.c[2] = x1.c[1];
82    x2.c[3] = x1.c[0];
83    return x2.l;
84}
85
86#define S(X) \
87    (sizeof(X)==4               \
88     ? (X = Slong(X))           \
89     : (sizeof(X)==2            \
90        ? (X = Sshort(X))       \
91        : (sizeof(X)==1         \
92           ? 0                  \
93           : abort())))
94
95main (argc, argv)
96int argc;
97char **argv;
98{
99     int i;
100
101     has_privs = TRUE;
102     use_zephyr = 0;
103
104#if defined(__APPLE__) && defined(__MACH__)
105     add_error_table(&et_dsc_error_table);
106#else
107     initialize_dsc_error_table();
108#endif
109
110     for (i = 1; i < argc; i++) {
111          if (*argv[i] == '-') switch (argv[i][1]) {
112          case 'c':
113               if (++i < argc)
114                    chairman = argv[i];
115               continue;
116
117          case 'n':
118               if (++i < argc)
119                    mtg_name = argv[i];
120               continue;
121
122           case 't':
123               if (++i < argc)
124                   temp_dir = argv[i];
125               continue;
126
127          default:
128               goto lusage;
129          }
130          if (trn_file == NULL)
131               trn_file = argv[i];
132          else if (location == NULL)
133               location = argv[i];
134          else goto lusage;
135     }
136
137     if (trn_file == NULL || location == NULL)
138          goto lusage;                                  /* required */
139
140     if ((trnf = open (trn_file, O_RDONLY, 0)) < 0) {
141          fprintf (stderr, "Can't open transaction file %s\n", trn_file);
142          exit(1);
143     }
144
145     trnfsize = fsize (trnf);
146     read_header();                             /* check meeting */
147
148
149     /* search for last transaction, which gives us our best toehold into
150        the meeting.  This is done by searching from the end of the meeting
151        for unique. */
152     read_last_trn();                           /* read last_trn into th */
153
154     trn_pos = (int *) malloc (sizeof(int) * th.current);
155     if (trn_pos == NULL) {
156          fprintf (stderr, "Can't allocate memory for transaction positions\n");
157          exit(1);
158     }
159
160     /* zero out array */
161     num_trns = th.current;
162     for (i = 0; i <= num_trns; i++) {
163          trn_pos[i] = 0;
164     }
165
166     /* loop to fill out transaction position array */
167     while (current_pos != 0) {
168          read_trn_hdr (current_pos);
169          trn_pos [th.current] = current_pos;
170
171          current_pos = th.prev_trn;
172     }
173
174     create_temp();
175
176     for (i = 1; i <= num_trns; i++) {
177          if (trn_pos [i] != 0)
178               save_trn (trn_pos [i]);
179          else {
180               int result;
181
182               expunge_trn(location, i, &result);
183               if (result != 0) {
184                    fprintf(stderr, "Error expunging transaction [%04d]: %s\n", i, error_message(result));
185                    exit(1);
186               }
187          }
188     }
189
190     exit (0);
191
192lusage:
193     fprintf(stderr, "usage: recover trn_file mtg_name {-c chairman} {-n name}\n");
194     exit (1);
195}
196
197read_header()
198{
199     int result;
200     int pos;
201
202     lseek(trnf,0,SEEK_SET);                            /* rewind file */
203     if (read (trnf, &tb, sizeof (trn_base)) < sizeof (trn_base)) {
204          fprintf (stderr, "Can't read trn_base\n");
205          exit(1);
206     }
207
208     if (tb.unique != TRN_BASE_UNIQUE) {
209             /*
210              * Try byte swapping the arguments before giving up.
211              */
212             S(tb.unique);
213             if (tb.unique == TRN_BASE_UNIQUE)
214                     do_byteswap++;
215             else {
216                     fprintf (stderr, "Invalid trn_base unique\n");
217                     exit(1);
218             }
219     }
220
221     if (do_byteswap) {
222             S(tb.version);
223             S(tb.date_created);
224             S(tb.long_name_addr);
225             S(tb.chairman_addr);
226             S(tb.long_name_len);
227             S(tb.chairman_len);
228             S(tb.public_flag);
229     }
230             
231     if (tb.version != TRN_BASE_1) {
232          fprintf (stderr, "Invalid trn_base version\n");
233          exit(1);
234     }
235
236     /* read the chairman */
237     if (chairman == NULL) {
238          if (tb.chairman_len > 255) {
239               fprintf (stderr, "Unreasonable chairman length: %d\n",
240                        tb.chairman_len);
241               exit(1);
242          }
243          chairman = malloc (tb.chairman_len);
244          if (lseek(trnf, tb.chairman_addr, SEEK_SET) < 0) {
245no_chairman:
246               fprintf (stderr, "Can't read chairman\n");
247               exit(1);
248          }
249         
250          if (read (trnf, chairman, tb.chairman_len) < tb.chairman_len)
251               goto no_chairman;
252     }
253         
254     /* read the long name */
255     if (mtg_name == NULL) {
256          if (tb.long_name_len > 255) {
257               fprintf (stderr, "Unreasonable long_name length\n");
258               exit(1);
259          }
260          mtg_name = malloc (tb.long_name_len);
261          if (lseek(trnf, tb.long_name_addr, SEEK_SET) < 0) {
262no_long_name:
263               fprintf (stderr, "Can't read long_name\n");
264               exit(1);
265          }
266         
267          if (read (trnf, mtg_name, tb.long_name_len) < tb.long_name_len)
268               goto no_long_name;
269     }
270
271     strcpy (rpc_caller, chairman);
272     /* got the params, now create the meeting */
273     create_mtg_priv (location, mtg_name, tb.public_flag, tb.date_created, chairman, NULL, &result);
274     if (result != 0) {
275          fprintf (stderr, "Couldn't create meeting, %s", error_message(result));
276          exit(1);
277     }
278
279     pos = sizeof (tb) + tb.long_name_len + tb.chairman_len;
280     if (pos == trnfsize) {
281          fprintf (stderr, "Empty meeting\n");
282          exit (0);
283     }
284}
285
286/*
287 *
288 * read_trn_hdr () -- Procedure to read a transaction header, erroring out
289 *                    if not kosher.
290 *
291 */
292static
293read_trn_hdr (position)
294int position;
295{
296     if (lseek (trnf, position, SEEK_SET) < 0) {
297no_read:
298          fprintf (stderr, "Can't find transaction at %d\n", position);
299          exit (1);
300     }
301
302     if (read (trnf, &th, sizeof (th)) != sizeof (th))
303          goto no_read;
304
305     if (do_byteswap) {
306             S(th.version);
307             S(th.unique);
308             S(th.current);
309             S(th.orig_pref);
310             S(th.date_entered);
311             S(th.num_lines);
312             S(th.num_chars);
313             S(th.prev_trn);
314             S(th.subject_addr);
315             S(th.author_addr);
316             S(th.text_addr);
317             S(th.subject_len);
318             S(th.author_len);
319     }
320     
321     /* safety checks */
322     if (th.version != TRN_HDR_1) {
323          fprintf (stderr, "Invalid trn_hdr version at %d\n", position);
324          exit(1);
325     }
326
327     if (th.unique != TRN_HDR_UNIQUE) {
328          fprintf (stderr, "Invalid trn_hdr unique\n");
329          exit(1);
330     }
331
332     if (th.current <= 0 || th.author_len < 0 || th.subject_len < 0 || th.num_chars < 0 || th.num_lines < 0) {
333          fprintf (stderr, "Negative number\n");
334          exit(1);
335     }
336
337     if (th.author_addr+th.author_len > trnfsize || th.subject_addr+th.subject_len > trnfsize || th.text_addr+th.num_chars > trnfsize) {
338          fprintf (stderr, "Field past file\n");
339          exit(1);
340     }
341
342     return;
343}
344/*
345 *
346 * maybe_read_trn_hdr -- procedure to try to read a transaction header,
347 *                       returning true if successful.
348 *
349 */
350static
351maybe_read_trn_hdr(position)
352int position;
353{
354     if (lseek (trnf, position, SEEK_SET) < 0) {
355          return (FALSE);
356     }
357
358     if (read (trnf, &th, sizeof (th)) != sizeof (th))
359          return (FALSE);
360
361     if (do_byteswap) {
362             S(th.version);
363             S(th.unique);
364             S(th.current);
365             S(th.orig_pref);
366             S(th.date_entered);
367             S(th.num_lines);
368             S(th.num_chars);
369             S(th.prev_trn);
370             S(th.subject_addr);
371             S(th.author_addr);
372             S(th.text_addr);
373             S(th.subject_len);
374             S(th.author_len);
375     }       
376     
377     /* safety checks */
378     if (th.version != TRN_HDR_1) {
379          return (FALSE);
380     }
381
382     if (th.unique != TRN_HDR_UNIQUE) {
383          return (FALSE);
384     }
385
386     if (th.current <= 0 || th.author_len < 0 || th.subject_len < 0 || th.num_chars < 0 || th.num_lines < 0) {
387          return (FALSE);
388     }
389
390     if (th.author_addr+th.author_len > trnfsize || th.subject_addr+th.subject_len > trnfsize || th.text_addr+th.num_chars > trnfsize) {
391          return (FALSE);
392     }
393
394     return (TRUE);
395}
396
397/*
398 *
399 * read_last_trn -- brute force routine to just try reading transactions until
400 *                  get a success.
401 *
402 */
403static
404read_last_trn ()
405{
406     current_pos = trnfsize - sizeof (th) - 2;
407
408     while (current_pos > sizeof (tb)) {
409          if (maybe_read_trn_hdr (current_pos))
410               return;
411          current_pos--;
412     }
413}
414
415static
416save_trn (position)
417int position;
418{
419     char *th_subject, *th_author, *th_signature;
420     tfile tf;
421     int tfs,tocopy;
422     trn_nums result_trn;
423     int result;
424     char buffer[512];
425
426     read_trn_hdr (position);
427
428     th_subject = malloc (th.subject_len);
429     lseek (trnf, th.subject_addr, SEEK_SET);
430     read (trnf, th_subject, th.subject_len);
431         
432     th_author = malloc (th.author_len);
433     lseek (trnf, th.author_addr, SEEK_SET);
434     read (trnf, th_author, th.author_len);
435
436     th_signature = NULL;
437     if (strlen (th_author) + 1 != th.author_len) {
438          th_signature = th_author + strlen(th_author) + 1;
439     }
440
441     /* start temp file */
442     ftruncate(tempf,0);
443     lseek(tempf,0,SEEK_SET);
444
445     lseek(trnf, th.text_addr, SEEK_SET);
446     tfs = th.num_chars;
447     while (tfs > 0) {
448          tocopy = min (512, tfs);
449          read (trnf, buffer, tocopy);
450          write (tempf, buffer, tocopy);
451          tfs -= tocopy;
452     }
453
454     lseek(tempf,0,SEEK_SET);
455
456     tf = unix_tfile (tempf);
457
458     add_trn_priv (location, tf, th_subject, th_signature, th.orig_pref, th.current, th_author, th.date_entered, 0, &result_trn, &result);
459     if (result != 0) {
460          fprintf (stderr, "Couldn't add transaction %d; %s", th.current, error_message(result));
461          exit(1);
462     }
463
464     free(th_author);
465     free(th_subject);
466     tdestroy (tf);
467     printf ("Added transaction %d\n", th.current);
468     return;
469}
470
471/*
472 *
473 * fsize () -- Routine to find out the size of a file.
474 *
475 */
476static
477fsize (d)
478int d;
479{
480     struct stat buf;
481
482     if (fstat (d, &buf) < 0)
483          return (0);
484
485     return (buf.st_size);
486}
487
488/*
489 *
490 * new_string (s)  --   Routine to create a copy of the given string, using
491 *                      malloc.
492 *
493 */
494static
495char *new_string (s)
496char *s;
497{
498     int len;
499     char *newstr;
500
501     len = strlen (s) + 1;
502     newstr = malloc (len);
503     strcpy (newstr, s);
504     return (newstr);
505}
506
507/*
508 *
509 * create_temp () -- Create temp file, and let it be tempf.
510 *
511 */
512create_temp()
513{
514     char *filename;
515
516     filename = malloc (strlen (temp_dir) + 10);
517     strcpy (filename, temp_dir);
518     strcat (filename, "/rcXXXXXX");
519     mktemp (filename);
520
521     tempf = open (filename, O_RDWR | O_CREAT, 0700);
522     if (tempf < 0) {
523          fprintf (stderr, "Cannot open temp file `%s'\n", filename);
524          exit (1);
525     }
526}
Note: See TracBrowser for help on using the repository browser.