Don't cast the return from realloc()
[openafs.git] / src / export / cfgexport.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * cfgexport -  load/configure the EXPORT kernel extension
12  */
13 #include <afsconfig.h>
14 #include <afs/param.h>
15
16
17 #include <errno.h>
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <sys/types.h>
21 #include <sys/device.h>
22 #include <sys/sysconfig.h>
23 #include <sys/uio.h>
24 #include <sys/xcoff.h>
25 #include <sys/ldr.h>
26 #include <setjmp.h>
27 #include <signal.h>
28 #include "export.h"
29 #include "sym.h"
30
31 extern char *malloc(), *optarg;
32 extern int sysconfig(int cmd, void *arg, int len);
33
34 int debug = 0;
35 char *syms = "/unix";
36 char *xstrings;
37
38 #include "AFS_component_version_number.c"
39
40 main(argc, argv)
41      char **argv;
42 {
43     int add, del, opts;
44     int c;
45     char *file;
46     mid_t kmid;
47     struct cfg_load cload;
48     struct cfg_kmod cmod;
49     struct k_conf conf;
50     FILE *fp;
51
52 #ifdef  AFS_AIX32_ENV
53     /*
54      * The following signal action for AIX is necessary so that in case of a
55      * crash (i.e. core is generated) we can include the user's data section
56      * in the core dump. Unfortunately, by default, only a partial core is
57      * generated which, in many cases, isn't too useful.
58      */
59     struct sigaction nsa;
60
61     sigemptyset(&nsa.sa_mask);
62     nsa.sa_handler = SIG_DFL;
63     nsa.sa_flags = SA_FULLDUMP;
64     sigaction(SIGSEGV, &nsa, NULL);
65 #endif
66     add = del = 0;
67
68     while ((c = getopt(argc, argv, "a:s:Z:d:")) != EOF) {
69         switch (c) {
70         case 'Z':               /* Zdebug option        */
71             ++debug;
72             break;
73
74         case 'a':
75             add = 1;
76             file = optarg;
77             if (!file)
78                 usage();
79             break;
80
81         case 'd':
82             del = 1;
83             file = optarg;
84             if (!file)
85                 usage();
86             break;
87
88         case 's':
89             syms = optarg;
90             break;
91
92         default:
93             usage();
94             break;
95         }
96     }
97
98     if (!add && !del)
99         usage();
100
101     if (add) {
102         char *buf[1024];
103         char PidFile[256];
104
105         buf[0] = "execerror";
106         buf[1] = "cfgexport";
107         get_syms(&conf, syms);
108
109         cload.path = file;
110         if (sysconfig(SYS_KLOAD, &cload, sizeof(cload)) == -1) {
111             loadquery(L_GETMESSAGES, &buf[2], sizeof buf - 8);
112             execvp("/etc/execerror", buf);
113             perror("SYS_KLOAD");
114             exit(1);
115         }
116
117         cmod.kmid = cload.kmid;
118         cmod.cmd = CFG_INIT;
119         cmod.mdiptr = (caddr_t) & conf;
120         cmod.mdilen = sizeof(conf);
121
122         if (sysconfig(SYS_CFGKMOD, &cmod, sizeof(cmod)) == -1) {
123             perror("SYS_CFGKMOD");
124             cload.kmid = cload.kmid;
125             sysconfig(SYS_KULOAD, &cload, sizeof(cload));
126             exit(1);
127         }
128 #ifdef  notdef
129         printf("cfgexport -d 0x%x # to remove EXPORT\n", cload.kmid);
130 #endif
131         strcpy(PidFile, file);
132         strcat(PidFile, ".kmid");
133         fp = fopen(PidFile, "w");
134         if (fp) {
135             (void)fprintf(fp, "%d\n", cload.kmid);
136             (void)fclose(fp);
137         } else {
138             printf("Can't open for write file %s (error=%d); ignored\n",
139                    PidFile, errno);
140         }
141         exit(0);
142     } else if (del) {
143         char PidFile[256];
144
145         strcpy(PidFile, file);
146         strcat(PidFile, ".kmid");
147         fp = fopen(PidFile, "r");
148         if (!fp) {
149             printf("Can't read %s file (error=%d); aborting\n", PidFile,
150                    errno);
151             exit(1);
152         }
153         (void)fscanf(fp, "%d\n", &kmid);
154         (void)fclose(fp);
155         unlink(PidFile);
156         cmod.kmid = kmid;
157         cmod.cmd = CFG_TERM;
158         cmod.mdiptr = NULL;
159         cmod.mdilen = 0;
160
161         if (sysconfig(SYS_CFGKMOD, &cmod, sizeof(cmod)) == -1) {
162             perror("SYS_CFGKMOD");
163             exit(1);
164         }
165
166         cload.kmid = kmid;
167         if (sysconfig(SYS_KULOAD, &cload, sizeof(cload)) == -1) {
168             perror("SYS_KULOAD");
169             exit(1);
170         }
171         exit(0);
172     }
173 }
174
175 usage()
176 {
177
178     error("usage: cfgexport [-a mod_file [-s symbols]] [-d mod_file]\n");
179 }
180
181 /*
182  * get_syms -   get kernel symbol table info.
183  *
184  * Input:
185  *      conf    -       ^ to EXPORT extension configuration struct
186  *      syms    -       ^ to name of file containing XCOFF symbols
187  */
188 get_syms(conf, syms)
189      struct k_conf *conf;
190      char *syms;
191 {
192     sym_t *k_symtab, *ksp;
193     struct syment *x_symtab, *xsp, *xsq;
194     char *kstrings;
195     struct xcoffhdr hdr;        /* XCOFF header from symbol file */
196     sym_t k_sym;                /* export version of symbol     */
197     struct syment xcoff_sym;    /* xcoff version of symbol      */
198     int i, nsyms, nksyms, nxsyms = 0;
199     int xstr_size, kstr_size;
200     FILE *fp;
201     int xsym_compar();
202
203     if (syms == NULL)
204       sys_error("syms is NULL");
205     fp = fopen(syms, "r");
206     if (fp == NULL)
207         sys_error(syms);
208
209     if (fread(&hdr, sizeof(hdr), 1, fp) != 1)
210         sys_error(syms);
211
212     if (hdr.filehdr.f_nsyms == 0)
213         error("%s: no symbols", syms);
214
215     switch (hdr.filehdr.f_magic) {
216     case U802WRMAGIC:
217     case U802ROMAGIC:
218     case U802TOCMAGIC:
219     case U800WRMAGIC:
220     case U800ROMAGIC:
221     case U800TOCMAGIC:
222 #ifdef __XCOFF64__
223     case U64_TOCMAGIC:
224 #endif
225         break;
226
227     default:
228         error("%s: funny magic number 0%o", syms, hdr.filehdr.f_magic);
229     }
230
231     nsyms = hdr.filehdr.f_nsyms;
232     if (debug)
233         printf("nsyms = %d\n", nsyms);
234
235     x_symtab = (struct syment *)malloc(nsyms * SYMESZ);
236     if (!x_symtab)
237         error("no memory for symbol table");
238
239     /*
240      * try to snarf the string table: should be just past the
241      * symbol table: first 4 bytes is length of rest.
242      */
243     if (fseek(fp, hdr.filehdr.f_symptr + nsyms * SYMESZ, 0) < 0)
244         sys_error("%s: seek to strtab", syms);
245
246     if (fread(&xstr_size, sizeof(xstr_size), 1, fp) != 1)
247         error("%s: reading string table size", syms);
248
249     xstrings = malloc(xstr_size + sizeof(xstr_size));
250     if (!xstrings)
251         error("no memory for string table");
252
253     /*
254      * seek back to the start of the strings
255      */
256     if (fseek(fp, hdr.filehdr.f_symptr + nsyms * SYMESZ, 0) < 0)
257         sys_error("%s: seek to strtab", syms);
258
259     if (fread(xstrings, sizeof(*xstrings), xstr_size, fp) != xstr_size)
260         error("%s: reading string table");
261
262     /*
263      * now seek back to the start of the symbol table, and read it
264      * all in.
265      */
266     if (fseek(fp, hdr.filehdr.f_symptr, 0) < 0)
267         sys_error("%s: seek to symtab", syms);
268
269     xsp = &x_symtab[0];
270
271     for (i = nxsyms = 0; i < nsyms; ++i) {
272         char name[16], *p;
273
274         if (fread(&xcoff_sym, SYMESZ, 1, fp) != 1)
275             error("%s: reading symbol entry", syms);
276
277 #ifdef __XCOFF64__
278         p = xstrings + xcoff_sym.n_offset;
279 #else
280         if (xcoff_sym.n_zeroes == 0) {
281             /*
282              * Need to relocate string table offset
283              */
284             p = xcoff_sym.n_nptr = xstrings + xcoff_sym.n_offset;
285         } else {
286             strncpy(name, xcoff_sym.n_name, 8);
287
288             p = name, p[8] = 0;
289         }
290 #endif
291
292         if (debug > 2)
293             dump_xsym(&xcoff_sym);
294
295         switch (xcoff_sym.n_sclass) {
296         case C_EXT:             /* external                     */
297         case C_HIDEXT:          /* hidden external (sic)        */
298             /*
299              * filtre out the ones with the strange names
300              */
301             if (strchr(p, '@') || strchr(p, '$') || p[0] == 0)
302                 break;
303
304             *xsp++ = xcoff_sym;
305             ++nxsyms;
306
307             if (debug > 1)
308                 dump_xsym(&xcoff_sym);
309
310             break;
311         }
312
313         if (xcoff_sym.n_numaux) {
314             fseek(fp, xcoff_sym.n_numaux * AUXESZ, 1);
315             i += xcoff_sym.n_numaux;
316         }
317     }
318
319     fclose(fp);
320
321     /*
322      * sort the symbol table
323      */
324     qsort((char *)x_symtab, nxsyms, sizeof(*x_symtab), xsym_compar);
325
326     /*
327      * we will need no more than `nxsyms' symbols.
328      */
329     k_symtab = (sym_t *) malloc(nxsyms * sizeof(sym_t));
330     if (!k_symtab)
331         error("no memory for EXPORT symbol table");
332
333     /*
334      * uniquify it, and xlate to funny EXPORT format
335      */
336     xsp = xsq = x_symtab;
337     ksp = k_symtab;
338     kstrings = 0;
339     kstr_size = 0;
340     nksyms = 0;
341
342     memset(xsq = &xcoff_sym, 0, sizeof(*xsq));
343
344     for (i = 1; i < nxsyms; ++i, xsq = xsp++) {
345 #ifdef __XCOFF64__
346         if (xsp->n_offset != xsq->n_offset || xsp->n_value != xsq->n_value) {
347 #else
348         if (xsp->n_zeroes != xsq->n_zeroes || xsp->n_offset != xsq->n_offset
349             || xsp->n_value != xsq->n_value) {
350 #endif
351             xlate_xtok(xsp, ksp++, &kstrings, &kstr_size);
352             ++nksyms;
353         }
354     }
355
356     /*
357      * place the symbol table info into the `conf' data structure
358      *
359      * XXXXX: for today only, leave the string table the same.
360      */
361     conf->nsyms = nksyms;
362     conf->symt_sz = nksyms * sizeof(sym_t);
363     conf->str_sz = kstr_size;
364     conf->symtab = (caddr_t) k_symtab;
365     conf->strtab = kstrings;
366 }
367
368
369 /*
370  * xlate_xtok   -       xlate XCOFF to EXPORT format
371  *
372  * Input:
373  *      xp      -       ^ to XCOFF symbol
374  *      kp      -       ^ to EXPORT  symbol save area
375  *      strp    -       ^ to ^ to EXPORT string table
376  *      szp     -       ^ to EXPORT string table size
377  */
378 #define SYMBUFSIZE 1048576
379 xlate_xtok(xp, kp, strp, szp)
380      struct syment *xp;
381      sym_t *kp;
382      char **strp;
383      uint *szp;
384 {
385     int len;
386     static char *export_strings = NULL, *prev = "";
387     static left, offset, sz;
388
389     if (!export_strings) {
390         export_strings = malloc(sz = SYMBUFSIZE);
391         if (!export_strings)
392             error("no memory for EXPORT string table");
393
394         *strp = export_strings;
395         *szp = offset = sizeof(uint);
396         left = SYMBUFSIZE - offset;
397
398         export_strings += offset;
399
400         *(uint *) export_strings = 0;   /* initial 4 bytes      */
401     }
402 #ifdef __XCOFF64__
403     if (strcmp(prev, xstrings + xp->n_offset) == 0) {
404         /*
405          * same name as previous entry: just use previous
406          */
407         kp->n_offset = offset - strlen(*strp + xp->n_offset) - 1;
408     } else
409         if (find_suffix
410             (xstrings + xp->n_offset, *strp, offset, &kp->n_offset)) {
411         /*
412          * found a string that we are a suffix of
413          */
414         ;
415     } else {
416         /*
417          * need to add to our string table
418          */
419         len = strlen(xstrings + xp->n_offset) + 1;
420         while (len >= left) {
421             fprintf(stderr, "cfgexport: Out of memory. Increase SYMBUFSIZE and recompile\n");
422             exit(1);
423 #if 0
424             /* Something is broken with this code, after being here
425                cfgexport segfaults */
426             export_strings = (char *)realloc(*strp, sz += SYMBUFSIZE);
427             if (!export_strings)
428                 error("no memory for EXPORT string table");
429             *strp = export_strings;
430             left += SYMBUFSIZE;
431             prev = "";          /* lazy */
432 #endif
433         }
434
435         strcpy(prev = *strp + offset, xstrings + xp->n_offset);
436
437         kp->n_offset = offset;
438         offset += len;
439         left -= len;
440         *szp += len;
441     }
442 #else
443     if (kp->n_zeroes = xp->n_zeroes) {  /* sic  */
444         kp->n_zeroes = xp->n_zeroes;
445         kp->n_offset = xp->n_offset;
446     } else if (strcmp(prev, xp->n_nptr) == 0) {
447         /*
448          * same name as previous entry: just use previous
449          */
450         kp->n_offset = offset - strlen(xp->n_nptr) - 1;
451     } else if (find_suffix(xp->n_nptr, *strp, offset, &kp->n_offset)) {
452         /*
453          * found a string that we are a suffix of
454          */
455         ;
456     } else {
457         /*
458          * need to add to our string table
459          */
460         len = strlen(xp->n_nptr) + 1;
461         while (len >= left) {
462             export_strings = realloc(*strp, sz += SYMBUFSIZE);
463             if (!export_strings)
464                 error("no memory for EXPORT string table");
465             *strp = export_strings;
466             left += SYMBUFSIZE;
467             prev = "";          /* lazy */
468         }
469
470         strcpy(prev = *strp + offset, xp->n_nptr);
471
472         kp->n_offset = offset;
473         offset += len;
474         left -= len;
475         *szp += len;
476     }
477 #endif
478
479     kp->n_value = xp->n_value;
480
481     if (debug)
482         dump_ksym(kp, *strp);
483 }
484
485 /*
486  * find_suffix  -       look for a string that arg string is suffix of
487  *
488  * Input:
489  *      p       -       ^ to string we hope is a suffix of another
490  *      strings -       ^ to string table
491  *      max     -       max offset of valid string in strings
492  *      offp    -       ^ to place to store offset, if containing string found
493  *
494  * Returns:
495  *       0      -       no containing string found
496  *      !0      -       string found of which `p' is a suffix
497  *
498  * NOTE:
499  *      This is rather inefficient.
500  */
501 find_suffix(p, strings, max, offp)
502      char *p, *strings;
503      uint *offp;
504 {
505     char *q, *e;
506     int len = strlen(p) - 1;
507
508     strings += sizeof(uint);
509     max -= sizeof(uint);
510
511     for (e = strings + max; e > strings;) {
512         /*
513          * adjust `e' to point at last non-blank
514          */
515         if (*e == 0) {
516             --e;
517             continue;
518         }
519
520         for (q = p + len; q > p && *q == *e;)
521             --q, --e;
522
523         if (*q == *e) {
524             if (debug)
525                 printf("found_suffix: %s\n", p);
526             return *offp = e - strings + sizeof(uint);
527         }
528
529         if (*e)
530             while (*e && e > strings)
531                 --e;
532     }
533
534     return 0;
535 }
536
537 /*
538  * xsym_compar -        compare two XCOFF symbol table entries
539  *
540  * If the names are the same, sort by descending storage class, so that
541  * C_EXT < C_HIDEXT;
542  */
543 xsym_compar(xp, xq)
544      struct syment *xp, *xq;
545 {
546     char *p, *q;
547     int compar;
548
549 #ifndef __XCOFF64__
550     p = (xp->n_zeroes ? xp->n_name : xp->n_nptr);
551     q = (xq->n_zeroes ? xq->n_name : xq->n_nptr);
552
553     if (xp->n_zeroes || xq->n_zeroes)
554         compar = strncmp(p, q, 8);
555     else
556 #else
557     p = xstrings + xp->n_offset;
558     q = xstrings + xq->n_offset;
559 #endif
560     compar = strcmp(p, q);
561
562     if (compar == 0)
563         compar = xp->n_sclass - xq->n_sclass;
564
565     return compar;
566 }
567
568 /*
569  * dump_xsym -  print to XCOFF symbol
570  */
571 dump_xsym(xsp)
572      struct syment *xsp;
573 {
574
575 #ifndef __XCOFF64__
576     if (xsp->n_zeroes)
577         printf
578             ("nptr <%-8.8s  %8.8s> val %8.8x sc# %4.4x type %4.4x sclass %2.2x naux %2.2x\n",
579              xsp->n_name, "", xsp->n_value, xsp->n_scnum & 0xffff,
580              xsp->n_type, xsp->n_sclass, xsp->n_numaux);
581     else
582 #endif
583         printf
584             ("nptr <%-17.17s> val %8.8x sc# %4.4x type %4.4x sclass %2.2x naux %2.2x\n"
585 #ifdef __XCOFF64__
586              , xstrings + xsp->n_offset
587 #else
588              , xsp->n_nptr
589 #endif
590              , xsp->n_value, xsp->n_scnum & 0xffff, xsp->n_type,
591              xsp->n_sclass, xsp->n_numaux);
592 }
593
594 dump_ksym(ksp, strings)
595      sym_t *ksp;
596      char *strings;
597 {
598
599 #ifndef __XCOFF64__
600     if (ksp->n_zeroes)
601         printf("%8.8x %-8.8s\n", ksp->n_value, ksp->n_name);
602     else
603 #endif
604         printf("%8.8x %s\n", ksp->n_value, ksp->n_offset + strings);
605 }
606
607 error(p, a, b, c, d, e)
608      char *p;
609 {
610
611     fprintf(stderr, p, a, b, c, d, e);
612     fprintf(stderr, "\n");
613     exit(1);
614 }
615
616 sys_error(p, a, b, c, d, e)
617      char *p;
618 {
619
620     fprintf(stderr, p, a, b, c, d, e);
621     perror(": ");
622     exit(1);
623 }
624
625 warn(p, a, b, c, d, e)
626      char *p;
627 {
628
629     fprintf(stderr, p, a, b, c, d, e);
630     fprintf(stderr, "\n");
631 }