[6956] | 1 | /* |
---|
| 2 | * |
---|
| 3 | * expunge -- program to expunge a meeting; i.e. really delete those |
---|
| 4 | * deleted transaction. This program is linked to a server |
---|
| 5 | * so it can use the privileged procedure of create_mtg, and |
---|
| 6 | * the like. |
---|
| 7 | * |
---|
| 8 | */ |
---|
| 9 | |
---|
| 10 | #include <stdio.h> |
---|
| 11 | #include <strings.h> |
---|
| 12 | #include <sys/types.h> |
---|
| 13 | #include <sys/file.h> |
---|
| 14 | #include <sys/stat.h> |
---|
[17452] | 15 | #include <unistd.h> |
---|
[6956] | 16 | |
---|
| 17 | #include <discuss/types.h> |
---|
| 18 | #include <discuss/dsc_et.h> |
---|
| 19 | #include <discuss/tfile.h> |
---|
| 20 | #include <discuss/interface.h> |
---|
| 21 | #include <discuss/acl.h> |
---|
| 22 | #include "mtg.h" |
---|
| 23 | |
---|
| 24 | #define NULL 0 |
---|
| 25 | #define MAX_TRNS 1000 |
---|
| 26 | #define min(a, b) (a < b ? a : b) |
---|
| 27 | |
---|
| 28 | static int tempf; |
---|
| 29 | static char *mtg_name = NULL, *location = NULL, *chairman = NULL, *trn_file = NULL; |
---|
| 30 | static char *backup_location = NULL; |
---|
| 31 | static char *future_location = NULL; |
---|
| 32 | static int found_eof = 0; |
---|
| 33 | static int error_occurred = 0; |
---|
| 34 | |
---|
| 35 | tfile unix_tfile (); |
---|
| 36 | char *malloc(); |
---|
| 37 | |
---|
| 38 | extern char rpc_caller[]; |
---|
| 39 | extern int has_privs; |
---|
| 40 | extern int errno; |
---|
| 41 | extern int no_nuke; |
---|
| 42 | |
---|
| 43 | main (argc, argv) |
---|
| 44 | int argc; |
---|
| 45 | char **argv; |
---|
| 46 | { |
---|
| 47 | int i,n,low,high; |
---|
| 48 | mtg_info old_mtg_info,new_mtg_info; |
---|
| 49 | trn_info old_trn_info; |
---|
| 50 | int result; |
---|
| 51 | dsc_acl *acl_list,*new_acl_list; |
---|
| 52 | dsc_acl_entry *ae; |
---|
| 53 | char *new_modes; |
---|
| 54 | tfile tf; |
---|
| 55 | char control_name[256]; |
---|
| 56 | int control_fd; |
---|
| 57 | |
---|
[23271] | 58 | #if defined(__APPLE__) && defined(__MACH__) |
---|
| 59 | add_error_table(&et_dsc_error_table); |
---|
| 60 | #else |
---|
[22864] | 61 | initialize_dsc_error_table(); |
---|
[23271] | 62 | #endif |
---|
[6956] | 63 | |
---|
| 64 | for (i = 1; i < argc; i++) { |
---|
| 65 | if (*argv[i] == '-') switch (argv[i][1]) { |
---|
| 66 | case 'c': |
---|
| 67 | if (++i < argc) |
---|
| 68 | chairman = argv[i]; |
---|
| 69 | continue; |
---|
| 70 | |
---|
| 71 | case 'n': |
---|
| 72 | if (++i < argc) |
---|
| 73 | mtg_name = argv[i]; |
---|
| 74 | continue; |
---|
| 75 | |
---|
| 76 | default: |
---|
| 77 | goto lusage; |
---|
| 78 | } |
---|
| 79 | if (location == NULL) |
---|
| 80 | location = argv[i]; |
---|
| 81 | else goto lusage; |
---|
| 82 | } |
---|
| 83 | |
---|
| 84 | if (location == NULL) |
---|
| 85 | goto lusage; /* required */ |
---|
| 86 | |
---|
| 87 | has_privs = TRUE; /* Tell discuss we're special */ |
---|
| 88 | strcpy (rpc_caller, "expunger"); |
---|
| 89 | |
---|
| 90 | /* First, we get the mtg info to make sure it exists */ |
---|
| 91 | get_mtg_info (location, &old_mtg_info, &result); |
---|
| 92 | if (result != 0) { |
---|
| 93 | fprintf(stderr, "%s: %s while getting mtg info\n", location, error_message(result)); |
---|
| 94 | exit (1); |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | get_acl (location, &result, &acl_list); |
---|
| 98 | if (result != 0) { |
---|
| 99 | fprintf(stderr, "%s: %s while getting acl\n", location, error_message(result)); |
---|
| 100 | exit (1); |
---|
| 101 | } |
---|
| 102 | |
---|
| 103 | /* Create the new meeting */ |
---|
| 104 | backup_location = malloc (strlen(location)+5); /* be generous */ |
---|
| 105 | strcpy (backup_location, location); |
---|
| 106 | strcat (backup_location, "~"); |
---|
| 107 | |
---|
| 108 | future_location = malloc (strlen(location)+5); /* be generous */ |
---|
| 109 | strcpy (future_location, location); |
---|
| 110 | strcat (future_location, "#"); |
---|
| 111 | |
---|
| 112 | printf("Creating new meeting\n"); |
---|
| 113 | fflush(stdout); |
---|
| 114 | |
---|
| 115 | if (mtg_name == NULL) { |
---|
| 116 | mtg_name = old_mtg_info.long_name; |
---|
| 117 | } |
---|
| 118 | if (chairman == NULL) { |
---|
| 119 | chairman = old_mtg_info.chairman; |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | /* get acl's on old meeting, so we can make it new one */ |
---|
| 123 | get_acl (location, &result, &new_acl_list); |
---|
| 124 | if (result != 0) { |
---|
| 125 | fprintf(stderr, "%s: %s while getting acl\n", backup_location, error_message(result)); |
---|
| 126 | exit (1); |
---|
| 127 | } |
---|
| 128 | |
---|
| 129 | create_mtg_priv (backup_location, mtg_name, old_mtg_info.public_flag, |
---|
| 130 | old_mtg_info.date_created, chairman, |
---|
| 131 | new_acl_list, &result); |
---|
| 132 | if (result != 0) { |
---|
| 133 | fprintf (stderr, "%s: %s while creating new meeting\n", |
---|
| 134 | location, error_message(result)); |
---|
| 135 | exit (1); |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | /* now, do the actual expunging */ |
---|
| 139 | low = old_mtg_info.lowest; |
---|
| 140 | high = old_mtg_info.highest; |
---|
| 141 | create_temp (); |
---|
| 142 | |
---|
| 143 | expunge_range: |
---|
| 144 | for (i = low; i <= high; i++) { |
---|
| 145 | get_trn_info (location, i, &old_trn_info, &result); |
---|
| 146 | if (result != 0 && result != DELETED_TRN && result != EXPUNGED_TRN) { |
---|
| 147 | fprintf(stderr, |
---|
| 148 | "Error getting info for transaction [%04d]: %s\n", |
---|
| 149 | i, error_message(result)); |
---|
| 150 | error_occurred = TRUE; |
---|
| 151 | } else if (result != 0) { /* expunge it */ |
---|
| 152 | no_nuke = TRUE; |
---|
| 153 | printf("Expunging transaction [%04d]\n", i); |
---|
| 154 | expunge_trn (backup_location, i, &result); |
---|
| 155 | no_nuke = FALSE; |
---|
| 156 | if (result != 0) { |
---|
| 157 | fprintf(stderr, |
---|
| 158 | "Error expunging transaction [%04d]: %s\n", |
---|
| 159 | i, error_message(result)); |
---|
| 160 | error_occurred = TRUE; |
---|
| 161 | } |
---|
| 162 | } else if (result == 0) { |
---|
| 163 | ftruncate(tempf,0); |
---|
[17452] | 164 | lseek(tempf,0,SEEK_SET); |
---|
[6956] | 165 | tf = unix_tfile (tempf); |
---|
| 166 | |
---|
| 167 | get_trn (location, i, tf, &result); |
---|
| 168 | if (result != 0) { |
---|
| 169 | fprintf(stderr, "Error getting transaction [%04d]: %s\n", |
---|
| 170 | i, error_message(result)); |
---|
| 171 | error_occurred = TRUE; |
---|
| 172 | free(old_trn_info. author); |
---|
| 173 | free(old_trn_info.subject); |
---|
| 174 | continue; |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | tdestroy (tf); |
---|
[17452] | 178 | lseek(tempf,0,SEEK_SET); |
---|
[6956] | 179 | |
---|
| 180 | tf = unix_tfile (tempf); |
---|
| 181 | no_nuke = TRUE; |
---|
| 182 | add_trn_priv (backup_location, tf, old_trn_info.subject, |
---|
| 183 | old_trn_info.pref, old_trn_info.current, |
---|
| 184 | old_trn_info.author, old_trn_info.date_entered, |
---|
| 185 | &n, &result); |
---|
| 186 | no_nuke = FALSE; |
---|
| 187 | if (result != 0) { |
---|
| 188 | fprintf(stderr, |
---|
| 189 | "Error getting info for transaction %d: %s\n", i, |
---|
| 190 | error_message(result)); |
---|
| 191 | error_occurred = TRUE; |
---|
| 192 | } |
---|
| 193 | free(old_trn_info.author); |
---|
| 194 | free(old_trn_info.subject); |
---|
| 195 | } |
---|
| 196 | } |
---|
| 197 | |
---|
| 198 | /* Check if any new transactions have been added */ |
---|
| 199 | free(old_mtg_info.long_name); |
---|
| 200 | free(old_mtg_info.chairman); |
---|
| 201 | free(old_mtg_info.location); |
---|
| 202 | get_mtg_info(location, &old_mtg_info, &result); |
---|
| 203 | if (result != 0) { |
---|
| 204 | fprintf(stderr, "%s: %s while getting mtg info\n", location, error_message(result)); |
---|
| 205 | error_occurred = TRUE; |
---|
| 206 | } else if (old_mtg_info.highest > high) { /* New transactions added */ |
---|
| 207 | low = high+1; |
---|
| 208 | high = old_mtg_info.highest; |
---|
| 209 | goto expunge_range; |
---|
| 210 | } |
---|
| 211 | |
---|
| 212 | strcpy(control_name, location); |
---|
| 213 | strcat(control_name, "/control"); |
---|
| 214 | if ((control_fd = open (control_name, O_RDWR, 0700)) < 0) { |
---|
| 215 | error_occurred = TRUE; |
---|
| 216 | } else { |
---|
| 217 | flock(control_fd, LOCK_EX); /* Hold meeting by the balls */ |
---|
| 218 | free(old_mtg_info.long_name); |
---|
| 219 | free(old_mtg_info.chairman); |
---|
| 220 | free(old_mtg_info.location); |
---|
| 221 | |
---|
| 222 | no_nuke = TRUE; |
---|
| 223 | get_mtg_info(location, &old_mtg_info, &result); |
---|
| 224 | if (result != 0) { |
---|
| 225 | fprintf(stderr, "%s: %s while getting mtg info\n", location, error_message(result)); |
---|
| 226 | error_occurred = TRUE; |
---|
| 227 | flock(control_fd,LOCK_UN); |
---|
| 228 | close(control_fd); |
---|
| 229 | } else if (old_mtg_info.highest > high) { /* New transactions added */ |
---|
| 230 | low = high + 1; |
---|
| 231 | high = old_mtg_info.highest; |
---|
| 232 | flock(control_fd,LOCK_UN); |
---|
| 233 | close(control_fd); |
---|
| 234 | goto expunge_range; |
---|
| 235 | } |
---|
| 236 | } |
---|
| 237 | |
---|
| 238 | /* When we get here, we have the old meeting locked. Now we do the move |
---|
| 239 | as atomically as we can */ |
---|
| 240 | if (!error_occurred) { |
---|
| 241 | if (rename(location, future_location) < 0) { |
---|
| 242 | perror("rename of old meeting failed"); |
---|
| 243 | exit (1); |
---|
| 244 | } |
---|
| 245 | if (rename(backup_location, location) < 0) { |
---|
| 246 | perror("rename of new meeting"); |
---|
| 247 | exit (1); |
---|
| 248 | } |
---|
| 249 | remove_mtg (future_location, &result); |
---|
| 250 | if (result != 0) { |
---|
| 251 | fprintf(stderr, "%s: %s while removing new meeting.\n", |
---|
| 252 | location, error_message(result)); |
---|
| 253 | exit (1); |
---|
| 254 | } |
---|
| 255 | } else exit (1); /* error occurred */ |
---|
| 256 | |
---|
| 257 | exit (0); |
---|
| 258 | |
---|
| 259 | lusage: |
---|
| 260 | fprintf(stderr, "usage: expunge mtg_location {-c chairman} {-n name}\n"); |
---|
| 261 | exit (1); |
---|
| 262 | } |
---|
| 263 | |
---|
| 264 | /* |
---|
| 265 | * |
---|
| 266 | * create_temp () -- Create temp file, and let it be tempf. |
---|
| 267 | * |
---|
| 268 | */ |
---|
| 269 | create_temp() |
---|
| 270 | { |
---|
| 271 | char filename [20]; |
---|
| 272 | |
---|
| 273 | strcpy (filename, "/tmp/rcXXXXXX"); |
---|
| 274 | mktemp (filename); |
---|
| 275 | |
---|
| 276 | tempf = open (filename, O_RDWR | O_CREAT, 0700); |
---|
| 277 | if (tempf < 0) { |
---|
| 278 | fprintf (stderr, "Cannot open temp file\n"); |
---|
| 279 | exit (1); |
---|
| 280 | } |
---|
| 281 | } |
---|
| 282 | |
---|
| 283 | |
---|