home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / amd / part08 / opts.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-10  |  14.5 KB  |  718 lines

  1. /*
  2.  * $Id: opts.c,v 5.1 89/11/17 18:21:43 jsp Exp Locker: jsp $
  3.  *
  4.  * Copyright (c) 1989 Jan-Simon Pendry
  5.  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
  6.  * Copyright (c) 1989 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Jan-Simon Pendry at Imperial College, London.
  11.  *
  12.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. #include "am.h"
  29.  
  30. extern char *getenv P((char *));
  31.  
  32. /*
  33.  * static copy of the options with
  34.  * which to play
  35.  */
  36. static struct am_opts fs_static;
  37.  
  38. static char *opt_host = hostname;
  39. static char *opt_hostd = hostd;
  40. static char nullstr[] = "";
  41. static char *opt_key = nullstr;
  42. static char *opt_map = nullstr;
  43. static char *opt_path = nullstr;
  44.  
  45. /*
  46.  * Length of longest option name
  47.  */
  48. #define    NLEN    16
  49. #define S(x) (x) , (sizeof(x)-1)
  50. static struct opt {
  51.     char *name;        /* Name of the option */
  52.     int nlen;        /* Length of option name */
  53.     char **optp;        /* Pointer to option value string */
  54.     char **sel_p;        /* Pointer to selector value string */
  55. } opt_fields[] = {
  56.     /* Options in something corresponding to frequency of use */
  57.     { S("opts"), &fs_static.opt_opts, 0 },
  58.     { S("host"), 0, &opt_host },
  59.     { S("hostd"), 0, &opt_hostd },
  60.     { S("type"), &fs_static.opt_type, 0 },
  61.     { S("rhost"), &fs_static.opt_rhost, 0 },
  62.     { S("rfs"), &fs_static.opt_rfs, 0 },
  63.     { S("fs"), &fs_static.opt_fs, 0 },
  64.     { S("key"), 0, &opt_key },
  65.     { S("map"), 0, &opt_map },
  66.     { S("sublink"), &fs_static.opt_sublink, 0 },
  67.     { S("arch"), 0, &arch },
  68.     { S("dev"), &fs_static.opt_dev, 0 },
  69.     { S("pref"), &fs_static.opt_pref, 0 },
  70.     { S("path"), 0, &opt_path },
  71.     { S("autodir"), 0, &auto_dir },
  72.     { S("delay"), &fs_static.opt_delay, 0 },
  73.     { S("domain"), 0, &hostdomain },
  74.     { S("karch"), 0, &karch },
  75.     { S("cluster"), 0, &cluster },
  76.     { S("byte"), 0, &endian },
  77.     { S("os"), 0, &op_sys },
  78.     { S("mount"), &fs_static.opt_mount, 0 },
  79.     { S("unmount"), &fs_static.opt_unmount, 0 },
  80.     { S("cache"), &fs_static.opt_cache, 0 },
  81.     { S("user"), &fs_static.opt_user, 0 },
  82.     { S("group"), &fs_static.opt_group, 0 },
  83.     { 0, 0, 0, 0 },
  84. };
  85.  
  86. typedef struct opt_apply opt_apply;
  87. struct opt_apply {
  88.     char **opt;
  89.     char *val;
  90. };
  91.  
  92. /*
  93.  * Specially expand the remote host name first
  94.  */
  95. static opt_apply rhost_expansion[] = {
  96.     { &fs_static.opt_rhost, "${host}" },
  97.     { 0, 0 },
  98. };
  99. /*
  100.  * List of options which need to be expanded
  101.  * Note that this the order here _may_ be important.
  102.  */
  103. static opt_apply expansions[] = {
  104. /*    { &fs_static.opt_dir, 0 },    */
  105.     { &fs_static.opt_sublink, 0 },
  106.     { &fs_static.opt_rfs, "${path}" },
  107.     { &fs_static.opt_fs, "${autodir}/${rhost}${rfs}" },
  108.     { &fs_static.opt_opts, "rw" },
  109.     { &fs_static.opt_mount, 0 },
  110.     { &fs_static.opt_unmount, 0 },
  111.     { 0, 0 },
  112. };
  113.  
  114. /*
  115.  * List of options which need to be free'ed before re-use
  116.  */
  117. static opt_apply to_free[] = {
  118.     { &fs_static.fs_glob, 0 },
  119.     { &fs_static.fs_local, 0 },
  120.     { &fs_static.fs_mtab, 0 },
  121. /*    { &fs_static.opt_dir, 0 },    */
  122.     { &fs_static.opt_sublink, 0 },
  123.     { &fs_static.opt_rfs, 0 },
  124.     { &fs_static.opt_fs, 0 },
  125.     { &fs_static.opt_rhost, 0 },
  126.     { &fs_static.opt_opts, 0 },
  127.     { &fs_static.opt_mount, 0 },
  128.     { &fs_static.opt_unmount, 0 },
  129.     { 0, 0 },
  130. };
  131.  
  132. /*
  133.  * Skip to next option in the string
  134.  */
  135. static char *opt P((char**));
  136. static char *opt(p)
  137. char **p;
  138. {
  139.     char *cp = *p;
  140.     char *dp = cp;
  141.     char *s = cp;
  142.  
  143. top:
  144.     while (*cp && *cp != ';') {
  145.         if (*cp == '\"') {
  146.             /*
  147.              * Skip past string
  148.              */
  149.             cp++;
  150.             while (*cp && *cp != '\"')
  151.                 *dp++ = *cp++;
  152.             if (*cp)
  153.                 cp++;
  154.         } else {
  155.             *dp++ = *cp++;
  156.         }
  157.     }
  158.  
  159.     /*
  160.      * Skip past any remaining ';'s
  161.      */
  162.     while (*cp == ';')
  163.         cp++;
  164.  
  165.     /*
  166.      * If we have a zero length string
  167.      * and there are more fields, then
  168.      * parse the next one.  This allows
  169.      * sequences of empty fields.
  170.      */
  171.     if (*cp && dp == s)
  172.         goto top;
  173.  
  174.     *dp = '\0';
  175.  
  176.     *p = cp;
  177.     return s;
  178. }
  179.  
  180. static int eval_opts P((char*));
  181. static int eval_opts(opts)
  182. char *opts;
  183. {
  184.     /*
  185.      * Fill in the global structure fs_static by
  186.      * cracking the string opts.  opts may be
  187.      * scribbled on at will.
  188.      */
  189.     char *o = opts;
  190.     char *f;
  191.  
  192.     /*
  193.      * For each user-specified option
  194.      */
  195.     while (*(f = opt(&o))) {
  196.         struct opt *op;
  197.         enum vs_opt { OldSyn, SelEQ, SelNE, VarAss } vs_opt;
  198.         char *eq = strchr(f, '=');
  199.         char *opt;
  200.         if (!eq || eq[1] == '\0' || eq == f) {
  201.             /*
  202.              * No value, just continue
  203.              */
  204.             plog(XLOG_USER, "No value component in \"%s\"", f);
  205.             continue;
  206.         }
  207.  
  208.         /*
  209.          * Check what type of operation is happening
  210.          * !=, =!  is SelNE
  211.          * == is SelEQ
  212.          * := is VarAss
  213.          * = is OldSyn (either SelEQ or VarAss)
  214.          */
  215.         if (eq[-1] == '!') {        /* != */
  216.             vs_opt = SelNE;
  217.             eq[-1] = '\0';
  218.             opt = eq + 1;
  219.         } else if (eq[-1] == ':') {    /* := */
  220.             vs_opt = VarAss;
  221.             eq[-1] = '\0';
  222.             opt = eq + 1;
  223.         } else if (eq[1] == '=') {    /* == */
  224.             vs_opt = SelEQ;
  225.             eq[0] = '\0';
  226.             opt = eq + 2;
  227.         } else if (eq[1] == '!') {    /* =! */
  228.             vs_opt = SelNE;
  229.             eq[0] = '\0';
  230.             opt = eq + 2;
  231.         } else {            /* = */
  232.             vs_opt = OldSyn;
  233.             eq[0] = '\0';
  234.             opt = eq + 1;
  235.         }
  236.  
  237.         /*
  238.          * For each recognised option
  239.          */
  240.         for (op = opt_fields; op->name; op++) {
  241.             /*
  242.              * Check whether they match
  243.              */
  244.             if (FSTREQ(op->name, f)) {
  245.                 switch (vs_opt) {
  246. #if AMD_COMPAT <= 5000108
  247.                 case OldSyn:
  248.                     if (!op->sel_p) {
  249.                         *op->optp = opt;
  250.                         break;
  251.                     }
  252.                     /* fall through ... */
  253. #endif /* 5000108 */
  254.                 case SelEQ:
  255.                 case SelNE:
  256.                     if (op->sel_p && (STREQ(*op->sel_p, opt) == (vs_opt == SelNE))) {
  257.                         plog(XLOG_MAP, "map selector %s (=%s) did not %smatch %s",
  258.                             op->name,
  259.                             *op->sel_p,
  260.                             vs_opt == SelNE ? "not " : "",
  261.                             opt);
  262.                         return 0;
  263.                     }
  264.                     break;
  265.  
  266.                 case VarAss:
  267.                     if (op->sel_p) {
  268.                         plog(XLOG_USER, "Can't assign to a selector (%s)", op->name);
  269.                         return 0;
  270.                     }
  271.                     *op->optp = opt;
  272.                     break;
  273.                 }
  274.                 break;
  275.             }
  276.         }
  277.  
  278.         if (!op->name)
  279.             plog(XLOG_USER, "Unrecognised key \"%s\"", f);
  280.     }
  281.  
  282.     return 1;
  283. }
  284.  
  285. /*
  286.  * Free an option
  287.  */
  288. static void free_op P((opt_apply*, int));
  289. /*ARGSUSED*/
  290. static void free_op(p, b)
  291. opt_apply *p;
  292. int b;
  293. {
  294.     if (*p->opt) {
  295.         free(*p->opt);
  296.         *p->opt = 0;
  297.     }
  298. }
  299.  
  300. /*
  301.  * Macro-expand an option.  Note that this does not
  302.  * handle recursive expansions.  They will go badly wrong.
  303.  * If sel is true then old expand selectors, otherwise
  304.  * don't expand selectors.
  305.  */
  306. static void expand_op P((opt_apply*, int));
  307. static void expand_op(p, sel_p)
  308. opt_apply *p;
  309. int sel_p;
  310. {
  311. /*
  312.  * The BUFSPACE macros checks that there is enough space
  313.  * left in the expansion buffer.  If there isn't then we
  314.  * give up completely.  This is done to avoid crashing the
  315.  * automounter itself (which would be a bad thing to do).
  316.  */
  317. #define BUFSPACE(ep, len) (((ep) + (len)) < expbuf+MAXPATHLEN)
  318. static char expand_error[] = "No space to expand \"%s\"";
  319.  
  320.     char expbuf[MAXPATHLEN];
  321.     char nbuf[NLEN+1];
  322.     char *ep = expbuf;
  323.     char *cp = *p->opt;
  324.     char *dp;
  325. #ifdef DEBUG
  326.     char *cp_orig = *p->opt;
  327. #endif
  328.     struct opt *op;
  329.  
  330.     while (dp = strchr(cp, '$')) {
  331.         char ch;
  332.         /*
  333.          * First copy up to the $
  334.          */
  335.         { int len = dp - cp;
  336.           if (BUFSPACE(ep, len)) {
  337.             strncpy(ep, cp, len);
  338.             ep += len;
  339.           } else {
  340.             plog(XLOG_ERROR, expand_error, *p->opt);
  341.             goto out;
  342.           }
  343.         }
  344.         cp = dp + 1;
  345.         ch = *cp++;
  346.         if (ch == '$') {
  347.             if (BUFSPACE(ep, 1)) {
  348.                 *ep++ = '$';
  349.             } else {
  350.                 plog(XLOG_ERROR, expand_error, *p->opt);
  351.                 goto out;
  352.             }
  353.         } else if (ch == '{') {
  354.             /* Expansion... */
  355.             enum { E_All, E_Dir, E_File } todo;
  356.             /*
  357.              * Find closing brace
  358.              */
  359.             char *br_p = strchr(cp, '}');
  360.             int len;
  361.             /*
  362.              * Check we found it
  363.              */
  364.             if (!br_p) {
  365.                 /*
  366.                  * Just give up
  367.                  */
  368.                 plog(XLOG_USER, "No closing '}' in \"%s\"", *p->opt);
  369.                 goto out;
  370.             }
  371.             len = br_p - cp;
  372.             /*
  373.              * Figure out which part of the variable to grab.
  374.              */
  375.             if (*cp == '/') {
  376.                 /*
  377.                  * Just take the last component
  378.                  */
  379.                 todo = E_File;
  380.                 cp++;
  381.                 --len;
  382.             } else if (br_p[-1] == '/') {
  383.                 /*
  384.                  * Take all but the last component
  385.                  */
  386.                 todo = E_Dir;
  387.                 --len;
  388.             } else {
  389.                 /*
  390.                  * Take the whole lot
  391.                  */
  392.                 todo = E_All;
  393.             }
  394.             /*
  395.              * Truncate if too long.  Since it won't
  396.              * match anyway it doesn't matter that
  397.              * it has been cut short.
  398.              */
  399.             if (len > NLEN)
  400.                 len = NLEN;
  401.             /*
  402.              * Put the string into another buffer so
  403.              * we can do comparisons.
  404.              */
  405.             strncpy(nbuf, cp, len);
  406.             nbuf[len] = '\0';
  407.             /*
  408.              * Advance cp
  409.              */
  410.             cp = br_p + 1;
  411.             /*
  412.              * Search the option array
  413.              */
  414.             for (op = opt_fields; op->name; op++) {
  415.                 /*
  416.                  * Check for match
  417.                  */
  418.                 if (len == op->nlen && STREQ(op->name, nbuf)) {
  419.                     char xbuf[NLEN+3];
  420.                     char *val;
  421.                     /*
  422.                      * Found expansion.  Copy
  423.                      * the correct value field.
  424.                      */
  425.                     if (!(!op->sel_p == !sel_p)) {
  426.                         /*
  427.                          * Copy the string across unexpanded
  428.                          */
  429.                         sprintf(xbuf, "${%s%s%s}",
  430.                             todo == E_File ? "/" : "",
  431.                             nbuf,
  432.                             todo == E_Dir ? "/" : "");
  433.                         val = xbuf;
  434.                     } else if (op->sel_p) {
  435.                         val = *op->sel_p;
  436.                     } else {
  437.                         val = *op->optp;
  438.                     }
  439.                     if (val) {
  440.                         /*
  441.                          * Do expansion:
  442.                          * ${/var} means take just the last part
  443.                          * ${var/} means take all but the last part
  444.                          * ${var} means take the whole lot
  445.                          */
  446.                         int vlen = strlen(val);
  447.                         char *vptr = val;
  448.                         switch (todo) {
  449.                         case E_Dir:
  450.                             vptr = strchr(val, '/');
  451.                             if (vptr)
  452.                                 vlen = vptr - val;
  453.                             vptr = val;
  454.                             break;
  455.                         case E_File:
  456.                             vptr = strchr(val, '/');
  457.                             if (vptr) {
  458.                                 vptr++;
  459.                                 vlen = strlen(vptr);
  460.                             }
  461.                             break;
  462.                         }
  463. #ifdef DEBUG
  464.                     /*dlog("Expanding \"%s\" to \"%s\"", nbuf, val);*/
  465. #endif
  466.                         if (BUFSPACE(ep, vlen)) {
  467.                             strcpy(ep, vptr);
  468.                             ep += vlen;
  469.                         } else {
  470.                             plog(XLOG_ERROR, expand_error, *p->opt);
  471.                             goto out;
  472.                         }
  473.                     }
  474.                     /*
  475.                      * Done with this variable
  476.                      */
  477.                     break;
  478.                 }
  479.             }
  480.             /*
  481.              * Check that the search was succesful
  482.              */
  483.             if (!op->name) {
  484.                 /*
  485.                  * If it wasn't then scan the
  486.                  * environment for that name
  487.                  * and use any value found
  488.                  */
  489.                 char *env = getenv(nbuf);
  490.                 if (env) {
  491.                     int vlen = strlen(env);
  492.  
  493.                     if (BUFSPACE(ep, vlen)) {
  494.                         strcpy(ep, env);
  495.                         ep += vlen;
  496.                     } else {
  497.                         plog(XLOG_ERROR, expand_error, *p->opt);
  498.                         goto out;
  499.                     }
  500. #ifdef DEBUG
  501.                     Debug(D_STR)
  502.                     plog(XLOG_DEBUG, "Environment gave \"%s\" -> \"%s\"", nbuf, env);
  503. #endif
  504.                 } else {
  505.                     plog(XLOG_USER, "Unknown sequence \"${%s}\"", nbuf);
  506.                 }
  507.             }
  508.         } else {
  509.             /*
  510.              * Error, error
  511.              */
  512.             plog(XLOG_USER, "Unknown $ sequence in \"%s\"", *p->opt);
  513.         }
  514.     }
  515.  
  516. out:
  517.     /*
  518.      * Handle common case - no expansion
  519.      */
  520.     if (cp == *p->opt) {
  521.         *p->opt = strdup(cp);
  522.     } else {
  523.         /*
  524.          * Finish off the expansion
  525.          */
  526.         if (BUFSPACE(ep, strlen(cp))) {
  527.             strcpy(ep, cp);
  528.             /*ep += strlen(ep);*/
  529.         } else {
  530.             plog(XLOG_ERROR, expand_error, *p->opt);
  531.         }
  532.  
  533.         /*
  534.          * Save the exansion
  535.          */
  536.         *p->opt = strdup(expbuf);
  537.     }
  538.  
  539.     /*
  540.      * Normalize slashes in the string.
  541.      */
  542.     { char *f = strchr(*p->opt, '/');
  543.       if (f) {
  544.         char *t = f;
  545.         do {
  546.             /* assert(*f == '/'); */
  547.             /* copy a single / across */
  548.             *t++ = *f++;
  549.  
  550.             /* assert(f[-1] == '/'); */
  551.             /* skip past more /'s */
  552.             while (*f == '/')
  553.                 f++;
  554.  
  555.             /* assert(*f != '/'); */
  556.             /* keep copying up to next / */
  557.             do {
  558.                 *t++ = *f++;
  559.             } while (*f && *f != '/');
  560.  
  561.             /* assert(*f == 0 || *f == '/'); */
  562.  
  563.         } while (*f);
  564.       }
  565.     }
  566.       
  567. #ifdef DEBUG
  568.     Debug(D_STR) {
  569.         plog(XLOG_DEBUG, "Expansion of \"%s\"...", cp_orig);
  570.         plog(XLOG_DEBUG, "... is \"%s\"", *p->opt);
  571.     }
  572. #endif
  573. }
  574.  
  575. /*
  576.  * Wrapper for expand_op
  577.  */
  578. static void expand_opts P((opt_apply*, int));
  579. static void expand_opts(p, sel_p)
  580. opt_apply *p;
  581. int sel_p;
  582. {
  583.     if (*p->opt) {
  584.         expand_op(p, sel_p);
  585.     } else if (p->val) {
  586.         /*
  587.          * Do double expansion, remembering
  588.          * to free the string from the first
  589.          * expansion...
  590.          */
  591.         char *s = *p->opt = expand_key(p->val);
  592.         expand_op(p, sel_p);
  593.         free(s);
  594.     }
  595. }
  596.  
  597. /*
  598.  * Apply a function to a list of options
  599.  */
  600. static void apply_opts(op, ppp, b)
  601. void (*op)();
  602. opt_apply ppp[];
  603. int b;
  604. {
  605.     opt_apply *pp;
  606.     for (pp = ppp; pp->opt; pp++)
  607.         (*op)(pp, b);
  608. }
  609.  
  610. /*
  611.  * Free the option table
  612.  */
  613. void free_opts(fo)
  614. am_opts *fo;
  615. {
  616.     /*
  617.      * Copy in the structure we are playing with
  618.      */
  619.     fs_static = *fo;
  620.  
  621.     /*
  622.      * Free previously allocated memory
  623.      */
  624.     apply_opts(free_op, to_free, FALSE);
  625. }
  626.  
  627. /*
  628.  * Expand lookup key
  629.  */
  630. char *expand_key(key)
  631. char *key;
  632. {
  633.     opt_apply oa;
  634.  
  635.     oa.opt = &key; oa.val = 0;
  636.     expand_opts(&oa, TRUE);
  637.  
  638.     return key;
  639. }
  640.  
  641. int eval_fs_opts(fo, opts, g_opts, path, key, map)
  642. am_opts *fo;
  643. char *opts, *g_opts, *path, *key, *map;
  644. {
  645.     int ok = TRUE;
  646.  
  647.     free_opts(fo);
  648.  
  649.     /*
  650.      * Clear out the option table
  651.      */
  652.     bzero((voidp) &fs_static, sizeof(fs_static));
  653.     bzero((voidp) fo, sizeof(*fo));
  654.  
  655.     /*
  656.      * Set key before expansion
  657.      */
  658.     opt_key = key;
  659.     opt_map = map;
  660.     opt_path = path;
  661.  
  662.     /*
  663.      * Expand global options
  664.      */
  665.     fs_static.fs_glob = expand_key(g_opts);
  666.  
  667.     /*
  668.      * Expand local options
  669.      */
  670.     fs_static.fs_local = expand_key(opts);
  671.  
  672.     /*
  673.      * Expand default (global) options
  674.      */
  675.     if (!eval_opts(fs_static.fs_glob))
  676.         ok = FALSE;
  677.  
  678.     /*
  679.      * Expand local options
  680.      */
  681.     if (ok && !eval_opts(fs_static.fs_local))
  682.         ok = FALSE;
  683.  
  684.     /*
  685.      * Normalise remote host name.
  686.      * 1.  Expand variables
  687.      * 2.  Normalize relative to host tables
  688.      * 3.  Strip local domains from the remote host
  689.      *     name before using it in other expansions.
  690.      *     This makes mount point names and other things
  691.      *     much shorter, while allowing cross domain
  692.      *     sharing of mount maps.
  693.      */
  694.     apply_opts(expand_opts, rhost_expansion, FALSE);
  695.     if (ok && fs_static.opt_rhost && *fs_static.opt_rhost)
  696.         host_normalize(&fs_static.opt_rhost);
  697.  
  698.     /*
  699.      * Macro expand the options.
  700.      * Do this regardless of whether we are accepting
  701.      * this mount - otherwise nasty things happen
  702.      * with memory allocation.
  703.      */
  704.     apply_opts(expand_opts, expansions, FALSE);
  705.  
  706.     /*
  707.      * ok... copy the data back out.
  708.      */
  709.     *fo = fs_static;
  710.  
  711.     /*
  712.      * Clear defined options
  713.      */
  714.     opt_key = opt_map = opt_path = nullstr;
  715.  
  716.     return ok;
  717. }
  718.