]> andersk Git - moira.git/blob - gen/nfs.pc
don't overflow buf for people with really long group lists (sloan sucks)
[moira.git] / gen / nfs.pc
1 /* $Id$
2  *
3  * This generates the files necessary to load an nfs server.
4  *
5  * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include <moira.h>
12 #include <moira_site.h>
13
14 #include <sys/stat.h>
15 #include <sys/types.h>
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include "util.h"
23
24 EXEC SQL INCLUDE sqlca;
25
26 RCSID("$Header$");
27
28 #define min(x, y)       ((x) < (y) ? (x) : (y))
29
30 char *whoami = "nfs.gen";
31 char *db = "moira/moira";
32 char nfs_dir[MAXPATHLEN];
33 struct hash *users, *groups;
34
35 int do_nfs(void);
36 int do_lists(struct save_queue *lists);
37 void do_everyone(void);
38 int do_machs(struct save_queue *machs);
39
40 int main(int argc, char **argv)
41 {
42   char cmd[64];
43   struct stat sb;
44   int changed = 0;
45
46   if (argc > 2)
47     {
48       fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
49       exit(MR_ARGS);
50     }
51
52   initialize_sms_error_table();
53   sprintf(nfs_dir, "%s/nfs", DCM_DIR);
54
55   EXEC SQL CONNECT :db;
56
57   changed = do_nfs();
58
59   EXEC SQL COMMIT;
60
61   if (!changed)
62     {
63       fprintf(stderr, "No files updated.\n");
64       if (argc == 2 && stat(argv[1], &sb) == 0)
65         exit(MR_NO_CHANGE);
66     }
67
68   if (argc == 2)
69     {
70       sprintf(cmd, "cd %s; cp %s/nfs/* .; tar cf %s .",
71               nfs_dir, MOIRA_DIR, argv[1]);
72       if (system(cmd))
73         exit(MR_TAR_FAIL);
74     }
75
76   exit(MR_SUCCESS);
77 }
78
79
80 /* Generate the files.  Returns zero if nothing changed, non-zero otherwise. */
81
82 int do_nfs(void)
83 {
84   EXEC SQL BEGIN DECLARE SECTION;
85   char machname[MACHINE_NAME_SIZE], listname[SERVERHOSTS_VALUE3_SIZE];
86   EXEC SQL END DECLARE SECTION;
87   struct save_queue *machs, *lists;
88   int changed;
89
90   machs = sq_create();
91   lists = sq_create();
92
93   /* The following is declarative, not executed,
94    * and so is dependent on where it is in the file,
95    * not in the order of execution of statements.
96    */
97   EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
98
99   EXEC SQL DECLARE s_cursor CURSOR FOR
100     SELECT m.name, s.value3
101     FROM machine m, serverhosts s
102     WHERE m.mach_id = s.mach_id AND s.service = 'NFS' AND s.enable != 0;
103   EXEC SQL OPEN s_cursor;
104   while (1)
105     {
106       EXEC SQL FETCH s_cursor INTO :machname, :listname;
107       if (sqlca.sqlcode)
108         break;
109       sq_save_unique_string(machs, strdup(strtrim(machname)));
110       sq_save_unique_string(lists, strdup(strtrim(listname)));
111     }
112   EXEC SQL CLOSE s_cursor;
113
114   changed = do_lists(lists);
115   EXEC SQL COMMIT;
116   changed += do_machs(machs);
117   return changed;
118 sqlerr:
119   db_error(sqlca.sqlcode);
120   exit(MR_DBMS_ERR);
121 }
122
123
124 /* Make all of the credentials lists that will be needed.  Returns 0 if
125  * no files were actually changed
126  */
127
128 int do_lists(struct save_queue *lists)
129 {
130   char file[MAXPATHLEN], *u;
131   FILE *fd;
132   EXEC SQL BEGIN DECLARE SECTION;
133   char *listname;
134   int id;
135   EXEC SQL END DECLARE SECTION;
136
137   sprintf(file, "%s/list-", nfs_dir);
138 #if 0
139   if (stat(file, &sb) == 0)
140     {
141       if ((ModDiff (&flag1, "users", sb.st_mtime)) ||
142           (ModDiff (&flag2, "list", sb.st_mtime)) ||
143           (ModDiff (&flag3, "imembers", sb.st_mtime)) ||
144           (ModDiff (&flag4, "serverhosts", sb.st_mtime)))
145         exit(MR_DATE);
146       if (flag1 < 0 && flag2 < 0 && flag3 < 0 && flag4 < 0)
147         {
148           fprintf(stderr, "The lists do not need to be rebuilt.\n");
149           return 0;
150         }
151     }
152 #endif
153
154   /* build the list of everyone, and store it in a file whose name
155    * corresponds to the empty list.
156    */
157   do_everyone();
158
159   fprintf(stderr, "Building specific lists\n");
160   /* now do each of the lists used by an NFS server */
161
162   while (sq_get_data(lists, &listname))
163     {
164       if (strlen(listname) == 0)
165         continue;
166       sprintf(file, "%s/list-%s", nfs_dir, listname);
167       fd = fopen(file, "w");
168       if (!fd)
169         {
170           fprintf(stderr, "cannot open %s for output\n", file);
171           exit(MR_OCONFIG);
172         }
173
174       EXEC SQL DECLARE m_cursor CURSOR FOR
175         SELECT m.member_id
176         FROM imembers m, list l
177         WHERE m.list_id = l.list_id AND l.name = :listname
178         AND m.member_type = 'USER'
179         ORDER BY member_id;
180       EXEC SQL OPEN m_cursor;
181       while (1)
182         {
183           EXEC SQL FETCH m_cursor INTO :id;
184           if (sqlca.sqlcode)
185             break;
186           if ((u = hash_lookup(users, id)))
187             fprintf(fd, "%s\n", u);
188         }
189       EXEC SQL CLOSE m_cursor;
190       if (fclose(fd) == EOF)
191         {
192           fprintf(stderr, "error closing %s\n", file);
193           exit(MR_CCONFIG);
194         }
195     }
196 /* don't free here either
197     sq_destroy(lists);
198  */
199   return 1;
200 sqlerr:
201   db_error(sqlca.sqlcode);
202   exit(MR_DBMS_ERR);
203 }
204
205
206 /*  Build the list of everybody. */
207 struct grp {
208   struct grp *next;
209   char *lid;
210 };
211
212 struct user {
213   char name[USERS_LOGIN_SIZE];
214   int uid;
215   struct grp *lists;
216 };
217
218
219 void do_everyone(void)
220 {
221   const buflen = MAXPATHLEN;
222   char buf[buflen], *l;
223   struct user *u;
224   struct grp *g;
225   struct bucket *b, **p;
226   EXEC SQL BEGIN DECLARE SECTION;
227   char name[USERS_LOGIN_SIZE];
228   int gid, id, lid, uid;
229   EXEC SQL END DECLARE SECTION;
230   FILE *fd;
231
232   fprintf(stderr, "Building the list of everybody\n");
233   sprintf(buf, "%s/list-", nfs_dir);
234   fd = fopen(buf, "w");
235   if (!fd)
236     {
237       fprintf(stderr, "cannot open %s for output\n", buf);
238       exit(MR_OCONFIG);
239     }
240
241   /* make space for group list */
242   groups = create_hash(15000);
243
244   /* retrieve simple groups */
245   EXEC SQL DECLARE l_cursor CURSOR FOR
246     SELECT gid, list_id
247     FROM list
248     WHERE grouplist != 0 AND active != 0
249     ORDER BY list_id;
250   EXEC SQL OPEN l_cursor;
251   while (1)
252     {
253       EXEC SQL FETCH l_cursor INTO :gid, :lid;
254       if (sqlca.sqlcode)
255         break;
256       sprintf(buf, ":%d", gid);
257       hash_store(groups, lid, strdup(buf));
258     }
259   EXEC SQL CLOSE l_cursor;
260
261   /* now do grplists */
262   users = create_hash(10000);
263   EXEC SQL DECLARE u_cursor CURSOR FOR
264     SELECT users_id, login, unix_uid
265     FROM users
266     WHERE status = 1
267     ORDER BY users_id;
268   EXEC SQL OPEN u_cursor;
269   while (1)
270     {
271       EXEC SQL FETCH u_cursor INTO :id, :name, :uid;
272       if (sqlca.sqlcode)
273         break;
274       u = malloc(sizeof(struct user));
275       strcpy(u->name, strtrim(name));
276       u->uid = uid;
277       u->lists = NULL;
278       hash_store(users, id, u);
279     }
280   EXEC SQL CLOSE u_cursor;
281
282   EXEC SQL DECLARE m_cursor2 CURSOR FOR
283     SELECT list_id, member_id
284     FROM imembers
285     WHERE member_type = 'USER'
286     ORDER BY list_id;
287   EXEC SQL OPEN m_cursor2;
288   while (1)
289     {
290       EXEC SQL FETCH m_cursor2 INTO :lid, :id;
291       if (sqlca.sqlcode)
292         break;
293       if ((u = hash_lookup(users, id)) && (l = hash_lookup(groups, lid)))
294         {
295           g = malloc(sizeof(struct grp));
296           g->next = u->lists;
297           u->lists = g;
298           g->lid = l;
299         }
300     }
301   EXEC SQL CLOSE m_cursor2;
302
303   for (p = &(users->data[users->size - 1]); p >= users->data; p--)
304     {
305       for (b = *p; b; b = b->next)
306         {
307           u = (struct user *)b->data;
308           sprintf(buf, "%s:%d:101", u->name, u->uid);
309           for (g = u->lists; g; g = g->next)
310             {
311               if ((strlen(buf) + strlen(g->lid)) <= buflen)
312                 strcat(buf, g->lid);
313               else
314                 {
315                   com_err(whoami, 0, "truncated server-side grp list for %s",
316                           u->name);
317                   break;
318                 }
319             }
320           b->data = strdup(buf);
321           fprintf(fd, "%s\n", buf);
322         }
323     }
324
325   fclose(fd);
326   return;
327
328 sqlerr:
329   db_error(sqlca.sqlcode);
330   exit(MR_DBMS_ERR);
331 }
332
333
334 /* Now do each of the servers, linking the credentials list file and
335  * compiling the quota and dirs files.
336  */
337
338 int do_machs(struct save_queue *machs)
339 {
340   EXEC SQL BEGIN DECLARE SECTION;
341   char *machname, listname[SERVERHOSTS_VALUE3_SIZE];
342   char dev[NFSPHYS_DEVICE_SIZE], dir[FILESYS_NAME_SIZE];
343   char fstype[FILESYS_LOCKERTYPE_SIZE];
344   int uid, quota, id, gid, flag1, flag2, flag3;
345   EXEC SQL END DECLARE SECTION;
346   char file[MAXPATHLEN], f1[MAXPATHLEN], f2[MAXPATHLEN], *cp;
347   int prevuid, quotasum, olddev, oldmach;
348   FILE *fd;
349   struct hash *machines;
350
351   fprintf(stderr, "Building machine files\n");
352
353   machines = create_hash(100);
354   while (sq_get_data(machs, &machname))
355     {
356       EXEC SQL SELECT s.value3, m.mach_id
357         INTO :listname, :id
358         FROM serverhosts s, machine m
359         WHERE s.mach_id = m.mach_id AND m.name = :machname AND
360         s.service = 'NFS';
361       strtrim(machname);
362       sprintf(f1, "%s/list-%s", nfs_dir, strtrim(listname));
363       sprintf(f2, "%s/%s.cred", nfs_dir, machname);
364       unlink(f2); /* ignore errors on this unlink */
365       if (link(f1, f2))
366         {
367           fprintf(stderr, "Cannot link %s to %s\n", f1, f2);
368           exit(MR_OCONFIG);
369         }
370       hash_store(machines, id, machname);
371     }
372
373   olddev = oldmach = -1;
374   fd = stdin;
375
376   EXEC SQL DECLARE q_cursor CURSOR FOR
377     SELECT DISTINCT q.quota, q.entity_id, q.phys_id, n.device, n.mach_id
378     FROM quota q, nfsphys n
379     WHERE n.nfsphys_id = q.phys_id AND q.phys_id != 0 AND
380     n.status < 16 AND q.type = 'USER'
381     ORDER BY n.mach_id, q.phys_id, q.entity_id;
382   EXEC SQL OPEN q_cursor;
383   while (1)
384     {
385       EXEC SQL FETCH q_cursor INTO :quota, :uid, :flag1, :dev, :flag2;
386       if (sqlca.sqlcode)
387         break;
388       if (flag1 != olddev || flag2 != oldmach)
389         {
390           if (quotasum)
391             fprintf(fd, "%d %d\n", prevuid, quotasum);
392           if (flag2 == 0 || !hash_lookup(machines, flag2))
393             continue;
394           if (fd != stdin)
395             fclose(fd);
396           olddev = flag1;
397           oldmach = flag2;
398           while ((cp = strchr(dev, '/')))
399             *cp = '@';
400           sprintf(file, "%s/%s.%s.quotas", nfs_dir,
401                   (char *)hash_lookup(machines, flag2), strtrim(dev));
402           fd = fopen(file, "w");
403           if (!fd)
404             {
405               fprintf(stderr, "cannot open %s for output\n", file);
406               exit(MR_OCONFIG);
407             }
408           prevuid = -1;
409           quotasum = 0;
410         }
411       if (uid != prevuid)
412         {
413           if ((cp = hash_lookup(users, prevuid)) &&
414               (cp = strchr(cp, ':')))
415             prevuid = atoi(cp + 1);
416           if (quotasum)
417             fprintf(fd, "%d %d\n", prevuid, quotasum);
418           prevuid = uid;
419           quotasum = quota;
420         }
421       else
422         quotasum += quota;
423     }
424   EXEC SQL CLOSE q_cursor;
425   if ((cp = hash_lookup(users, prevuid)) &&
426       (cp = strchr(cp, ':')))
427     prevuid = atoi(cp + 1);
428   if (quotasum)
429     fprintf(fd, "%d %d\n", prevuid, quotasum);
430   if (fd != stdin && fclose(fd) == EOF)
431     {
432       fprintf(stderr, "error closing %s", file);
433       exit(MR_CCONFIG);
434     }
435
436   olddev = oldmach = -1;
437   fd = stdin;
438   EXEC SQL DECLARE q_cursor2 CURSOR FOR
439     SELECT DISTINCT q.quota, q.entity_id, q.phys_id, n.device, n.mach_id,
440     n.status
441     FROM quota q, nfsphys n
442     WHERE n.nfsphys_id = q.phys_id AND q.phys_id != 0 AND
443     n.status > 15 AND q.type = 'GROUP'
444     ORDER BY mach_id, phys_id, entity_id;
445   EXEC SQL OPEN q_cursor2;
446   while (1)
447     {
448       EXEC SQL FETCH q_cursor2 INTO :quota, :gid, :flag1, :dev,
449         :flag2, :flag3;
450       if (sqlca.sqlcode)
451         break;
452       if (flag1 != olddev || flag2 != oldmach)
453         {
454           if (quotasum)
455             fprintf(fd, "%d %d\n", prevuid, quotasum);
456           if (flag2 == 0 || !hash_lookup(machines, flag2))
457             continue;
458           if (fd != stdin)
459             fclose(fd);
460           olddev = flag1;
461           oldmach = flag2;
462           while ((cp = strchr(dev, '/')))
463             *cp = '@';
464           sprintf(file, "%s/%s.%s.quotas", nfs_dir,
465                   (char *)hash_lookup(machines, flag2), strtrim(dev));
466           fd = fopen(file, "w");
467           if (!fd)
468             {
469               fprintf(stderr, "cannot open %s for output\n", file);
470               exit(MR_OCONFIG);
471             }
472           prevuid = -1;
473           quotasum = 0;
474         }
475       if (gid != prevuid)
476         {
477           if ((cp = hash_lookup(groups, prevuid)))
478             prevuid = atoi(cp + 1);
479           if (quotasum)
480             fprintf(fd, "%d %d\n", prevuid, quotasum);
481           prevuid = gid;
482           quotasum = quota;
483         }
484       else
485         quotasum += quota;
486     }
487   EXEC SQL CLOSE q_cursor2;
488   if ((cp = hash_lookup(groups, prevuid)))
489     prevuid = atoi(cp + 1);
490   if (quotasum)
491     fprintf(fd, "%d %d\n", prevuid, quotasum);
492   if (fd != stdin && fclose(fd) == EOF)
493     {
494       fprintf(stderr, "error closing %s", file);
495       exit(MR_CCONFIG);
496     }
497
498   olddev = oldmach = -1;
499   fd = stdin;
500
501   EXEC SQL DECLARE q_cursor3 CURSOR FOR
502     SELECT DISTINCT f.name, f.lockertype, u.unix_uid, l.gid, f.phys_id,
503     f.mach_id, n.device
504     FROM users u, list l, nfsphys n, filesys f
505     WHERE u.users_id = f.owner AND l.list_id = f.owners
506     AND f.createflg != 0 AND f.phys_id != 0 AND f.type = 'NFS'
507     AND f.phys_id = n.nfsphys_id
508     ORDER BY mach_id, phys_id;
509   EXEC SQL OPEN q_cursor3;
510   while (1)
511     {
512       EXEC SQL FETCH q_cursor3 INTO :dir, :fstype, :uid, :gid, :flag1,
513         :flag2, :dev;
514       if (sqlca.sqlcode)
515         break;
516       if ((flag1 != olddev || flag2 != oldmach) &&
517           hash_lookup(machines, flag2))
518         {
519           if (fd != stdin)
520             fclose(fd);
521           olddev = flag1;
522           oldmach = flag2;
523           while ((cp = strchr(dev, '/')))
524             *cp = '@';
525           sprintf(file, "%s/%s.%s.dirs", nfs_dir,
526                   (char *)hash_lookup(machines, flag2), strtrim(dev));
527           fd = fopen(file, "w");
528           if (!fd)
529             {
530               fprintf(stderr, "cannot open %s for output\n", file);
531               exit(MR_OCONFIG);
532             }
533         }
534       fprintf(fd, "%s %d %d %s\n", strtrim(dir), uid, gid, strtrim(fstype));
535     }
536   EXEC SQL CLOSE q_cursor3;
537   if (fclose(fd) == EOF)
538     {
539       fprintf(stderr, "error closing %s", file);
540       exit(MR_CCONFIG);
541     }
542   return 1;
543 sqlerr:
544   db_error(sqlca.sqlcode);
545   exit(MR_DBMS_ERR);
546 }
547
This page took 0.084511 seconds and 5 git commands to generate.