aix-20030417
[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 RCSID("$Header$");
17
18 #include <errno.h>
19 #include <stdio.h>
20 #include <fcntl.h>
21 #include <sys/types.h>
22 #include <sys/device.h>
23 #include <sys/sysconfig.h>
24 #include <sys/uio.h>
25 #include <sys/xcoff.h>
26 #include <sys/ldr.h>
27 #include <setjmp.h>
28 #include <signal.h>
29 #include "export.h"
30 #include "sym.h"
31
32 extern char    *malloc(), *optarg;
33 extern int      sysconfig(int cmd, void *arg, int len);
34
35 int debug = 0 ;
36 char *syms = "/unix";
37 char *xstrings;
38
39 #include "AFS_component_version_number.c"
40
41 main(argc, argv)
42 char **argv; {
43         register add, del, opts;
44         register 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", PidFile, errno);
139             }
140             exit(0);
141         } else if (del) {
142             char PidFile[256];
143
144             strcpy(PidFile, file);
145             strcat(PidFile, ".kmid");
146             fp = fopen(PidFile, "r");
147             if (!fp) {
148                 printf("Can't read %s file (error=%d); aborting\n", PidFile, errno);
149                 exit(1);
150             }
151             (void) fscanf(fp, "%d\n", &kmid);
152             (void) fclose(fp);
153             unlink(PidFile);
154             cmod.kmid   = kmid;
155             cmod.cmd    = CFG_TERM;
156             cmod.mdiptr = NULL;
157             cmod.mdilen = 0;
158
159             if (sysconfig(SYS_CFGKMOD, &cmod, sizeof(cmod)) == -1) {
160                 perror("SYS_CFGKMOD");
161                 exit(1);
162             }
163
164             cload.kmid = kmid;
165             if (sysconfig(SYS_KULOAD, &cload, sizeof(cload)) == -1) {
166                 perror("SYS_KULOAD");
167                 exit(1);
168             }
169             exit(0);
170         }
171 }
172
173 usage() {
174
175         error("usage: cfgexport [-a mod_file [-s symbols]] [-d mod_file]\n");
176 }
177
178 /*
179  * get_syms -   get kernel symbol table info.
180  *
181  * Input:
182  *      conf    -       ^ to EXPORT extension configuration struct
183  *      syms    -       ^ to name of file containing XCOFF symbols
184  */
185 get_syms(conf, syms)
186 struct k_conf *conf; 
187 char *syms;
188 {
189         sym_t *k_symtab, *ksp;
190         struct syment *x_symtab, *xsp, *xsq;
191         char *kstrings;
192         struct xcoffhdr hdr;            /* XCOFF header from symbol file*/
193         sym_t k_sym;                    /* export version of symbol     */
194         struct syment xcoff_sym;        /* xcoff version of symbol      */
195         int i, nsyms, nksyms, nxsyms = 0;
196         int xstr_size, kstr_size;
197         FILE *fp;
198         int xsym_compar();
199
200         fp = fopen(syms, "r");
201         if (fp == NULL)
202                 sys_error(syms);
203
204         if (fread(&hdr, sizeof (hdr), 1, fp) != 1)
205                 sys_error(syms);
206
207         if (hdr.filehdr.f_nsyms == 0)
208                 error("%s: no symbols", syms);
209
210         switch (hdr.filehdr.f_magic) {
211             case U802WRMAGIC:
212             case U802ROMAGIC:
213             case U802TOCMAGIC:
214             case U800WRMAGIC:
215             case U800ROMAGIC:
216             case U800TOCMAGIC:
217 #ifdef __XCOFF64__
218             case U64_TOCMAGIC:
219 #endif
220                 break;
221
222             default:
223                 error("%s: funny magic number 0%o"
224                       , syms, hdr.filehdr.f_magic);
225         }
226
227         nsyms = hdr.filehdr.f_nsyms;
228         if (debug)
229                 printf("nsyms = %d\n", nsyms);
230
231         x_symtab = (struct syment *) malloc(nsyms * SYMESZ);
232         if (!x_symtab)
233                 error("no memory for symbol table");
234
235         /*
236          * try to snarf the string table: should be just past the
237          * symbol table: first 4 bytes is length of rest.
238          */
239         if (fseek(fp, hdr.filehdr.f_symptr + nsyms * SYMESZ, 0) < 0)
240                 sys_error("%s: seek to strtab", syms);
241
242         if (fread(&xstr_size, sizeof (xstr_size), 1, fp) != 1)
243                 error("%s: reading string table size", syms);
244
245         xstrings = malloc(xstr_size + sizeof (xstr_size));
246         if (!xstrings)
247                 error("no memory for string table");
248
249         /*
250          * seek back to the start of the strings
251          */
252         if (fseek(fp, hdr.filehdr.f_symptr + nsyms * SYMESZ, 0) < 0)
253                 sys_error("%s: seek to strtab", syms);
254
255         if (fread(xstrings, sizeof (*xstrings), xstr_size, fp) != xstr_size)
256                 error("%s: reading string table");
257
258         /*
259          * now seek back to the start of the symbol table, and read it
260          * all in.
261          */
262         if (fseek(fp, hdr.filehdr.f_symptr, 0) < 0)
263                 sys_error("%s: seek to symtab", syms);
264
265         xsp = &x_symtab[0];
266
267         for (i = nxsyms = 0; i < nsyms; ++i) {
268                 char name[16], *p;
269
270                 if (fread(&xcoff_sym, SYMESZ, 1, fp) != 1)
271                         error("%s: reading symbol entry", syms);
272
273 #ifdef __XCOFF64__
274                 p = xstrings + xcoff_sym.n_offset;
275 #else
276                 if (xcoff_sym.n_zeroes == 0) {
277                         /*
278                          * Need to relocate string table offset
279                          */
280                         p = xcoff_sym.n_nptr = xstrings + xcoff_sym.n_offset;
281                 } else {
282                         strncpy(name, xcoff_sym.n_name, 8);
283                         
284                         p = name, p[8] = 0;
285                 }
286 #endif
287
288                 if (debug > 2)
289                         dump_xsym(&xcoff_sym);
290
291                 switch (xcoff_sym.n_sclass) {
292                     case C_EXT:         /* external                     */
293                     case C_HIDEXT:      /* hidden external (sic)        */
294                         /*
295                          * filtre out the ones with the strange names
296                          */
297                         if (strchr(p, '@') || strchr(p, '$') || p[0] == 0)
298                                 break;
299
300                         *xsp++ = xcoff_sym;
301                         ++nxsyms;
302
303                         if (debug > 1)
304                                 dump_xsym(&xcoff_sym);
305
306                         break;
307                 }
308
309                 if (xcoff_sym.n_numaux) {
310                         fseek(fp, xcoff_sym.n_numaux * AUXESZ, 1);
311                         i += xcoff_sym.n_numaux;
312                 }
313         }
314
315         fclose(fp);
316
317         /*
318          * sort the symbol table
319          */
320         qsort((char *) x_symtab, nxsyms, sizeof (*x_symtab), xsym_compar);
321  
322         /*
323          * we will need no more than `nxsyms' symbols.
324          */
325         k_symtab = (sym_t *) malloc(nxsyms * sizeof (sym_t));
326         if (!k_symtab)
327                 error("no memory for EXPORT symbol table");
328
329         /*
330          * uniquify it, and xlate to funny EXPORT format
331          */
332         xsp = xsq = x_symtab;
333         ksp       = k_symtab;
334         kstrings  = 0;
335         kstr_size = 0;
336         nksyms    = 0;
337
338         memset(xsq = &xcoff_sym, 0, sizeof (*xsq));
339
340         for (i = 1; i < nxsyms; ++i, xsq = xsp++) {
341 #ifdef __XCOFF64__
342                 if (xsp->n_offset != xsq->n_offset
343                     || xsp->n_value  != xsq->n_value) {
344 #else
345                 if (xsp->n_zeroes != xsq->n_zeroes
346                     || xsp->n_offset != xsq->n_offset
347                     || xsp->n_value  != xsq->n_value) {
348 #endif
349                         xlate_xtok(xsp, ksp++, &kstrings, &kstr_size);
350                         ++nksyms;
351                 }
352         }
353
354         /*
355          * place the symbol table info into the `conf' data structure
356          *
357          * XXXXX: for today only, leave the string table the same.
358          */
359         conf->nsyms   = nksyms;
360         conf->symt_sz = nksyms * sizeof (sym_t);
361         conf->str_sz  = kstr_size;
362         conf->symtab  = (caddr_t) k_symtab;
363         conf->strtab  = kstrings;
364 }
365
366
367 /*
368  * xlate_xtok   -       xlate XCOFF to EXPORT format
369  *
370  * Input:
371  *      xp      -       ^ to XCOFF symbol
372  *      kp      -       ^ to EXPORT  symbol save area
373  *      strp    -       ^ to ^ to EXPORT string table
374  *      szp     -       ^ to EXPORT string table size
375  */
376 xlate_xtok(xp, kp, strp, szp)
377 register struct syment *xp;
378 register sym_t *kp;
379 char **strp;
380 uint *szp; {
381         register len;
382         static char *export_strings, *prev = "";
383         static left, offset, sz;
384
385         if (!export_strings) {
386                 export_strings = malloc(sz=1024);
387                 if (!export_strings)
388                         error("no memory for EXPORT string table");
389
390                 *strp = export_strings;
391                 *szp  = offset = sizeof (uint);
392                 left  = 1024 - offset;
393
394                 export_strings += offset;
395
396                 *(uint *) export_strings = 0;   /* initial 4 bytes      */
397         }
398                         
399 #ifdef __XCOFF64__
400         if (strcmp(prev, xstrings + xp->n_offset) == 0) {
401                 /*
402                  * same name as previous entry: just use previous
403                  */
404                 kp->n_offset = offset - strlen( *strp + xp->n_offset) - 1;
405         } else if (find_suffix(xstrings + xp->n_offset, *strp, offset, &kp->n_offset)) {
406                 /*
407                  * found a string that we are a suffix of
408                  */
409                 ;
410         } else {
411                 /*
412                  * need to add to our string table
413                  */
414                 len = strlen(xstrings + xp->n_offset) + 1;
415                 while (len >= left) {
416                         export_strings = (char *)realloc(*strp, sz += 1024);
417                         if (!export_strings)
418                                 error("no memory for EXPORT string table");
419                         *strp = export_strings;
420                         left += 1024;
421                         prev  = "";     /* lazy */
422                 }
423
424                 strcpy(prev = *strp + offset, xstrings + xp->n_offset);
425
426                 kp->n_offset = offset;
427                 offset += len;
428                 left   -= len;
429                 *szp   += len;
430         }
431 #else
432         if (kp->n_zeroes = xp->n_zeroes) {      /* sic  */
433                 kp->n_zeroes = xp->n_zeroes;
434                 kp->n_offset = xp->n_offset;
435         } else if (strcmp(prev, xp->n_nptr) == 0) {
436                 /*
437                  * same name as previous entry: just use previous
438                  */
439                 kp->n_offset = offset - strlen(xp->n_nptr) - 1;
440         } else if (find_suffix(xp->n_nptr, *strp, offset, &kp->n_offset)) {
441                 /*
442                  * found a string that we are a suffix of
443                  */
444                 ;
445         } else {
446                 /*
447                  * need to add to our string table
448                  */
449                 len = strlen(xp->n_nptr) + 1;
450                 while (len >= left) {
451                         export_strings = (char *)realloc(*strp, sz += 1024);
452                         if (!export_strings)
453                                 error("no memory for EXPORT string table");
454                         *strp = export_strings;
455                         left += 1024;
456                         prev  = "";     /* lazy */
457                 }
458
459                 strcpy(prev = *strp + offset, xp->n_nptr);
460
461                 kp->n_offset = offset;
462                 offset += len;
463                 left   -= len;
464                 *szp   += len;
465         }
466 #endif
467
468         kp->n_value  = xp->n_value;
469
470         if (debug)
471                 dump_ksym(kp, *strp);
472 }
473 \f
474 /*
475  * find_suffix  -       look for a string that arg string is suffix of
476  *
477  * Input:
478  *      p       -       ^ to string we hope is a suffix of another
479  *      strings -       ^ to string table
480  *      max     -       max offset of valid string in strings
481  *      offp    -       ^ to place to store offset, if containing string found
482  *
483  * Returns:
484  *       0      -       no containing string found
485  *      !0      -       string found of which `p' is a suffix
486  *
487  * NOTE:
488  *      This is rather inefficient.
489  */
490 find_suffix(p, strings, max, offp)
491 register char *p, *strings;
492 uint *offp; {
493         register char *q, *e;
494         register len = strlen(p) - 1;
495
496         strings += sizeof (uint);
497         max     -= sizeof (uint);
498
499         for (e = strings + max; e > strings; ) {
500                 /*
501                  * adjust `e' to point at last non-blank
502                  */
503                 if (*e == 0) {
504                         --e;
505                         continue;
506                 }
507
508                 for (q = p + len; q > p && *q == *e; )
509                         --q, --e;
510
511                 if (*q == *e) {
512                         if (debug)
513                                 printf("found_suffix: %s\n", p);
514                         return *offp = e - strings + sizeof (uint);
515                 }
516
517                 if (*e)
518                         while (*e && e > strings)
519                                 --e;
520         }
521
522         return 0;
523 }
524 \f
525 /*
526  * xsym_compar -        compare two XCOFF symbol table entries
527  *
528  * If the names are the same, sort by descending storage class, so that
529  * C_EXT < C_HIDEXT;
530  */
531 xsym_compar(xp, xq)
532 register struct syment *xp, *xq; {
533         register char *p, *q;
534         register compar;
535
536 #ifndef __XCOFF64__
537         p = (xp->n_zeroes ? xp->n_name : xp->n_nptr);
538         q = (xq->n_zeroes ? xq->n_name : xq->n_nptr);
539
540         if (xp->n_zeroes || xq->n_zeroes)
541                 compar = strncmp(p, q, 8);
542         else
543 #else 
544         p = xstrings + xp->n_offset;
545         q = xstrings + xq->n_offset;
546 #endif
547                 compar = strcmp(p, q);
548
549         if (compar == 0)
550                 compar = xp->n_sclass - xq->n_sclass;
551
552         return compar;
553 }
554 \f
555 /*
556  * dump_xsym -  print to XCOFF symbol
557  */
558 dump_xsym(xsp)
559 struct syment *xsp; {
560
561 #ifndef __XCOFF64__
562         if (xsp->n_zeroes)
563                 printf(
564 "nptr <%-8.8s  %8.8s> val %8.8x sc# %4.4x type %4.4x sclass %2.2x naux %2.2x\n"
565                        , xsp->n_name
566                        , ""
567                        , xsp->n_value
568                        , xsp->n_scnum & 0xffff
569                        , xsp->n_type
570
571                        , xsp->n_sclass
572                        , xsp->n_numaux);
573         else
574 #endif
575                 printf(
576 "nptr <%-17.17s> val %8.8x sc# %4.4x type %4.4x sclass %2.2x naux %2.2x\n"
577 #ifdef __XCOFF64__
578                        , xstrings + xsp->n_offset
579 #else
580                        , xsp->n_nptr
581 #endif
582                        , xsp->n_value
583                        , xsp->n_scnum & 0xffff
584                        , xsp->n_type
585                        , xsp->n_sclass
586                        , xsp->n_numaux);
587 }
588
589 dump_ksym(ksp, strings)
590 sym_t *ksp;
591 char *strings; {
592
593 #ifndef __XCOFF64__
594         if (ksp->n_zeroes)
595                 printf("%8.8x %-8.8s\n", ksp->n_value, ksp->n_name);
596         else
597 #endif
598                 printf("%8.8x %s\n", ksp->n_value, ksp->n_offset + strings);
599 }
600
601 error(p, a, b, c, d, e)
602 char *p; {
603
604         fprintf(stderr, p, a, b, c, d, e);
605         fprintf(stderr, "\n");
606         exit(1);
607 }
608
609 sys_error(p, a, b, c, d, e) 
610 char *p;
611 {
612
613         fprintf(stderr, p, a, b, c, d, e);
614         perror(": ");
615         exit(1);
616 }
617
618 warn(p, a, b, c, d, e) 
619 char *p;
620 {
621
622         fprintf(stderr, p, a, b, c, d, e);
623         fprintf(stderr, "\n");
624 }