+ if (!has_host) {
+ grp->gr_type = GT_HOST;
+ if (debug)
+ fprintf(stderr,"Adding a default entry\n");
+ /* add a default group and make the grp list NULL */
+ hpe = (struct hostent *)malloc(sizeof(struct hostent));
+ if (hpe == (struct hostent *)0)
+ out_of_mem();
+ hpe->h_name = "Default";
+ hpe->h_addrtype = AF_INET;
+ hpe->h_length = sizeof (u_long);
+ hpe->h_addr_list = (char **)0;
+ grp->gr_ptr.gt_hostent = hpe;
+ }
+ if (do_mount(ep, grp, exflags, &anon, dirp,
+ dirplen, &fsb)) {
+ getexp_err(ep, grp);
+ goto nextline;
+ }
+
+ /*
+ * Success. Update the data structures.
+ */
+ if (has_host) {
+ grp->gr_next = grphead;
+ grphead = grp;
+ hang_dirp(dirhead, grp, ep, (opt_flags & OP_ALLDIRS));
+ } else {
+ hang_dirp(dirhead, (struct grouplist *)0, ep,
+ (opt_flags & OP_ALLDIRS));
+ free_grp(grp);
+ }
+ dirhead = (struct dirlist *)0;
+ if ((ep->ex_flag & EX_LINKED) == 0) {
+ ep2 = exphead;
+ epp = &exphead;
+
+ /*
+ * Insert in the list in alphabetical order.
+ */
+ while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
+ epp = &ep2->ex_next;
+ ep2 = ep2->ex_next;
+ }
+ if (ep2)
+ ep->ex_next = ep2;
+ *epp = ep;
+ ep->ex_flag |= EX_LINKED;
+ }
+nextline:
+ if (dirhead) {
+ free_dir(dirhead);
+ dirhead = (struct dirlist *)0;
+ }
+ }
+ fclose(exp_file);
+}
+
+/*
+ * Allocate an export list element
+ */
+struct exportlist *
+get_exp()
+{
+ register struct exportlist *ep;
+
+ ep = (struct exportlist *)malloc(sizeof (struct exportlist));
+ if (ep == (struct exportlist *)0)
+ out_of_mem();
+ bzero((caddr_t)ep, sizeof (struct exportlist));
+ return (ep);
+}
+
+/*
+ * Allocate a group list element
+ */
+struct grouplist *
+get_grp()
+{
+ register struct grouplist *gp;
+
+ gp = (struct grouplist *)malloc(sizeof (struct grouplist));
+ if (gp == (struct grouplist *)0)
+ out_of_mem();
+ bzero((caddr_t)gp, sizeof (struct grouplist));
+ return (gp);
+}
+
+/*
+ * Clean up upon an error in get_exportlist().
+ */
+void
+getexp_err(ep, grp)
+ struct exportlist *ep;
+ struct grouplist *grp;
+{
+
+ syslog(LOG_ERR, "Bad exports list line %s", line);
+ if (ep && ep->ex_next == (struct exportlist *)0)
+ free_exp(ep);
+ if (grp && grp->gr_next == (struct grouplist *)0)
+ free_grp(grp);
+}
+
+/*
+ * Search the export list for a matching fs.
+ */
+struct exportlist *
+ex_search(fsid)
+ quad *fsid;
+{
+ register struct exportlist *ep;
+
+ ep = exphead;
+ while (ep) {
+ if (ep->ex_fs.val[0] == fsid->val[0] &&
+ ep->ex_fs.val[1] == fsid->val[1])
+ return (ep);
+ ep = ep->ex_next;
+ }
+ return (ep);
+}
+
+/*
+ * Add a directory path to the list.
+ */
+char *
+add_expdir(dpp, cp, len)
+ struct dirlist **dpp;
+ char *cp;
+ int len;
+{
+ register struct dirlist *dp;
+
+ dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
+ dp->dp_left = *dpp;
+ dp->dp_right = (struct dirlist *)0;
+ dp->dp_flag = 0;
+ dp->dp_hosts = (struct hostlist *)0;
+ strcpy(dp->dp_dirp, cp);
+ *dpp = dp;
+ return (dp->dp_dirp);
+}
+
+/*
+ * Hang the dir list element off the dirpath binary tree as required
+ * and update the entry for host.
+ */
+void
+hang_dirp(dp, grp, ep, alldirs)
+ register struct dirlist *dp;
+ struct grouplist *grp;
+ struct exportlist *ep;
+ int alldirs;
+{
+ register struct hostlist *hp;
+ struct dirlist *dp2;
+
+ if (alldirs) {
+ if (ep->ex_defdir)
+ free((caddr_t)dp);
+ else
+ ep->ex_defdir = dp;
+ if (grp) {
+ hp = get_ht();
+ hp->ht_grp = grp;
+ hp->ht_next = ep->ex_defdir->dp_hosts;
+ ep->ex_defdir->dp_hosts = hp;
+ } else
+ ep->ex_defdir->dp_flag |= DP_DEFSET;
+ } else {
+ while (dp) {
+ if (grp) {
+ hp = get_ht();
+ hp->ht_grp = grp;
+ } else
+ hp = (struct hostlist *)0;
+ dp2 = dp->dp_left;
+ add_dlist(&ep->ex_dirl, dp, hp);
+ dp = dp2;
+ }
+ }
+}
+
+/*
+ * Traverse the binary tree either updating a node that is already there
+ * for the new directory or adding the new node.
+ */
+void
+add_dlist(dpp, newdp, hp)
+ struct dirlist **dpp;
+ struct dirlist *newdp;
+ struct hostlist *hp;
+{
+ register struct dirlist *dp;
+ int cmp;
+
+ dp = *dpp;
+ if (dp) {
+ cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
+ if (cmp > 0) {
+ add_dlist(&dp->dp_left, newdp, hp);
+ return;
+ } else if (cmp < 0) {
+ add_dlist(&dp->dp_right, newdp, hp);
+ return;
+ } else
+ free((caddr_t)newdp);
+ } else {
+ dp = newdp;
+ dp->dp_left = (struct dirlist *)0;
+ *dpp = dp;
+ }
+ if (hp) {
+ hp->ht_next = dp->dp_hosts;
+ dp->dp_hosts = hp;
+ } else
+ dp->dp_flag |= DP_DEFSET;
+}
+
+/*
+ * Search for a dirpath on the export point.
+ */
+struct dirlist *
+dirp_search(dp, dirpath)
+ register struct dirlist *dp;
+ char *dirpath;
+{
+ register int cmp;
+
+ if (dp) {
+ cmp = strcmp(dp->dp_dirp, dirpath);
+ if (cmp > 0)
+ return (dirp_search(dp->dp_left, dirpath));
+ else if (cmp < 0)
+ return (dirp_search(dp->dp_right, dirpath));
+ else
+ return (dp);
+ }
+ return (dp);
+}
+
+/*
+ * Scan for a host match in a directory tree.
+ */
+chk_host(dp, saddr, defsetp)
+ struct dirlist *dp;
+ u_long saddr;
+ int *defsetp;
+{
+ register struct hostlist *hp;
+ register struct grouplist *grp;
+ register u_long **addrp;
+
+ if (dp) {
+ if (dp->dp_flag & DP_DEFSET)
+ *defsetp = 1;
+ hp = dp->dp_hosts;
+ while (hp) {
+ grp = hp->ht_grp;
+ switch (grp->gr_type) {
+ case GT_HOST:
+ addrp = (u_long **)
+ grp->gr_ptr.gt_hostent->h_addr_list;
+ while (*addrp) {
+ if (**addrp == saddr)
+ return (1);
+ addrp++;
+ }
+ break;
+ case GT_NET:
+ if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
+ grp->gr_ptr.gt_net.nt_net)
+ return (1);
+ break;
+ };
+ hp = hp->ht_next;
+ }
+ }
+ return (0);
+}
+
+/*
+ * Scan tree for a host that matches the address.
+ */
+scan_tree(dp, saddr)
+ register struct dirlist *dp;
+ u_long saddr;
+{
+ int defset;
+
+ if (dp) {
+ if (scan_tree(dp->dp_left, saddr))
+ return (1);
+ if (chk_host(dp, saddr, &defset))
+ return (1);
+ if (scan_tree(dp->dp_right, saddr))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Traverse the dirlist tree and free it up.
+ */
+void
+free_dir(dp)
+ register struct dirlist *dp;
+{
+
+ if (dp) {
+ free_dir(dp->dp_left);
+ free_dir(dp->dp_right);
+ free_host(dp->dp_hosts);
+ free((caddr_t)dp);
+ }
+}
+
+/*
+ * Parse the option string and update fields.
+ * Option arguments may either be -<option>=<value> or
+ * -<option> <value>
+ */
+do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
+ char **cpp, **endcpp;
+ struct exportlist *ep;
+ struct grouplist *grp;
+ int *has_hostp;
+ int *exflagsp;
+ struct ucred *cr;
+{
+ register char *cpoptarg, *cpoptend;
+ char *cp, *endcp, *cpopt, savedc, savedc2;
+ int allflag, usedarg;
+
+ cpopt = *cpp;
+ cpopt++;
+ cp = *endcpp;
+ savedc = *cp;
+ *cp = '\0';
+ while (cpopt && *cpopt) {
+ allflag = 1;
+ usedarg = -2;
+ if (cpoptend = index(cpopt, ',')) {
+ *cpoptend++ = '\0';
+ if (cpoptarg = index(cpopt, '='))
+ *cpoptarg++ = '\0';
+ } else {
+ if (cpoptarg = index(cpopt, '='))
+ *cpoptarg++ = '\0';
+ else {
+ *cp = savedc;
+ nextfield(&cp, &endcp);
+ **endcpp = '\0';
+ if (endcp > cp && *cp != '-') {
+ cpoptarg = cp;
+ savedc2 = *endcp;
+ *endcp = '\0';
+ usedarg = 0;
+ }
+ }
+ }
+ if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
+ *exflagsp |= MNT_EXRDONLY;
+ } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
+ !(allflag = strcmp(cpopt, "mapall")) ||
+ !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
+ usedarg++;
+ parsecred(cpoptarg, cr);
+ if (allflag == 0) {
+ *exflagsp |= MNT_EXPORTANON;
+ opt_flags |= OP_MAPALL;
+ } else
+ opt_flags |= OP_MAPROOT;
+ } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
+ *exflagsp |= MNT_EXKERB;
+ opt_flags |= OP_KERB;
+ } else if (cpoptarg && !strcmp(cpopt, "mask")) {
+ if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
+ syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
+ return (1);
+ }
+ usedarg++;
+ opt_flags |= OP_MASK;
+ } else if (cpoptarg && !strcmp(cpopt, "network")) {
+ if (grp->gr_type != GT_NULL) {
+ syslog(LOG_ERR, "Network/host conflict");
+ return (1);
+ } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
+ syslog(LOG_ERR, "Bad net: %s", cpoptarg);
+ return (1);
+ }
+ grp->gr_type = GT_NET;
+ *has_hostp = 1;
+ usedarg++;
+ opt_flags |= OP_NET;
+ } else if (!strcmp(cpopt, "alldirs")) {
+ opt_flags |= OP_ALLDIRS;
+#ifdef ISO
+ } else if (cpoptarg && !strcmp(cpopt, "iso")) {
+ if (get_isoaddr(cpoptarg, grp)) {
+ syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
+ return (1);
+ }
+ *has_hostp = 1;
+ usedarg++;
+ opt_flags |= OP_ISO;
+#endif /* ISO */
+ } else {
+ syslog(LOG_ERR, "Bad opt %s", cpopt);
+ return (1);
+ }
+ if (usedarg >= 0) {
+ *endcp = savedc2;
+ **endcpp = savedc;
+ if (usedarg > 0) {
+ *cpp = cp;
+ *endcpp = endcp;
+ }
+ return (0);
+ }
+ cpopt = cpoptend;
+ }
+ **endcpp = savedc;
+ return (0);
+}
+
+/*
+ * Translate a character string to the corresponding list of network
+ * addresses for a hostname.
+ */
+get_host(cp, grp)
+ char *cp;
+ register struct grouplist *grp;
+{
+ register struct hostent *hp, *nhp;
+ register char **addrp, **naddrp;
+ struct hostent t_host;
+ int i;
+ u_long saddr;
+ char *aptr[2];
+
+ if (grp->gr_type != GT_NULL)
+ return (1);
+ if ((hp = gethostbyname(cp)) == NULL) {
+ if (isdigit(*cp)) {
+ saddr = inet_addr(cp);
+ if (saddr == -1) {
+ syslog(LOG_ERR, "Inet_addr failed");
+ return (1);
+ }
+ if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
+ AF_INET)) == NULL) {
+ hp = &t_host;
+ hp->h_name = cp;
+ hp->h_addrtype = AF_INET;
+ hp->h_length = sizeof (u_long);
+ hp->h_addr_list = aptr;
+ aptr[0] = (char *)&saddr;
+ aptr[1] = (char *)0;
+ }
+ } else {
+ syslog(LOG_ERR, "Gethostbyname failed");
+ return (1);
+ }
+ }
+ grp->gr_type = GT_HOST;
+ nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
+ malloc(sizeof(struct hostent));
+ if (nhp == (struct hostent *)0)
+ out_of_mem();
+ bcopy((caddr_t)hp, (caddr_t)nhp,
+ sizeof(struct hostent));
+ i = strlen(hp->h_name)+1;
+ nhp->h_name = (char *)malloc(i);
+ if (nhp->h_name == (char *)0)
+ out_of_mem();
+ bcopy(hp->h_name, nhp->h_name, i);
+ addrp = hp->h_addr_list;
+ i = 1;
+ while (*addrp++)
+ i++;
+ naddrp = nhp->h_addr_list = (char **)
+ malloc(i*sizeof(char *));
+ if (naddrp == (char **)0)
+ out_of_mem();
+ addrp = hp->h_addr_list;
+ while (*addrp) {
+ *naddrp = (char *)
+ malloc(hp->h_length);
+ if (*naddrp == (char *)0)
+ out_of_mem();
+ bcopy(*addrp, *naddrp,
+ hp->h_length);
+ addrp++;
+ naddrp++;
+ }
+ *naddrp = (char *)0;
+ return (0);
+}
+
+/*
+ * Free up an exports list component
+ */
+void
+free_exp(ep)
+ register struct exportlist *ep;
+{
+
+ if (ep->ex_defdir) {
+ free_host(ep->ex_defdir->dp_hosts);
+ free((caddr_t)ep->ex_defdir);
+ }
+ if (ep->ex_fsdir)
+ free(ep->ex_fsdir);
+ free_dir(ep->ex_dirl);
+ free((caddr_t)ep);
+}
+
+/*
+ * Free hosts.
+ */
+void
+free_host(hp)
+ register struct hostlist *hp;
+{
+ register struct hostlist *hp2;
+
+ while (hp) {
+ hp2 = hp;
+ hp = hp->ht_next;
+ free((caddr_t)hp2);
+ }
+}
+
+struct hostlist *
+get_ht()
+{
+ register struct hostlist *hp;