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