]> andersk Git - moira.git/blob - afssync/resync.qc
Used /bin/sh format instead of /bin/csh format, by accident.
[moira.git] / afssync / resync.qc
1 /* $Header$
2  *
3  */
4
5 #include <mit-copyright.h>
6 #include <stdio.h>
7 #include <sys/file.h>
8 #include <rx/xdr.h>
9 #include <afs/ptint.h>
10 #include <afs/ptserver.h>
11 #include <afs/pterror.h>
12 #include <moira.h>
13 #include <moira_site.h>
14 #include <ctype.h>
15
16
17 #define min(x,y)        ((x) < (y) ? (x) : (y))
18 #define abs(x)          (((x) > 0) ? (x) : -(x))
19 struct hash *users, *groups, *usersid, *groupsid;
20 char *whoami = "sync";
21
22 char *malloc(), *strsave(), *perm_malloc();
23 int dbase_fd;
24 int replaceflag = 0;
25 struct prheader prh;
26
27
28 main(argc, argv)
29 int argc;
30 char **argv;
31 {
32     int i;
33     char *file = NULL;
34     int ingerr();
35
36     for (i = 1; i < argc; i++) {
37         if (argv[i][0] == '-') {
38             switch (argv[i][1]) {
39             case 'r':
40                 replaceflag++;
41                 break;
42             default:
43                 usage(argv[0]);
44             }
45         } else {
46             if (file == NULL)
47               file = argv[i];
48             else
49               usage(argv[0]);
50         }
51     }
52
53     i = O_RDONLY;
54     if (replaceflag)
55       i = O_RDWR;
56     dbase_fd = open(file, i, 0660);
57     if (dbase_fd < 0) {
58         perror("opening file %s", file);
59         exit(1);
60     }   
61     IIseterr(ingerr);
62     initialize_sms_error_table ();
63
64 ##  ingres sms
65 ##  set lockmode session where level = table
66 ##  begin transaction
67
68     get_users();
69     get_groups();
70     get_members();
71
72 ##  end transaction
73 ##  exit
74
75     pr_Read(NULL, 0, 0, &prh, sizeof(prh));
76     check_users_and_groups();
77
78     exit(MR_SUCCESS);
79 }
80
81 usage(name)
82 char *name;
83 {
84     fprintf(stderr, "usage: %s [-r] dbfile\n", name);
85     exit(MR_ARGS);
86 }
87
88
89 /*
90  * ingerr: (supposedly) called when Ingres indicates an error.
91  * I have not yet been able to get this to work to intercept a
92  * database open error.
93  */
94 #define INGRES_DEADLOCK 4700
95
96 static int ingerr(num)
97     int *num;
98 {
99     char buf[256];
100     int ingres_errno;
101
102     switch (*num) {
103     case INGRES_DEADLOCK:
104         ingres_errno = MR_DEADLOCK;
105         break;
106     default:
107         ingres_errno = MR_INGRES_ERR;
108     }
109     com_err(whoami, MR_INGRES_ERR, " code %d\n", *num);
110     exit(ingres_errno);
111 }
112
113
114 prserror(status, msg, arg1, arg2)
115 int status;
116 char *msg;
117 unsigned long arg1, arg2;
118 {
119     char buf[512];
120
121     sprintf(buf, msg, arg1, arg2);
122     switch (status) {
123     case PREXIST:
124         msg = "name already exists";
125         break;
126     case PRIDEXIST:
127         msg = "ID already exists";
128         break;
129     case PRNOIDS:
130         msg = "no IDs available";
131         break;
132     case PRDBFAIL:
133         msg = "database failed";
134         break;
135     case PRNOENT:
136         msg = "no space left in database";
137         break;
138     case PRPERM:
139         msg = "permission denied";
140         break;
141     case PRNOTGROUP:
142         msg = "not a group";
143         break;
144     case PRNOTUSER:
145         msg = "not a user";
146         break;
147     case PRBADNAM:
148         msg = "bad name";
149         break;
150     case 0:
151         msg = "no error";
152         break;
153     default:
154         msg = "unknown code";
155         break;
156     }
157     fprintf(stderr, "%s (%d): %s\n", msg, status, buf);
158 }
159
160
161 nomem(msg)
162 char *msg;
163 {
164     fprintf(stderr, "Out of memory: %s\n", msg);
165     exit(1);
166 }
167
168
169 struct user {
170     char login[9];
171     char flag;
172     short uid;
173 };
174
175
176 get_users()
177 ##{
178 ##  char login[9];
179 ##  int uid, id;
180     struct user *u;
181
182     fprintf(stderr, "Loading users from Moira\n");
183     users = create_hash(10000);
184     usersid = create_hash(10000);
185 ##  range of u is users
186 ##  retrieve (login = u.#login, uid = u.#uid, id = u.users_id)
187 ##      where u.#status = 1 {
188             strtrim(login);
189             u = (struct user *)perm_malloc(sizeof(struct user));
190             if (u == NULL)
191               nomem("loading users");
192             strncpy(u->login, login, 9);
193             u->flag = 0;
194             u->uid = uid;
195             hash_store(users, uid, u);
196             hash_store(usersid, id, u);
197 ##  }
198 ##}
199
200
201 #define CHUNKSIZE 5
202 struct chunk {
203     short member[CHUNKSIZE];
204     struct chunk *xmem;
205 };
206
207 struct group {
208     char name[33];
209     char flag;
210     short gid;
211     short members;
212     struct chunk ch;
213 };
214
215
216 get_groups()
217 ##{
218 ##  char name[33];
219 ##  int gid, id;
220     struct group *g;
221
222     fprintf(stderr, "Loading groups from Moira\n");
223     groups = create_hash(10000);
224     groupsid = create_hash(10000);
225 ##  range of l is list
226 ##  retrieve (name = l.#name, gid = l.#gid, id = l.list_id)
227 ##      where l.#active = 1 and l.#group = 1 {
228             strtrim(name);
229             g = (struct group *)perm_malloc(sizeof(struct group));
230             if (g == NULL)
231               nomem("loading groups");
232             bzero(g, sizeof(struct group));
233             strncpy(g->name, name, 33);
234             g->gid = gid;
235             hash_store(groups, gid, g);
236             hash_store(groupsid, id, g);
237 ##  }
238 ##}
239
240
241 get_members()
242 ##{
243     struct user *u;
244     struct group *g;
245 ##  int id, lid;
246
247     fprintf(stderr, "Fetching members from Moira\n");
248
249 ##  range of m is imembers
250
251 ##  retrieve (lid = m.list_id, id = m.member_id)
252 ##      where m.member_type = "USER" {
253       if ((u = (struct user *) hash_lookup(usersid, id)) &&
254           (g = (struct group *) hash_lookup(groupsid, lid))) {
255           if (g->members < CHUNKSIZE) {
256               g->ch.member[g->members] = u->uid;
257           } else {
258               int i = g->members - CHUNKSIZE;
259               struct chunk *c;
260
261               if ((c = g->ch.xmem) == NULL) {
262                   c = (struct chunk *) perm_malloc(sizeof(struct chunk));
263                   if (c == NULL)
264                     nomem("loading members");
265                   g->ch.xmem = c;
266               }
267               while (i >= CHUNKSIZE) {
268                   i -= CHUNKSIZE;
269                   if (c->xmem == NULL) {
270                       c->xmem = (struct chunk *) perm_malloc(sizeof(struct chunk));
271                       if (c->xmem == NULL)
272                         nomem("loading members");
273                   }
274                   c = c->xmem;
275               }
276               c->member[i] = u->uid;
277           }
278           g->members++;
279       }
280 ##  }
281
282 ##}
283
284
285
286 checkuser(id, u)
287 int id;
288 struct user *u;
289 {
290     int status;
291
292     if (u->flag == 0) {
293         printf("< User %s id %d is in Moira but not in prs\n",
294                u->login, u->uid);
295         if (replaceflag) {
296             status = PR_INewEntry(NULL, u->login, u->uid, 0);
297             if (status) {
298                 prserror(status, "adding user %s uid %d to prs database",
299                          u->login, u->uid);
300             }
301         }
302     }
303 }
304
305 checkgroup(id, g)
306 int id;
307 struct group *g;
308 {
309     register int i, j, status;
310     struct chunk *c;
311
312     if (g->flag == 0) {
313         printf("< Group %s id %d is in Moira but not in prs\n",
314                g->name, g->gid);
315         if (replaceflag) {
316             char namebuf[64];
317             sprintf(namebuf, "system:%s", g->name);
318             status = PR_INewEntry(NULL, namebuf, -g->gid, SYSADMINID);
319             if (status)
320               prserror(status, "adding list %s gid %d to prs database",
321                        namebuf, -g->gid);
322         }
323     }
324     c = (struct chunk *)&(g->ch);
325     for (i = 0; i < g->members; i++) {
326         j = i % CHUNKSIZE;
327         printf("< Group %s contains user %d in Moira but not in prs\n",
328                g->name, c->member[j]);
329         if (replaceflag) {
330             status = PR_AddToGroup(NULL, c->member[j], -g->gid);
331             if (status)
332               prserror(status, "adding %d to group %d in prs",
333                        c->member[j], -g->gid);
334         }
335         if (j == CHUNKSIZE - 1)
336           c = c->xmem;
337     }
338 }
339
340 check_users_and_groups()
341 {
342     register int i;
343     int offset;
344
345     fprintf(stderr, "Scanning PRS database\n");
346
347     for (i = 0; i < HASHSIZE; i++) {
348         offset = ntohl(prh.idHash[i]);
349         while (offset)
350           offset = check_entry(offset);
351     }
352     hash_step(users, checkuser, NULL);
353     hash_step(groups, checkgroup, NULL);
354 }
355
356 check_entry(offset)
357 int offset;
358 {
359     struct prentry entry;
360     int flags, id, status;
361     struct user *u;
362     struct group *g;
363
364     status = pr_Read(NULL, 0, offset, &entry, sizeof(entry));
365     if (status)
366       prserror(status, "reading prentry at %d", offset, 0);
367     flags = ntohl(entry.flags);
368     id = ntohl(entry.id);
369     if ((flags & PRFREE) == 0) {
370         if (flags & PRGRP) {
371             g = (struct group *) hash_lookup(groups, abs(id));
372             if (g == NULL) {
373                 if (!strncmp(entry.name, "system:", 7)) {
374                     printf("> Group %s, id %d is in prs but not moira\n",
375                            entry.name, id);
376                     if (replaceflag) {
377                         status = PR_Delete(NULL, id);
378                         if (status)
379                           prserror(status, "deleting group %d from prs", id);
380                     }
381                 }
382             } else if (strcasecmp(g->name, index(entry.name, ':')+1)) {
383                 printf("> GID %d in prs is %s, but GID %d in moira is %s\n",
384                        id, entry.name, -id, g->name);
385                 if (replaceflag) {
386                     printf("*** Dont' know how to fix this!!!!!\n");
387                 }
388             } else {
389                 g->flag = 1;
390                 if (entry.entries[0])
391                   do_members(&entry, g);
392             }
393         } else {
394             u = (struct user *) hash_lookup(users, abs(id));
395             if (u == NULL) {
396                 printf("> User %s, id %d is in prs but not moira\n",
397                        entry.name, id);
398                 if (replaceflag) {
399                     status = PR_Delete(NULL, id);
400                     if (status)
401                       prserror(status, "while deleting user %d from prs", id);
402                 }
403             } else if (strcasecmp(u->login, entry.name)) {
404                 printf("> User id %d in prs is %s, but UID %d in moira is %s\n",
405                        id, entry.name, id, u->login);
406                 if (replaceflag) {
407                     printf("*** don't know how to fix this!!!!!\n");
408                 }
409             } else
410               u->flag = 1;
411         }
412     }
413     return(ntohl(entry.nextID));
414 }
415
416
417 do_members(e, g)
418 struct prentry *e;
419 struct group *g;
420 {
421     register int i;
422     int offset;
423     struct contentry prco;
424
425     for (i = 0; i < PRSIZE; i++) {
426         if (e->entries[i] == 0)
427           return;
428         mark_member(g, ntohl(e->entries[i]));
429     }
430     offset = ntohl(e->next);
431     while (offset) {
432         pr_Read(NULL, 0, offset, &prco, sizeof(struct contentry));
433         for (i = 0; i < COSIZE; i++) {
434             if (prco.entries[i] == 0)
435               return;
436             mark_member(g, ntohl(prco.entries[i]));
437         }
438         offset = ntohl(prco.next);
439     }
440 }
441
442
443 mark_member(g, uid)
444 struct group *g;
445 int uid;
446 {
447     register int i, j, status;
448
449     if (uid == PRBADID)
450       return;
451     if (g->members >= CHUNKSIZE) {
452         short *s = NULL, s1;
453         struct chunk *c = (struct chunk *)&(g->ch);
454
455         for (i = 0; i < g->members; i++) {
456             j = i % CHUNKSIZE;
457             if (c->member[j] == uid) {
458                 s = &(c->member[j]);
459             }
460             if (j == CHUNKSIZE - 1) {
461                 s1 = c->member[CHUNKSIZE - 1];
462                 c = c->xmem;
463             }
464         }
465         if (j != CHUNKSIZE - 1)
466           s1 = c->member[j];
467         if (s) {
468             *s = s1;
469             g->members--;
470             return;
471         }
472         printf("> Group %s contains user %d in prs but not in Moira\n", g->name,
473                uid);
474         if (replaceflag) {
475             status = PR_RemoveFromGroup(NULL, uid, -g->gid);
476             if (status)
477               prserror(status, "While removing user %d from group %d in prs",
478                        uid, g->gid);
479         }
480         return;
481     }
482     for (i = 0; i < g->members; i++) {
483         if (g->ch.member[i] == uid) {
484             if (g->members == i + 1)
485               g->ch.member[i] = 0;
486             else {
487                 g->ch.member[i] = g->ch.member[g->members];
488                 g->ch.member[g->members] = 0;
489             }
490             g->members--;
491             return;
492         }
493     }
494     printf("> Group %s contains user %d in prs but not in Moira\n", g->name,
495            uid);
496     if (replaceflag) {
497         status = PR_RemoveFromGroup(NULL, uid, -g->gid);
498         if (status)
499           prserror(status, "While removing user %d from group %d in prs",
500                    uid, g->gid);
501     }
502 }
503
504
505 #define MALLOC_BLOCK    102400
506
507 char *perm_malloc(size)
508 unsigned size;
509 {
510     static char *pool = NULL;
511     static unsigned pool_size = 0;
512     register char *ret;
513
514     if (size > pool_size) {
515         pool = (char *) malloc(MALLOC_BLOCK);
516         pool_size = MALLOC_BLOCK;
517     }
518     ret = pool;
519     pool += size;
520     pool = (char *)(((unsigned) (pool + 1)) & ~1);
521     pool_size -= (pool - ret);
522     return(ret);
523 }
524
This page took 0.132244 seconds and 5 git commands to generate.