13914ddf8SEdward Tomasz Napierala /*- 2abdd3945SEdward Tomasz Napierala * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3abdd3945SEdward Tomasz Napierala * 43914ddf8SEdward Tomasz Napierala * Copyright (c) 2014 The FreeBSD Foundation 53914ddf8SEdward Tomasz Napierala * All rights reserved. 63914ddf8SEdward Tomasz Napierala * 73914ddf8SEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship 83914ddf8SEdward Tomasz Napierala * from the FreeBSD Foundation. 93914ddf8SEdward Tomasz Napierala * 103914ddf8SEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 113914ddf8SEdward Tomasz Napierala * modification, are permitted provided that the following conditions 123914ddf8SEdward Tomasz Napierala * are met: 133914ddf8SEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 143914ddf8SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 153914ddf8SEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 163914ddf8SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 173914ddf8SEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 183914ddf8SEdward Tomasz Napierala * 193914ddf8SEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 203914ddf8SEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 213914ddf8SEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 223914ddf8SEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 233914ddf8SEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 243914ddf8SEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 253914ddf8SEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 263914ddf8SEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 273914ddf8SEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 283914ddf8SEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 293914ddf8SEdward Tomasz Napierala * SUCH DAMAGE. 303914ddf8SEdward Tomasz Napierala * 313914ddf8SEdward Tomasz Napierala */ 323914ddf8SEdward Tomasz Napierala 33925fd945SEdward Tomasz Napierala #include <sys/cdefs.h> 34925fd945SEdward Tomasz Napierala __FBSDID("$FreeBSD$"); 35925fd945SEdward Tomasz Napierala 363914ddf8SEdward Tomasz Napierala #include <sys/types.h> 373914ddf8SEdward Tomasz Napierala #include <sys/time.h> 383914ddf8SEdward Tomasz Napierala #include <sys/ioctl.h> 393914ddf8SEdward Tomasz Napierala #include <sys/param.h> 403914ddf8SEdward Tomasz Napierala #include <sys/linker.h> 413914ddf8SEdward Tomasz Napierala #include <sys/mount.h> 423914ddf8SEdward Tomasz Napierala #include <sys/socket.h> 433914ddf8SEdward Tomasz Napierala #include <sys/stat.h> 443914ddf8SEdward Tomasz Napierala #include <sys/wait.h> 453914ddf8SEdward Tomasz Napierala #include <sys/utsname.h> 463914ddf8SEdward Tomasz Napierala #include <assert.h> 473914ddf8SEdward Tomasz Napierala #include <ctype.h> 483914ddf8SEdward Tomasz Napierala #include <err.h> 493914ddf8SEdward Tomasz Napierala #include <errno.h> 503914ddf8SEdward Tomasz Napierala #include <fcntl.h> 513914ddf8SEdward Tomasz Napierala #include <libgen.h> 52592d6e85SEdward Tomasz Napierala #include <libutil.h> 533914ddf8SEdward Tomasz Napierala #include <netdb.h> 543914ddf8SEdward Tomasz Napierala #include <paths.h> 553914ddf8SEdward Tomasz Napierala #include <signal.h> 563914ddf8SEdward Tomasz Napierala #include <stdbool.h> 573914ddf8SEdward Tomasz Napierala #include <stdint.h> 583914ddf8SEdward Tomasz Napierala #include <stdio.h> 593914ddf8SEdward Tomasz Napierala #include <stdlib.h> 603914ddf8SEdward Tomasz Napierala #include <string.h> 613914ddf8SEdward Tomasz Napierala #include <unistd.h> 623914ddf8SEdward Tomasz Napierala 633914ddf8SEdward Tomasz Napierala #include "autofs_ioctl.h" 643914ddf8SEdward Tomasz Napierala 653914ddf8SEdward Tomasz Napierala #include "common.h" 663914ddf8SEdward Tomasz Napierala 673914ddf8SEdward Tomasz Napierala extern FILE *yyin; 683914ddf8SEdward Tomasz Napierala extern char *yytext; 693914ddf8SEdward Tomasz Napierala extern int yylex(void); 703914ddf8SEdward Tomasz Napierala 713914ddf8SEdward Tomasz Napierala static void parse_master_yyin(struct node *root, const char *master); 723914ddf8SEdward Tomasz Napierala static void parse_map_yyin(struct node *parent, const char *map, 733914ddf8SEdward Tomasz Napierala const char *executable_key); 743914ddf8SEdward Tomasz Napierala 753914ddf8SEdward Tomasz Napierala char * 763914ddf8SEdward Tomasz Napierala checked_strdup(const char *s) 773914ddf8SEdward Tomasz Napierala { 783914ddf8SEdward Tomasz Napierala char *c; 793914ddf8SEdward Tomasz Napierala 803914ddf8SEdward Tomasz Napierala assert(s != NULL); 813914ddf8SEdward Tomasz Napierala 823914ddf8SEdward Tomasz Napierala c = strdup(s); 833914ddf8SEdward Tomasz Napierala if (c == NULL) 843914ddf8SEdward Tomasz Napierala log_err(1, "strdup"); 853914ddf8SEdward Tomasz Napierala return (c); 863914ddf8SEdward Tomasz Napierala } 873914ddf8SEdward Tomasz Napierala 883914ddf8SEdward Tomasz Napierala /* 893914ddf8SEdward Tomasz Napierala * Concatenate two strings, inserting separator between them, unless not needed. 903914ddf8SEdward Tomasz Napierala */ 913914ddf8SEdward Tomasz Napierala char * 926d8e60c3SEdward Tomasz Napierala concat(const char *s1, char separator, const char *s2) 933914ddf8SEdward Tomasz Napierala { 943914ddf8SEdward Tomasz Napierala char *result; 95cd3772d0SEdward Tomasz Napierala char s1last, s2first; 963914ddf8SEdward Tomasz Napierala int ret; 973914ddf8SEdward Tomasz Napierala 984d58da13SEdward Tomasz Napierala if (s1 == NULL) 994d58da13SEdward Tomasz Napierala s1 = ""; 1004d58da13SEdward Tomasz Napierala if (s2 == NULL) 1014d58da13SEdward Tomasz Napierala s2 = ""; 1023914ddf8SEdward Tomasz Napierala 103cd3772d0SEdward Tomasz Napierala if (s1[0] == '\0') 104cd3772d0SEdward Tomasz Napierala s1last = '\0'; 105cd3772d0SEdward Tomasz Napierala else 106cd3772d0SEdward Tomasz Napierala s1last = s1[strlen(s1) - 1]; 1075585582dSEdward Tomasz Napierala 108cd3772d0SEdward Tomasz Napierala s2first = s2[0]; 109cd3772d0SEdward Tomasz Napierala 110cd3772d0SEdward Tomasz Napierala if (s1last == separator && s2first == separator) { 111cd3772d0SEdward Tomasz Napierala /* 112cd3772d0SEdward Tomasz Napierala * If s1 ends with the separator and s2 begins with 113cd3772d0SEdward Tomasz Napierala * it - skip the latter; otherwise concatenating "/" 114cd3772d0SEdward Tomasz Napierala * and "/foo" would end up returning "//foo". 115cd3772d0SEdward Tomasz Napierala */ 116cd3772d0SEdward Tomasz Napierala ret = asprintf(&result, "%s%s", s1, s2 + 1); 117cd3772d0SEdward Tomasz Napierala } else if (s1last == separator || s2first == separator || 118cd3772d0SEdward Tomasz Napierala s1[0] == '\0' || s2[0] == '\0') { 1193914ddf8SEdward Tomasz Napierala ret = asprintf(&result, "%s%s", s1, s2); 1203914ddf8SEdward Tomasz Napierala } else { 1213914ddf8SEdward Tomasz Napierala ret = asprintf(&result, "%s%c%s", s1, separator, s2); 1223914ddf8SEdward Tomasz Napierala } 1233914ddf8SEdward Tomasz Napierala if (ret < 0) 1243914ddf8SEdward Tomasz Napierala log_err(1, "asprintf"); 1253914ddf8SEdward Tomasz Napierala 126ef4b8dfaSEdward Tomasz Napierala //log_debugx("%s: got %s and %s, returning %s", __func__, s1, s2, result); 1273914ddf8SEdward Tomasz Napierala 1283914ddf8SEdward Tomasz Napierala return (result); 1293914ddf8SEdward Tomasz Napierala } 1303914ddf8SEdward Tomasz Napierala 1313914ddf8SEdward Tomasz Napierala void 1323914ddf8SEdward Tomasz Napierala create_directory(const char *path) 1333914ddf8SEdward Tomasz Napierala { 134ef4b8dfaSEdward Tomasz Napierala char *component, *copy, *tofree, *partial, *tmp; 1353914ddf8SEdward Tomasz Napierala int error; 1363914ddf8SEdward Tomasz Napierala 1373914ddf8SEdward Tomasz Napierala assert(path[0] == '/'); 1383914ddf8SEdward Tomasz Napierala 1393914ddf8SEdward Tomasz Napierala /* 1403914ddf8SEdward Tomasz Napierala * +1 to skip the leading slash. 1413914ddf8SEdward Tomasz Napierala */ 1423914ddf8SEdward Tomasz Napierala copy = tofree = checked_strdup(path + 1); 1433914ddf8SEdward Tomasz Napierala 144ef4b8dfaSEdward Tomasz Napierala partial = checked_strdup(""); 1453914ddf8SEdward Tomasz Napierala for (;;) { 1463914ddf8SEdward Tomasz Napierala component = strsep(©, "/"); 1473914ddf8SEdward Tomasz Napierala if (component == NULL) 1483914ddf8SEdward Tomasz Napierala break; 1496d8e60c3SEdward Tomasz Napierala tmp = concat(partial, '/', component); 150ef4b8dfaSEdward Tomasz Napierala free(partial); 151ef4b8dfaSEdward Tomasz Napierala partial = tmp; 1527ebeea9aSEdward Tomasz Napierala //log_debugx("creating \"%s\"", partial); 1533914ddf8SEdward Tomasz Napierala error = mkdir(partial, 0755); 1547ebeea9aSEdward Tomasz Napierala if (error != 0 && errno != EEXIST) { 1557ebeea9aSEdward Tomasz Napierala log_warn("cannot create %s", partial); 1567ebeea9aSEdward Tomasz Napierala return; 1577ebeea9aSEdward Tomasz Napierala } 1583914ddf8SEdward Tomasz Napierala } 1593914ddf8SEdward Tomasz Napierala 1603914ddf8SEdward Tomasz Napierala free(tofree); 1613914ddf8SEdward Tomasz Napierala } 1623914ddf8SEdward Tomasz Napierala 1633914ddf8SEdward Tomasz Napierala struct node * 1643914ddf8SEdward Tomasz Napierala node_new_root(void) 1653914ddf8SEdward Tomasz Napierala { 1663914ddf8SEdward Tomasz Napierala struct node *n; 1673914ddf8SEdward Tomasz Napierala 1683914ddf8SEdward Tomasz Napierala n = calloc(1, sizeof(*n)); 1693914ddf8SEdward Tomasz Napierala if (n == NULL) 1703914ddf8SEdward Tomasz Napierala log_err(1, "calloc"); 1713914ddf8SEdward Tomasz Napierala // XXX 1723914ddf8SEdward Tomasz Napierala n->n_key = checked_strdup("/"); 1733914ddf8SEdward Tomasz Napierala n->n_options = checked_strdup(""); 1743914ddf8SEdward Tomasz Napierala 1753914ddf8SEdward Tomasz Napierala TAILQ_INIT(&n->n_children); 1763914ddf8SEdward Tomasz Napierala 1773914ddf8SEdward Tomasz Napierala return (n); 1783914ddf8SEdward Tomasz Napierala } 1793914ddf8SEdward Tomasz Napierala 1803914ddf8SEdward Tomasz Napierala struct node * 1813914ddf8SEdward Tomasz Napierala node_new(struct node *parent, char *key, char *options, char *location, 1823914ddf8SEdward Tomasz Napierala const char *config_file, int config_line) 1833914ddf8SEdward Tomasz Napierala { 1843914ddf8SEdward Tomasz Napierala struct node *n; 1853914ddf8SEdward Tomasz Napierala 1863914ddf8SEdward Tomasz Napierala n = calloc(1, sizeof(*n)); 1873914ddf8SEdward Tomasz Napierala if (n == NULL) 1883914ddf8SEdward Tomasz Napierala log_err(1, "calloc"); 1893914ddf8SEdward Tomasz Napierala 1903914ddf8SEdward Tomasz Napierala TAILQ_INIT(&n->n_children); 1913914ddf8SEdward Tomasz Napierala assert(key != NULL); 1923dd80c05SEdward Tomasz Napierala assert(key[0] != '\0'); 1933914ddf8SEdward Tomasz Napierala n->n_key = key; 1943914ddf8SEdward Tomasz Napierala if (options != NULL) 1953914ddf8SEdward Tomasz Napierala n->n_options = options; 1963914ddf8SEdward Tomasz Napierala else 1973914ddf8SEdward Tomasz Napierala n->n_options = strdup(""); 1983914ddf8SEdward Tomasz Napierala n->n_location = location; 1993914ddf8SEdward Tomasz Napierala assert(config_file != NULL); 2003914ddf8SEdward Tomasz Napierala n->n_config_file = config_file; 2013914ddf8SEdward Tomasz Napierala assert(config_line >= 0); 2023914ddf8SEdward Tomasz Napierala n->n_config_line = config_line; 2033914ddf8SEdward Tomasz Napierala 2043914ddf8SEdward Tomasz Napierala assert(parent != NULL); 2053914ddf8SEdward Tomasz Napierala n->n_parent = parent; 2063914ddf8SEdward Tomasz Napierala TAILQ_INSERT_TAIL(&parent->n_children, n, n_next); 2073914ddf8SEdward Tomasz Napierala 2083914ddf8SEdward Tomasz Napierala return (n); 2093914ddf8SEdward Tomasz Napierala } 2103914ddf8SEdward Tomasz Napierala 2113914ddf8SEdward Tomasz Napierala struct node * 2123914ddf8SEdward Tomasz Napierala node_new_map(struct node *parent, char *key, char *options, char *map, 2133914ddf8SEdward Tomasz Napierala const char *config_file, int config_line) 2143914ddf8SEdward Tomasz Napierala { 2153914ddf8SEdward Tomasz Napierala struct node *n; 2163914ddf8SEdward Tomasz Napierala 2173914ddf8SEdward Tomasz Napierala n = calloc(1, sizeof(*n)); 2183914ddf8SEdward Tomasz Napierala if (n == NULL) 2193914ddf8SEdward Tomasz Napierala log_err(1, "calloc"); 2203914ddf8SEdward Tomasz Napierala 2213914ddf8SEdward Tomasz Napierala TAILQ_INIT(&n->n_children); 2223914ddf8SEdward Tomasz Napierala assert(key != NULL); 2233dd80c05SEdward Tomasz Napierala assert(key[0] != '\0'); 2243914ddf8SEdward Tomasz Napierala n->n_key = key; 2253914ddf8SEdward Tomasz Napierala if (options != NULL) 2263914ddf8SEdward Tomasz Napierala n->n_options = options; 2273914ddf8SEdward Tomasz Napierala else 2283914ddf8SEdward Tomasz Napierala n->n_options = strdup(""); 2293914ddf8SEdward Tomasz Napierala n->n_map = map; 2303914ddf8SEdward Tomasz Napierala assert(config_file != NULL); 2313914ddf8SEdward Tomasz Napierala n->n_config_file = config_file; 2323914ddf8SEdward Tomasz Napierala assert(config_line >= 0); 2333914ddf8SEdward Tomasz Napierala n->n_config_line = config_line; 2343914ddf8SEdward Tomasz Napierala 2353914ddf8SEdward Tomasz Napierala assert(parent != NULL); 2363914ddf8SEdward Tomasz Napierala n->n_parent = parent; 2373914ddf8SEdward Tomasz Napierala TAILQ_INSERT_TAIL(&parent->n_children, n, n_next); 2383914ddf8SEdward Tomasz Napierala 2393914ddf8SEdward Tomasz Napierala return (n); 2403914ddf8SEdward Tomasz Napierala } 2413914ddf8SEdward Tomasz Napierala 2423914ddf8SEdward Tomasz Napierala static struct node * 2433914ddf8SEdward Tomasz Napierala node_duplicate(const struct node *o, struct node *parent) 2443914ddf8SEdward Tomasz Napierala { 2453914ddf8SEdward Tomasz Napierala const struct node *child; 2463914ddf8SEdward Tomasz Napierala struct node *n; 2473914ddf8SEdward Tomasz Napierala 2483914ddf8SEdward Tomasz Napierala if (parent == NULL) 2493914ddf8SEdward Tomasz Napierala parent = o->n_parent; 2503914ddf8SEdward Tomasz Napierala 2513914ddf8SEdward Tomasz Napierala n = node_new(parent, o->n_key, o->n_options, o->n_location, 2523914ddf8SEdward Tomasz Napierala o->n_config_file, o->n_config_line); 2533914ddf8SEdward Tomasz Napierala 2543914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(child, &o->n_children, n_next) 2553914ddf8SEdward Tomasz Napierala node_duplicate(child, n); 2563914ddf8SEdward Tomasz Napierala 2573914ddf8SEdward Tomasz Napierala return (n); 2583914ddf8SEdward Tomasz Napierala } 2593914ddf8SEdward Tomasz Napierala 2603914ddf8SEdward Tomasz Napierala static void 2613914ddf8SEdward Tomasz Napierala node_delete(struct node *n) 2623914ddf8SEdward Tomasz Napierala { 2633914ddf8SEdward Tomasz Napierala struct node *child, *tmp; 2643914ddf8SEdward Tomasz Napierala 2653914ddf8SEdward Tomasz Napierala assert (n != NULL); 2663914ddf8SEdward Tomasz Napierala 2673914ddf8SEdward Tomasz Napierala TAILQ_FOREACH_SAFE(child, &n->n_children, n_next, tmp) 2683914ddf8SEdward Tomasz Napierala node_delete(child); 2693914ddf8SEdward Tomasz Napierala 2703914ddf8SEdward Tomasz Napierala if (n->n_parent != NULL) 2713914ddf8SEdward Tomasz Napierala TAILQ_REMOVE(&n->n_parent->n_children, n, n_next); 2723914ddf8SEdward Tomasz Napierala 2733914ddf8SEdward Tomasz Napierala free(n); 2743914ddf8SEdward Tomasz Napierala } 2753914ddf8SEdward Tomasz Napierala 2763914ddf8SEdward Tomasz Napierala /* 2773914ddf8SEdward Tomasz Napierala * Move (reparent) node 'n' to make it sibling of 'previous', placed 2783914ddf8SEdward Tomasz Napierala * just after it. 2793914ddf8SEdward Tomasz Napierala */ 2803914ddf8SEdward Tomasz Napierala static void 2813914ddf8SEdward Tomasz Napierala node_move_after(struct node *n, struct node *previous) 2823914ddf8SEdward Tomasz Napierala { 2833914ddf8SEdward Tomasz Napierala 2843914ddf8SEdward Tomasz Napierala TAILQ_REMOVE(&n->n_parent->n_children, n, n_next); 2853914ddf8SEdward Tomasz Napierala n->n_parent = previous->n_parent; 2863914ddf8SEdward Tomasz Napierala TAILQ_INSERT_AFTER(&previous->n_parent->n_children, previous, n, n_next); 2873914ddf8SEdward Tomasz Napierala } 2883914ddf8SEdward Tomasz Napierala 2893914ddf8SEdward Tomasz Napierala static void 2903914ddf8SEdward Tomasz Napierala node_expand_includes(struct node *root, bool is_master) 2913914ddf8SEdward Tomasz Napierala { 2923914ddf8SEdward Tomasz Napierala struct node *n, *n2, *tmp, *tmp2, *tmproot; 2933914ddf8SEdward Tomasz Napierala int error; 2943914ddf8SEdward Tomasz Napierala 2953914ddf8SEdward Tomasz Napierala TAILQ_FOREACH_SAFE(n, &root->n_children, n_next, tmp) { 2963914ddf8SEdward Tomasz Napierala if (n->n_key[0] != '+') 2973914ddf8SEdward Tomasz Napierala continue; 2983914ddf8SEdward Tomasz Napierala 2993914ddf8SEdward Tomasz Napierala error = access(AUTO_INCLUDE_PATH, F_OK); 3003914ddf8SEdward Tomasz Napierala if (error != 0) { 3013914ddf8SEdward Tomasz Napierala log_errx(1, "directory services not configured; " 3023914ddf8SEdward Tomasz Napierala "%s does not exist", AUTO_INCLUDE_PATH); 3033914ddf8SEdward Tomasz Napierala } 3043914ddf8SEdward Tomasz Napierala 3053914ddf8SEdward Tomasz Napierala /* 3063914ddf8SEdward Tomasz Napierala * "+1" to skip leading "+". 3073914ddf8SEdward Tomasz Napierala */ 3083914ddf8SEdward Tomasz Napierala yyin = auto_popen(AUTO_INCLUDE_PATH, n->n_key + 1, NULL); 3093914ddf8SEdward Tomasz Napierala assert(yyin != NULL); 3103914ddf8SEdward Tomasz Napierala 3113914ddf8SEdward Tomasz Napierala tmproot = node_new_root(); 3123914ddf8SEdward Tomasz Napierala if (is_master) 3133914ddf8SEdward Tomasz Napierala parse_master_yyin(tmproot, n->n_key); 3143914ddf8SEdward Tomasz Napierala else 3153914ddf8SEdward Tomasz Napierala parse_map_yyin(tmproot, n->n_key, NULL); 3163914ddf8SEdward Tomasz Napierala 3173914ddf8SEdward Tomasz Napierala error = auto_pclose(yyin); 3183914ddf8SEdward Tomasz Napierala yyin = NULL; 3193914ddf8SEdward Tomasz Napierala if (error != 0) { 3203914ddf8SEdward Tomasz Napierala log_errx(1, "failed to handle include \"%s\"", 3213914ddf8SEdward Tomasz Napierala n->n_key); 3223914ddf8SEdward Tomasz Napierala } 3233914ddf8SEdward Tomasz Napierala 3243914ddf8SEdward Tomasz Napierala /* 3253914ddf8SEdward Tomasz Napierala * Entries to be included are now in tmproot. We need to merge 3263914ddf8SEdward Tomasz Napierala * them with the rest, preserving their place and ordering. 3273914ddf8SEdward Tomasz Napierala */ 3283914ddf8SEdward Tomasz Napierala TAILQ_FOREACH_REVERSE_SAFE(n2, 3293914ddf8SEdward Tomasz Napierala &tmproot->n_children, nodehead, n_next, tmp2) { 3303914ddf8SEdward Tomasz Napierala node_move_after(n2, n); 3313914ddf8SEdward Tomasz Napierala } 3323914ddf8SEdward Tomasz Napierala 3333914ddf8SEdward Tomasz Napierala node_delete(n); 3343914ddf8SEdward Tomasz Napierala node_delete(tmproot); 3353914ddf8SEdward Tomasz Napierala } 3363914ddf8SEdward Tomasz Napierala } 3373914ddf8SEdward Tomasz Napierala 3383914ddf8SEdward Tomasz Napierala static char * 3393914ddf8SEdward Tomasz Napierala expand_ampersand(char *string, const char *key) 3403914ddf8SEdward Tomasz Napierala { 3413914ddf8SEdward Tomasz Napierala char c, *expanded; 3423914ddf8SEdward Tomasz Napierala int i, ret, before_len = 0; 3433914ddf8SEdward Tomasz Napierala bool backslashed = false; 3443914ddf8SEdward Tomasz Napierala 3453914ddf8SEdward Tomasz Napierala assert(key[0] != '\0'); 3463914ddf8SEdward Tomasz Napierala 3473914ddf8SEdward Tomasz Napierala expanded = checked_strdup(string); 3483914ddf8SEdward Tomasz Napierala 3493914ddf8SEdward Tomasz Napierala for (i = 0; string[i] != '\0'; i++) { 3503914ddf8SEdward Tomasz Napierala c = string[i]; 3513914ddf8SEdward Tomasz Napierala if (c == '\\' && backslashed == false) { 3523914ddf8SEdward Tomasz Napierala backslashed = true; 3533914ddf8SEdward Tomasz Napierala continue; 3543914ddf8SEdward Tomasz Napierala } 3553914ddf8SEdward Tomasz Napierala if (backslashed) { 3563914ddf8SEdward Tomasz Napierala backslashed = false; 3573914ddf8SEdward Tomasz Napierala continue; 3583914ddf8SEdward Tomasz Napierala } 3593914ddf8SEdward Tomasz Napierala backslashed = false; 3603914ddf8SEdward Tomasz Napierala if (c != '&') 3613914ddf8SEdward Tomasz Napierala continue; 3623914ddf8SEdward Tomasz Napierala 3633914ddf8SEdward Tomasz Napierala /* 3643914ddf8SEdward Tomasz Napierala * The 'before_len' variable contains the number 3653914ddf8SEdward Tomasz Napierala * of characters before the '&'. 3663914ddf8SEdward Tomasz Napierala */ 3673914ddf8SEdward Tomasz Napierala before_len = i; 368*1383afcbSEdward Tomasz Napierala //assert(i < (int)strlen(string)); 3693914ddf8SEdward Tomasz Napierala 3703914ddf8SEdward Tomasz Napierala ret = asprintf(&expanded, "%.*s%s%s", 3713914ddf8SEdward Tomasz Napierala before_len, string, key, string + before_len + 1); 3723914ddf8SEdward Tomasz Napierala if (ret < 0) 3733914ddf8SEdward Tomasz Napierala log_err(1, "asprintf"); 3743914ddf8SEdward Tomasz Napierala 3753914ddf8SEdward Tomasz Napierala //log_debugx("\"%s\" expanded with key \"%s\" to \"%s\"", 3763914ddf8SEdward Tomasz Napierala // string, key, expanded); 3773914ddf8SEdward Tomasz Napierala 3783914ddf8SEdward Tomasz Napierala /* 3793914ddf8SEdward Tomasz Napierala * Figure out where to start searching for next variable. 3803914ddf8SEdward Tomasz Napierala */ 3813914ddf8SEdward Tomasz Napierala string = expanded; 3823914ddf8SEdward Tomasz Napierala i = before_len + strlen(key); 383*1383afcbSEdward Tomasz Napierala if (i == (int)strlen(string)) 384*1383afcbSEdward Tomasz Napierala break; 3853914ddf8SEdward Tomasz Napierala backslashed = false; 3863914ddf8SEdward Tomasz Napierala //assert(i < (int)strlen(string)); 3873914ddf8SEdward Tomasz Napierala } 3883914ddf8SEdward Tomasz Napierala 3893914ddf8SEdward Tomasz Napierala return (expanded); 3903914ddf8SEdward Tomasz Napierala } 3913914ddf8SEdward Tomasz Napierala 3923914ddf8SEdward Tomasz Napierala /* 3933914ddf8SEdward Tomasz Napierala * Expand "&" in n_location. If the key is NULL, try to use 3943914ddf8SEdward Tomasz Napierala * key from map entries themselves. Keep in mind that maps 3953914ddf8SEdward Tomasz Napierala * consist of tho levels of node structures, the key is one 3963914ddf8SEdward Tomasz Napierala * level up. 3973914ddf8SEdward Tomasz Napierala * 3983914ddf8SEdward Tomasz Napierala * Variant with NULL key is for "automount -LL". 3993914ddf8SEdward Tomasz Napierala */ 4003914ddf8SEdward Tomasz Napierala void 4013914ddf8SEdward Tomasz Napierala node_expand_ampersand(struct node *n, const char *key) 4023914ddf8SEdward Tomasz Napierala { 4033914ddf8SEdward Tomasz Napierala struct node *child; 4043914ddf8SEdward Tomasz Napierala 4053914ddf8SEdward Tomasz Napierala if (n->n_location != NULL) { 4063914ddf8SEdward Tomasz Napierala if (key == NULL) { 4073914ddf8SEdward Tomasz Napierala if (n->n_parent != NULL && 4083914ddf8SEdward Tomasz Napierala strcmp(n->n_parent->n_key, "*") != 0) { 4093914ddf8SEdward Tomasz Napierala n->n_location = expand_ampersand(n->n_location, 4103914ddf8SEdward Tomasz Napierala n->n_parent->n_key); 4113914ddf8SEdward Tomasz Napierala } 4123914ddf8SEdward Tomasz Napierala } else { 4133914ddf8SEdward Tomasz Napierala n->n_location = expand_ampersand(n->n_location, key); 4143914ddf8SEdward Tomasz Napierala } 4153914ddf8SEdward Tomasz Napierala } 4163914ddf8SEdward Tomasz Napierala 4173914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(child, &n->n_children, n_next) 4183914ddf8SEdward Tomasz Napierala node_expand_ampersand(child, key); 4193914ddf8SEdward Tomasz Napierala } 4203914ddf8SEdward Tomasz Napierala 4213914ddf8SEdward Tomasz Napierala /* 4223914ddf8SEdward Tomasz Napierala * Expand "*" in n_key. 4233914ddf8SEdward Tomasz Napierala */ 4243914ddf8SEdward Tomasz Napierala void 4253914ddf8SEdward Tomasz Napierala node_expand_wildcard(struct node *n, const char *key) 4263914ddf8SEdward Tomasz Napierala { 4273914ddf8SEdward Tomasz Napierala struct node *child, *expanded; 4283914ddf8SEdward Tomasz Napierala 4293914ddf8SEdward Tomasz Napierala assert(key != NULL); 4303914ddf8SEdward Tomasz Napierala 4313914ddf8SEdward Tomasz Napierala if (strcmp(n->n_key, "*") == 0) { 4323914ddf8SEdward Tomasz Napierala expanded = node_duplicate(n, NULL); 4333914ddf8SEdward Tomasz Napierala expanded->n_key = checked_strdup(key); 4343914ddf8SEdward Tomasz Napierala node_move_after(expanded, n); 4353914ddf8SEdward Tomasz Napierala } 4363914ddf8SEdward Tomasz Napierala 4373914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(child, &n->n_children, n_next) 4383914ddf8SEdward Tomasz Napierala node_expand_wildcard(child, key); 4393914ddf8SEdward Tomasz Napierala } 4403914ddf8SEdward Tomasz Napierala 4413914ddf8SEdward Tomasz Napierala int 4423914ddf8SEdward Tomasz Napierala node_expand_defined(struct node *n) 4433914ddf8SEdward Tomasz Napierala { 4443914ddf8SEdward Tomasz Napierala struct node *child; 4453914ddf8SEdward Tomasz Napierala int error, cumulated_error = 0; 4463914ddf8SEdward Tomasz Napierala 4473914ddf8SEdward Tomasz Napierala if (n->n_location != NULL) { 4483914ddf8SEdward Tomasz Napierala n->n_location = defined_expand(n->n_location); 4493914ddf8SEdward Tomasz Napierala if (n->n_location == NULL) { 4503914ddf8SEdward Tomasz Napierala log_warnx("failed to expand location for %s", 4513914ddf8SEdward Tomasz Napierala node_path(n)); 4523914ddf8SEdward Tomasz Napierala return (EINVAL); 4533914ddf8SEdward Tomasz Napierala } 4543914ddf8SEdward Tomasz Napierala } 4553914ddf8SEdward Tomasz Napierala 4563914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(child, &n->n_children, n_next) { 4573914ddf8SEdward Tomasz Napierala error = node_expand_defined(child); 4583914ddf8SEdward Tomasz Napierala if (error != 0 && cumulated_error == 0) 4593914ddf8SEdward Tomasz Napierala cumulated_error = error; 4603914ddf8SEdward Tomasz Napierala } 4613914ddf8SEdward Tomasz Napierala 4623914ddf8SEdward Tomasz Napierala return (cumulated_error); 4633914ddf8SEdward Tomasz Napierala } 4643914ddf8SEdward Tomasz Napierala 4657a20e479SEdward Tomasz Napierala static bool 4667a20e479SEdward Tomasz Napierala node_is_direct_key(const struct node *n) 4677a20e479SEdward Tomasz Napierala { 4687a20e479SEdward Tomasz Napierala 4697a20e479SEdward Tomasz Napierala if (n->n_parent != NULL && n->n_parent->n_parent == NULL && 4707a20e479SEdward Tomasz Napierala strcmp(n->n_key, "/-") == 0) { 4717a20e479SEdward Tomasz Napierala return (true); 4727a20e479SEdward Tomasz Napierala } 4737a20e479SEdward Tomasz Napierala 4747a20e479SEdward Tomasz Napierala return (false); 4757a20e479SEdward Tomasz Napierala } 4767a20e479SEdward Tomasz Napierala 4773914ddf8SEdward Tomasz Napierala bool 4783914ddf8SEdward Tomasz Napierala node_is_direct_map(const struct node *n) 4793914ddf8SEdward Tomasz Napierala { 4803914ddf8SEdward Tomasz Napierala 4813914ddf8SEdward Tomasz Napierala for (;;) { 4823914ddf8SEdward Tomasz Napierala assert(n->n_parent != NULL); 4833914ddf8SEdward Tomasz Napierala if (n->n_parent->n_parent == NULL) 4843914ddf8SEdward Tomasz Napierala break; 4853914ddf8SEdward Tomasz Napierala n = n->n_parent; 4863914ddf8SEdward Tomasz Napierala } 4873914ddf8SEdward Tomasz Napierala 4887a20e479SEdward Tomasz Napierala return (node_is_direct_key(n)); 4893914ddf8SEdward Tomasz Napierala } 4903914ddf8SEdward Tomasz Napierala 4914cdc52bdSEdward Tomasz Napierala bool 4924cdc52bdSEdward Tomasz Napierala node_has_wildcards(const struct node *n) 4934cdc52bdSEdward Tomasz Napierala { 4944cdc52bdSEdward Tomasz Napierala const struct node *child; 4954cdc52bdSEdward Tomasz Napierala 4964cdc52bdSEdward Tomasz Napierala TAILQ_FOREACH(child, &n->n_children, n_next) { 4974cdc52bdSEdward Tomasz Napierala if (strcmp(child->n_key, "*") == 0) 4984cdc52bdSEdward Tomasz Napierala return (true); 4994cdc52bdSEdward Tomasz Napierala } 5004cdc52bdSEdward Tomasz Napierala 5014cdc52bdSEdward Tomasz Napierala return (false); 5024cdc52bdSEdward Tomasz Napierala } 5034cdc52bdSEdward Tomasz Napierala 5043914ddf8SEdward Tomasz Napierala static void 5053914ddf8SEdward Tomasz Napierala node_expand_maps(struct node *n, bool indirect) 5063914ddf8SEdward Tomasz Napierala { 5073914ddf8SEdward Tomasz Napierala struct node *child, *tmp; 5083914ddf8SEdward Tomasz Napierala 5093914ddf8SEdward Tomasz Napierala TAILQ_FOREACH_SAFE(child, &n->n_children, n_next, tmp) { 5103914ddf8SEdward Tomasz Napierala if (node_is_direct_map(child)) { 5113914ddf8SEdward Tomasz Napierala if (indirect) 5123914ddf8SEdward Tomasz Napierala continue; 5133914ddf8SEdward Tomasz Napierala } else { 5143914ddf8SEdward Tomasz Napierala if (indirect == false) 5153914ddf8SEdward Tomasz Napierala continue; 5163914ddf8SEdward Tomasz Napierala } 5173914ddf8SEdward Tomasz Napierala 5183914ddf8SEdward Tomasz Napierala /* 5193914ddf8SEdward Tomasz Napierala * This is the first-level map node; the one that contains 5203914ddf8SEdward Tomasz Napierala * the key and subnodes with mountpoints and actual map names. 5213914ddf8SEdward Tomasz Napierala */ 5223914ddf8SEdward Tomasz Napierala if (child->n_map == NULL) 5233914ddf8SEdward Tomasz Napierala continue; 5243914ddf8SEdward Tomasz Napierala 5253914ddf8SEdward Tomasz Napierala if (indirect) { 5263914ddf8SEdward Tomasz Napierala log_debugx("map \"%s\" is an indirect map, parsing", 5273914ddf8SEdward Tomasz Napierala child->n_map); 5283914ddf8SEdward Tomasz Napierala } else { 5293914ddf8SEdward Tomasz Napierala log_debugx("map \"%s\" is a direct map, parsing", 5303914ddf8SEdward Tomasz Napierala child->n_map); 5313914ddf8SEdward Tomasz Napierala } 5324cdc52bdSEdward Tomasz Napierala parse_map(child, child->n_map, NULL, NULL); 5333914ddf8SEdward Tomasz Napierala } 5343914ddf8SEdward Tomasz Napierala } 5353914ddf8SEdward Tomasz Napierala 5363914ddf8SEdward Tomasz Napierala static void 5373914ddf8SEdward Tomasz Napierala node_expand_direct_maps(struct node *n) 5383914ddf8SEdward Tomasz Napierala { 5393914ddf8SEdward Tomasz Napierala 5403914ddf8SEdward Tomasz Napierala node_expand_maps(n, false); 5413914ddf8SEdward Tomasz Napierala } 5423914ddf8SEdward Tomasz Napierala 5433914ddf8SEdward Tomasz Napierala void 5443914ddf8SEdward Tomasz Napierala node_expand_indirect_maps(struct node *n) 5453914ddf8SEdward Tomasz Napierala { 5463914ddf8SEdward Tomasz Napierala 5473914ddf8SEdward Tomasz Napierala node_expand_maps(n, true); 5483914ddf8SEdward Tomasz Napierala } 5493914ddf8SEdward Tomasz Napierala 5503914ddf8SEdward Tomasz Napierala static char * 5513914ddf8SEdward Tomasz Napierala node_path_x(const struct node *n, char *x) 5523914ddf8SEdward Tomasz Napierala { 5533914ddf8SEdward Tomasz Napierala char *path; 5543914ddf8SEdward Tomasz Napierala 5553914ddf8SEdward Tomasz Napierala if (n->n_parent == NULL) 5563914ddf8SEdward Tomasz Napierala return (x); 5573914ddf8SEdward Tomasz Napierala 5583914ddf8SEdward Tomasz Napierala /* 5593914ddf8SEdward Tomasz Napierala * Return "/-" for direct maps only if we were asked for path 5603914ddf8SEdward Tomasz Napierala * to the "/-" node itself, not to any of its subnodes. 5613914ddf8SEdward Tomasz Napierala */ 5627a20e479SEdward Tomasz Napierala if (node_is_direct_key(n) && x[0] != '\0') 5633914ddf8SEdward Tomasz Napierala return (x); 5643914ddf8SEdward Tomasz Napierala 5653dd80c05SEdward Tomasz Napierala assert(n->n_key[0] != '\0'); 5666d8e60c3SEdward Tomasz Napierala path = concat(n->n_key, '/', x); 5673914ddf8SEdward Tomasz Napierala free(x); 5683914ddf8SEdward Tomasz Napierala 5693914ddf8SEdward Tomasz Napierala return (node_path_x(n->n_parent, path)); 5703914ddf8SEdward Tomasz Napierala } 5713914ddf8SEdward Tomasz Napierala 5723914ddf8SEdward Tomasz Napierala /* 5733914ddf8SEdward Tomasz Napierala * Return full path for node, consisting of concatenated 5743914ddf8SEdward Tomasz Napierala * paths of node itself and all its parents, up to the root. 5753914ddf8SEdward Tomasz Napierala */ 5763914ddf8SEdward Tomasz Napierala char * 5773914ddf8SEdward Tomasz Napierala node_path(const struct node *n) 5783914ddf8SEdward Tomasz Napierala { 5791bc6f464SEdward Tomasz Napierala char *path; 5801bc6f464SEdward Tomasz Napierala size_t len; 5813914ddf8SEdward Tomasz Napierala 5821bc6f464SEdward Tomasz Napierala path = node_path_x(n, checked_strdup("")); 5831bc6f464SEdward Tomasz Napierala 5841bc6f464SEdward Tomasz Napierala /* 5851bc6f464SEdward Tomasz Napierala * Strip trailing slash, unless the whole path is "/". 5861bc6f464SEdward Tomasz Napierala */ 5871bc6f464SEdward Tomasz Napierala len = strlen(path); 5881bc6f464SEdward Tomasz Napierala if (len > 1 && path[len - 1] == '/') 5891bc6f464SEdward Tomasz Napierala path[len - 1] = '\0'; 5901bc6f464SEdward Tomasz Napierala 5911bc6f464SEdward Tomasz Napierala return (path); 5923914ddf8SEdward Tomasz Napierala } 5933914ddf8SEdward Tomasz Napierala 5943914ddf8SEdward Tomasz Napierala static char * 5953914ddf8SEdward Tomasz Napierala node_options_x(const struct node *n, char *x) 5963914ddf8SEdward Tomasz Napierala { 5973914ddf8SEdward Tomasz Napierala char *options; 5983914ddf8SEdward Tomasz Napierala 5998f0eba67SEdward Tomasz Napierala if (n == NULL) 6008f0eba67SEdward Tomasz Napierala return (x); 6018f0eba67SEdward Tomasz Napierala 6026d8e60c3SEdward Tomasz Napierala options = concat(x, ',', n->n_options); 6038f0eba67SEdward Tomasz Napierala free(x); 6043914ddf8SEdward Tomasz Napierala 6053914ddf8SEdward Tomasz Napierala return (node_options_x(n->n_parent, options)); 6063914ddf8SEdward Tomasz Napierala } 6073914ddf8SEdward Tomasz Napierala 6083914ddf8SEdward Tomasz Napierala /* 6093914ddf8SEdward Tomasz Napierala * Return options for node, consisting of concatenated 6103914ddf8SEdward Tomasz Napierala * options from the node itself and all its parents, 6113914ddf8SEdward Tomasz Napierala * up to the root. 6123914ddf8SEdward Tomasz Napierala */ 6133914ddf8SEdward Tomasz Napierala char * 6143914ddf8SEdward Tomasz Napierala node_options(const struct node *n) 6153914ddf8SEdward Tomasz Napierala { 6163914ddf8SEdward Tomasz Napierala 6173914ddf8SEdward Tomasz Napierala return (node_options_x(n, checked_strdup(""))); 6183914ddf8SEdward Tomasz Napierala } 6193914ddf8SEdward Tomasz Napierala 6203914ddf8SEdward Tomasz Napierala static void 6218ee4f5efSEdward Tomasz Napierala node_print_indent(const struct node *n, const char *cmdline_options, 6228ee4f5efSEdward Tomasz Napierala int indent) 6233914ddf8SEdward Tomasz Napierala { 6243914ddf8SEdward Tomasz Napierala const struct node *child, *first_child; 6258ee4f5efSEdward Tomasz Napierala char *path, *options, *tmp; 6263914ddf8SEdward Tomasz Napierala 6273914ddf8SEdward Tomasz Napierala path = node_path(n); 6288ee4f5efSEdward Tomasz Napierala tmp = node_options(n); 6298ee4f5efSEdward Tomasz Napierala options = concat(cmdline_options, ',', tmp); 6308ee4f5efSEdward Tomasz Napierala free(tmp); 6313914ddf8SEdward Tomasz Napierala 6323914ddf8SEdward Tomasz Napierala /* 6333914ddf8SEdward Tomasz Napierala * Do not show both parent and child node if they have the same 6343914ddf8SEdward Tomasz Napierala * mountpoint; only show the child node. This means the typical, 6353914ddf8SEdward Tomasz Napierala * "key location", map entries are shown in a single line; 6363914ddf8SEdward Tomasz Napierala * the "key mountpoint1 location2 mountpoint2 location2" entries 6373914ddf8SEdward Tomasz Napierala * take multiple lines. 6383914ddf8SEdward Tomasz Napierala */ 6393914ddf8SEdward Tomasz Napierala first_child = TAILQ_FIRST(&n->n_children); 6403914ddf8SEdward Tomasz Napierala if (first_child == NULL || TAILQ_NEXT(first_child, n_next) != NULL || 6413914ddf8SEdward Tomasz Napierala strcmp(path, node_path(first_child)) != 0) { 6423914ddf8SEdward Tomasz Napierala assert(n->n_location == NULL || n->n_map == NULL); 6433914ddf8SEdward Tomasz Napierala printf("%*.s%-*s %s%-*s %-*s # %s map %s at %s:%d\n", 6443914ddf8SEdward Tomasz Napierala indent, "", 6453914ddf8SEdward Tomasz Napierala 25 - indent, 6463914ddf8SEdward Tomasz Napierala path, 6473914ddf8SEdward Tomasz Napierala options[0] != '\0' ? "-" : " ", 6483914ddf8SEdward Tomasz Napierala 20, 6493914ddf8SEdward Tomasz Napierala options[0] != '\0' ? options : "", 6503914ddf8SEdward Tomasz Napierala 20, 6513914ddf8SEdward Tomasz Napierala n->n_location != NULL ? n->n_location : n->n_map != NULL ? n->n_map : "", 6523914ddf8SEdward Tomasz Napierala node_is_direct_map(n) ? "direct" : "indirect", 6533914ddf8SEdward Tomasz Napierala indent == 0 ? "referenced" : "defined", 6543914ddf8SEdward Tomasz Napierala n->n_config_file, n->n_config_line); 6553914ddf8SEdward Tomasz Napierala } 6563914ddf8SEdward Tomasz Napierala 6573914ddf8SEdward Tomasz Napierala free(path); 6583914ddf8SEdward Tomasz Napierala free(options); 6593914ddf8SEdward Tomasz Napierala 6603914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(child, &n->n_children, n_next) 6618ee4f5efSEdward Tomasz Napierala node_print_indent(child, cmdline_options, indent + 2); 6623914ddf8SEdward Tomasz Napierala } 6633914ddf8SEdward Tomasz Napierala 6648ee4f5efSEdward Tomasz Napierala /* 6658ee4f5efSEdward Tomasz Napierala * Recursively print node with all its children. The cmdline_options 6668ee4f5efSEdward Tomasz Napierala * argument is used for additional options to be prepended to all the 6678ee4f5efSEdward Tomasz Napierala * others - usually those are the options passed by command line. 6688ee4f5efSEdward Tomasz Napierala */ 6693914ddf8SEdward Tomasz Napierala void 6708ee4f5efSEdward Tomasz Napierala node_print(const struct node *n, const char *cmdline_options) 6713914ddf8SEdward Tomasz Napierala { 6723914ddf8SEdward Tomasz Napierala const struct node *child; 6733914ddf8SEdward Tomasz Napierala 6743914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(child, &n->n_children, n_next) 6758ee4f5efSEdward Tomasz Napierala node_print_indent(child, cmdline_options, 0); 6763914ddf8SEdward Tomasz Napierala } 6773914ddf8SEdward Tomasz Napierala 678cc4026a4SEdward Tomasz Napierala static struct node * 679cc4026a4SEdward Tomasz Napierala node_find_x(struct node *node, const char *path) 6803914ddf8SEdward Tomasz Napierala { 6813914ddf8SEdward Tomasz Napierala struct node *child, *found; 6823914ddf8SEdward Tomasz Napierala char *tmp; 683c37463b3SEdward Tomasz Napierala size_t tmplen; 6843914ddf8SEdward Tomasz Napierala 68512f1f00cSEdward Tomasz Napierala //log_debugx("looking up %s in %s", path, node_path(node)); 6863914ddf8SEdward Tomasz Napierala 68712f1f00cSEdward Tomasz Napierala if (!node_is_direct_key(node)) { 6883914ddf8SEdward Tomasz Napierala tmp = node_path(node); 689c37463b3SEdward Tomasz Napierala tmplen = strlen(tmp); 690c37463b3SEdward Tomasz Napierala if (strncmp(tmp, path, tmplen) != 0) { 691c37463b3SEdward Tomasz Napierala free(tmp); 692c37463b3SEdward Tomasz Napierala return (NULL); 693c37463b3SEdward Tomasz Napierala } 694c37463b3SEdward Tomasz Napierala if (path[tmplen] != '/' && path[tmplen] != '\0') { 695c37463b3SEdward Tomasz Napierala /* 696c37463b3SEdward Tomasz Napierala * If we have two map entries like 'foo' and 'foobar', make 697c37463b3SEdward Tomasz Napierala * sure the search for 'foobar' won't match 'foo' instead. 698c37463b3SEdward Tomasz Napierala */ 6993914ddf8SEdward Tomasz Napierala free(tmp); 7003914ddf8SEdward Tomasz Napierala return (NULL); 7013914ddf8SEdward Tomasz Napierala } 7023914ddf8SEdward Tomasz Napierala free(tmp); 70312f1f00cSEdward Tomasz Napierala } 7043914ddf8SEdward Tomasz Napierala 7053914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(child, &node->n_children, n_next) { 706cc4026a4SEdward Tomasz Napierala found = node_find_x(child, path); 7073914ddf8SEdward Tomasz Napierala if (found != NULL) 7083914ddf8SEdward Tomasz Napierala return (found); 7093914ddf8SEdward Tomasz Napierala } 7103914ddf8SEdward Tomasz Napierala 71112f1f00cSEdward Tomasz Napierala if (node->n_parent == NULL || node_is_direct_key(node)) 71212f1f00cSEdward Tomasz Napierala return (NULL); 71312f1f00cSEdward Tomasz Napierala 7143914ddf8SEdward Tomasz Napierala return (node); 7153914ddf8SEdward Tomasz Napierala } 7163914ddf8SEdward Tomasz Napierala 717cc4026a4SEdward Tomasz Napierala struct node * 718cc4026a4SEdward Tomasz Napierala node_find(struct node *root, const char *path) 719cc4026a4SEdward Tomasz Napierala { 720cc4026a4SEdward Tomasz Napierala struct node *node; 721cc4026a4SEdward Tomasz Napierala 72212f1f00cSEdward Tomasz Napierala assert(root->n_parent == NULL); 72312f1f00cSEdward Tomasz Napierala 724cc4026a4SEdward Tomasz Napierala node = node_find_x(root, path); 72512f1f00cSEdward Tomasz Napierala if (node != NULL) 72612f1f00cSEdward Tomasz Napierala assert(node != root); 72712f1f00cSEdward Tomasz Napierala 728cc4026a4SEdward Tomasz Napierala return (node); 729cc4026a4SEdward Tomasz Napierala } 730cc4026a4SEdward Tomasz Napierala 7313914ddf8SEdward Tomasz Napierala /* 7323914ddf8SEdward Tomasz Napierala * Canonical form of a map entry looks like this: 7333914ddf8SEdward Tomasz Napierala * 7343914ddf8SEdward Tomasz Napierala * key [-options] [ [/mountpoint] [-options2] location ... ] 7353914ddf8SEdward Tomasz Napierala * 7363914ddf8SEdward Tomasz Napierala * Entries for executable maps are slightly different, as they 7373914ddf8SEdward Tomasz Napierala * lack the 'key' field and are always single-line; the key field 7383914ddf8SEdward Tomasz Napierala * for those maps is taken from 'executable_key' argument. 7393914ddf8SEdward Tomasz Napierala * 7403914ddf8SEdward Tomasz Napierala * We parse it in such a way that a map always has two levels - first 7413914ddf8SEdward Tomasz Napierala * for key, and the second, for the mountpoint. 7423914ddf8SEdward Tomasz Napierala */ 7433914ddf8SEdward Tomasz Napierala static void 7443914ddf8SEdward Tomasz Napierala parse_map_yyin(struct node *parent, const char *map, const char *executable_key) 7453914ddf8SEdward Tomasz Napierala { 7463914ddf8SEdward Tomasz Napierala char *key = NULL, *options = NULL, *mountpoint = NULL, 7473914ddf8SEdward Tomasz Napierala *options2 = NULL, *location = NULL; 7483914ddf8SEdward Tomasz Napierala int ret; 7493914ddf8SEdward Tomasz Napierala struct node *node; 7503914ddf8SEdward Tomasz Napierala 7513914ddf8SEdward Tomasz Napierala lineno = 1; 7523914ddf8SEdward Tomasz Napierala 7533914ddf8SEdward Tomasz Napierala if (executable_key != NULL) 7543914ddf8SEdward Tomasz Napierala key = checked_strdup(executable_key); 7553914ddf8SEdward Tomasz Napierala 7563914ddf8SEdward Tomasz Napierala for (;;) { 7573914ddf8SEdward Tomasz Napierala ret = yylex(); 7583914ddf8SEdward Tomasz Napierala if (ret == 0 || ret == NEWLINE) { 75930ae6e00SEdward Tomasz Napierala /* 76030ae6e00SEdward Tomasz Napierala * In case of executable map, the key is always 76130ae6e00SEdward Tomasz Napierala * non-NULL, even if the map is empty. So, make sure 76230ae6e00SEdward Tomasz Napierala * we don't fail empty maps here. 76330ae6e00SEdward Tomasz Napierala */ 76430ae6e00SEdward Tomasz Napierala if ((key != NULL && executable_key == NULL) || 76530ae6e00SEdward Tomasz Napierala options != NULL) { 7663914ddf8SEdward Tomasz Napierala log_errx(1, "truncated entry at %s, line %d", 7673914ddf8SEdward Tomasz Napierala map, lineno); 7683914ddf8SEdward Tomasz Napierala } 7693914ddf8SEdward Tomasz Napierala if (ret == 0 || executable_key != NULL) { 7703914ddf8SEdward Tomasz Napierala /* 7713914ddf8SEdward Tomasz Napierala * End of file. 7723914ddf8SEdward Tomasz Napierala */ 7733914ddf8SEdward Tomasz Napierala break; 7743914ddf8SEdward Tomasz Napierala } else { 7753914ddf8SEdward Tomasz Napierala key = options = NULL; 7763914ddf8SEdward Tomasz Napierala continue; 7773914ddf8SEdward Tomasz Napierala } 7783914ddf8SEdward Tomasz Napierala } 7793914ddf8SEdward Tomasz Napierala if (key == NULL) { 7803914ddf8SEdward Tomasz Napierala key = checked_strdup(yytext); 7813914ddf8SEdward Tomasz Napierala if (key[0] == '+') { 7823914ddf8SEdward Tomasz Napierala node_new(parent, key, NULL, NULL, map, lineno); 7833914ddf8SEdward Tomasz Napierala key = options = NULL; 7843914ddf8SEdward Tomasz Napierala continue; 7853914ddf8SEdward Tomasz Napierala } 7863914ddf8SEdward Tomasz Napierala continue; 7873914ddf8SEdward Tomasz Napierala } else if (yytext[0] == '-') { 7883914ddf8SEdward Tomasz Napierala if (options != NULL) { 7893914ddf8SEdward Tomasz Napierala log_errx(1, "duplicated options at %s, line %d", 7903914ddf8SEdward Tomasz Napierala map, lineno); 7913914ddf8SEdward Tomasz Napierala } 7923914ddf8SEdward Tomasz Napierala /* 7933914ddf8SEdward Tomasz Napierala * +1 to skip leading "-". 7943914ddf8SEdward Tomasz Napierala */ 7953914ddf8SEdward Tomasz Napierala options = checked_strdup(yytext + 1); 7963914ddf8SEdward Tomasz Napierala continue; 7973914ddf8SEdward Tomasz Napierala } 7983914ddf8SEdward Tomasz Napierala 7993914ddf8SEdward Tomasz Napierala /* 8003914ddf8SEdward Tomasz Napierala * We cannot properly handle a situation where the map key 8013914ddf8SEdward Tomasz Napierala * is "/". Ignore such entries. 8023914ddf8SEdward Tomasz Napierala * 8033914ddf8SEdward Tomasz Napierala * XXX: According to Piete Brooks, Linux automounter uses 8043914ddf8SEdward Tomasz Napierala * "/" as a wildcard character in LDAP maps. Perhaps 8053914ddf8SEdward Tomasz Napierala * we should work around this braindamage by substituting 8063914ddf8SEdward Tomasz Napierala * "*" for "/"? 8073914ddf8SEdward Tomasz Napierala */ 8083914ddf8SEdward Tomasz Napierala if (strcmp(key, "/") == 0) { 8093914ddf8SEdward Tomasz Napierala log_warnx("nonsensical map key \"/\" at %s, line %d; " 8103914ddf8SEdward Tomasz Napierala "ignoring map entry ", map, lineno); 8113914ddf8SEdward Tomasz Napierala 8123914ddf8SEdward Tomasz Napierala /* 8133914ddf8SEdward Tomasz Napierala * Skip the rest of the entry. 8143914ddf8SEdward Tomasz Napierala */ 8153914ddf8SEdward Tomasz Napierala do { 8163914ddf8SEdward Tomasz Napierala ret = yylex(); 8173914ddf8SEdward Tomasz Napierala } while (ret != 0 && ret != NEWLINE); 8183914ddf8SEdward Tomasz Napierala 8193914ddf8SEdward Tomasz Napierala key = options = NULL; 8203914ddf8SEdward Tomasz Napierala continue; 8213914ddf8SEdward Tomasz Napierala } 8223914ddf8SEdward Tomasz Napierala 8233914ddf8SEdward Tomasz Napierala //log_debugx("adding map node, %s", key); 8243914ddf8SEdward Tomasz Napierala node = node_new(parent, key, options, NULL, map, lineno); 8253914ddf8SEdward Tomasz Napierala key = options = NULL; 8263914ddf8SEdward Tomasz Napierala 8273914ddf8SEdward Tomasz Napierala for (;;) { 8283914ddf8SEdward Tomasz Napierala if (yytext[0] == '/') { 8293914ddf8SEdward Tomasz Napierala if (mountpoint != NULL) { 8303914ddf8SEdward Tomasz Napierala log_errx(1, "duplicated mountpoint " 8313914ddf8SEdward Tomasz Napierala "in %s, line %d", map, lineno); 8323914ddf8SEdward Tomasz Napierala } 8333914ddf8SEdward Tomasz Napierala if (options2 != NULL || location != NULL) { 8343914ddf8SEdward Tomasz Napierala log_errx(1, "mountpoint out of order " 8353914ddf8SEdward Tomasz Napierala "in %s, line %d", map, lineno); 8363914ddf8SEdward Tomasz Napierala } 8373914ddf8SEdward Tomasz Napierala mountpoint = checked_strdup(yytext); 8383914ddf8SEdward Tomasz Napierala goto again; 8393914ddf8SEdward Tomasz Napierala } 8403914ddf8SEdward Tomasz Napierala 8413914ddf8SEdward Tomasz Napierala if (yytext[0] == '-') { 8423914ddf8SEdward Tomasz Napierala if (options2 != NULL) { 8433914ddf8SEdward Tomasz Napierala log_errx(1, "duplicated options " 8443914ddf8SEdward Tomasz Napierala "in %s, line %d", map, lineno); 8453914ddf8SEdward Tomasz Napierala } 8463914ddf8SEdward Tomasz Napierala if (location != NULL) { 8473914ddf8SEdward Tomasz Napierala log_errx(1, "options out of order " 8483914ddf8SEdward Tomasz Napierala "in %s, line %d", map, lineno); 8493914ddf8SEdward Tomasz Napierala } 8503914ddf8SEdward Tomasz Napierala options2 = checked_strdup(yytext + 1); 8513914ddf8SEdward Tomasz Napierala goto again; 8523914ddf8SEdward Tomasz Napierala } 8533914ddf8SEdward Tomasz Napierala 8543914ddf8SEdward Tomasz Napierala if (location != NULL) { 8553914ddf8SEdward Tomasz Napierala log_errx(1, "too many arguments " 8563914ddf8SEdward Tomasz Napierala "in %s, line %d", map, lineno); 8573914ddf8SEdward Tomasz Napierala } 8583914ddf8SEdward Tomasz Napierala 8593914ddf8SEdward Tomasz Napierala /* 8603914ddf8SEdward Tomasz Napierala * If location field starts with colon, e.g. ":/dev/cd0", 8613914ddf8SEdward Tomasz Napierala * then strip it. 8623914ddf8SEdward Tomasz Napierala */ 8633914ddf8SEdward Tomasz Napierala if (yytext[0] == ':') { 8643914ddf8SEdward Tomasz Napierala location = checked_strdup(yytext + 1); 8653914ddf8SEdward Tomasz Napierala if (location[0] == '\0') { 8663914ddf8SEdward Tomasz Napierala log_errx(1, "empty location in %s, " 8673914ddf8SEdward Tomasz Napierala "line %d", map, lineno); 8683914ddf8SEdward Tomasz Napierala } 8693914ddf8SEdward Tomasz Napierala } else { 8703914ddf8SEdward Tomasz Napierala location = checked_strdup(yytext); 8713914ddf8SEdward Tomasz Napierala } 8723914ddf8SEdward Tomasz Napierala 8733914ddf8SEdward Tomasz Napierala if (mountpoint == NULL) 8743914ddf8SEdward Tomasz Napierala mountpoint = checked_strdup("/"); 8753914ddf8SEdward Tomasz Napierala if (options2 == NULL) 8763914ddf8SEdward Tomasz Napierala options2 = checked_strdup(""); 8773914ddf8SEdward Tomasz Napierala 8783914ddf8SEdward Tomasz Napierala #if 0 8793914ddf8SEdward Tomasz Napierala log_debugx("adding map node, %s %s %s", 8803914ddf8SEdward Tomasz Napierala mountpoint, options2, location); 8813914ddf8SEdward Tomasz Napierala #endif 8823914ddf8SEdward Tomasz Napierala node_new(node, mountpoint, options2, location, 8833914ddf8SEdward Tomasz Napierala map, lineno); 8843914ddf8SEdward Tomasz Napierala mountpoint = options2 = location = NULL; 8853914ddf8SEdward Tomasz Napierala again: 8863914ddf8SEdward Tomasz Napierala ret = yylex(); 8873914ddf8SEdward Tomasz Napierala if (ret == 0 || ret == NEWLINE) { 8883914ddf8SEdward Tomasz Napierala if (mountpoint != NULL || options2 != NULL || 8893914ddf8SEdward Tomasz Napierala location != NULL) { 8903914ddf8SEdward Tomasz Napierala log_errx(1, "truncated entry " 8913914ddf8SEdward Tomasz Napierala "in %s, line %d", map, lineno); 8923914ddf8SEdward Tomasz Napierala } 8933914ddf8SEdward Tomasz Napierala break; 8943914ddf8SEdward Tomasz Napierala } 8953914ddf8SEdward Tomasz Napierala } 8963914ddf8SEdward Tomasz Napierala } 8973914ddf8SEdward Tomasz Napierala } 8983914ddf8SEdward Tomasz Napierala 899f7ae8307SEdward Tomasz Napierala /* 9003dd80c05SEdward Tomasz Napierala * Parse output of a special map called without argument. It is a list 9013dd80c05SEdward Tomasz Napierala * of keys, separated by newlines. They can contain whitespace, so use 9023dd80c05SEdward Tomasz Napierala * getline(3) instead of lexer used for maps. 903f7ae8307SEdward Tomasz Napierala */ 904f7ae8307SEdward Tomasz Napierala static void 905f7ae8307SEdward Tomasz Napierala parse_map_keys_yyin(struct node *parent, const char *map) 906f7ae8307SEdward Tomasz Napierala { 9073dd80c05SEdward Tomasz Napierala char *line = NULL, *key; 9083dd80c05SEdward Tomasz Napierala size_t linecap = 0; 9093dd80c05SEdward Tomasz Napierala ssize_t linelen; 910f7ae8307SEdward Tomasz Napierala 911f7ae8307SEdward Tomasz Napierala lineno = 1; 912f7ae8307SEdward Tomasz Napierala 913f7ae8307SEdward Tomasz Napierala for (;;) { 9143dd80c05SEdward Tomasz Napierala linelen = getline(&line, &linecap, yyin); 9153dd80c05SEdward Tomasz Napierala if (linelen < 0) { 916f7ae8307SEdward Tomasz Napierala /* 917f7ae8307SEdward Tomasz Napierala * End of file. 918f7ae8307SEdward Tomasz Napierala */ 919f7ae8307SEdward Tomasz Napierala break; 920f7ae8307SEdward Tomasz Napierala } 9213dd80c05SEdward Tomasz Napierala if (linelen <= 1) { 9223dd80c05SEdward Tomasz Napierala /* 9233dd80c05SEdward Tomasz Napierala * Empty line, consisting of just the newline. 9243dd80c05SEdward Tomasz Napierala */ 9253dd80c05SEdward Tomasz Napierala continue; 926f7ae8307SEdward Tomasz Napierala } 9273dd80c05SEdward Tomasz Napierala 9283dd80c05SEdward Tomasz Napierala /* 9293dd80c05SEdward Tomasz Napierala * "-1" to strip the trailing newline. 9303dd80c05SEdward Tomasz Napierala */ 9313dd80c05SEdward Tomasz Napierala key = strndup(line, linelen - 1); 9323dd80c05SEdward Tomasz Napierala 9333dd80c05SEdward Tomasz Napierala log_debugx("adding key \"%s\"", key); 9343dd80c05SEdward Tomasz Napierala node_new(parent, key, NULL, NULL, map, lineno); 9353dd80c05SEdward Tomasz Napierala lineno++; 9363dd80c05SEdward Tomasz Napierala } 9373dd80c05SEdward Tomasz Napierala free(line); 938f7ae8307SEdward Tomasz Napierala } 939f7ae8307SEdward Tomasz Napierala 9403914ddf8SEdward Tomasz Napierala static bool 9413914ddf8SEdward Tomasz Napierala file_is_executable(const char *path) 9423914ddf8SEdward Tomasz Napierala { 9433914ddf8SEdward Tomasz Napierala struct stat sb; 9443914ddf8SEdward Tomasz Napierala int error; 9453914ddf8SEdward Tomasz Napierala 9463914ddf8SEdward Tomasz Napierala error = stat(path, &sb); 9473914ddf8SEdward Tomasz Napierala if (error != 0) 9483914ddf8SEdward Tomasz Napierala log_err(1, "cannot stat %s", path); 9493914ddf8SEdward Tomasz Napierala if ((sb.st_mode & S_IXUSR) || (sb.st_mode & S_IXGRP) || 9503914ddf8SEdward Tomasz Napierala (sb.st_mode & S_IXOTH)) 9513914ddf8SEdward Tomasz Napierala return (true); 9523914ddf8SEdward Tomasz Napierala return (false); 9533914ddf8SEdward Tomasz Napierala } 9543914ddf8SEdward Tomasz Napierala 9553914ddf8SEdward Tomasz Napierala /* 9563914ddf8SEdward Tomasz Napierala * Parse a special map, e.g. "-hosts". 9573914ddf8SEdward Tomasz Napierala */ 9583914ddf8SEdward Tomasz Napierala static void 9593914ddf8SEdward Tomasz Napierala parse_special_map(struct node *parent, const char *map, const char *key) 9603914ddf8SEdward Tomasz Napierala { 9613914ddf8SEdward Tomasz Napierala char *path; 9623914ddf8SEdward Tomasz Napierala int error, ret; 9633914ddf8SEdward Tomasz Napierala 9643914ddf8SEdward Tomasz Napierala assert(map[0] == '-'); 9653914ddf8SEdward Tomasz Napierala 9663914ddf8SEdward Tomasz Napierala /* 9673914ddf8SEdward Tomasz Napierala * +1 to skip leading "-" in map name. 9683914ddf8SEdward Tomasz Napierala */ 9693914ddf8SEdward Tomasz Napierala ret = asprintf(&path, "%s/special_%s", AUTO_SPECIAL_PREFIX, map + 1); 9703914ddf8SEdward Tomasz Napierala if (ret < 0) 9713914ddf8SEdward Tomasz Napierala log_err(1, "asprintf"); 9723914ddf8SEdward Tomasz Napierala 9733914ddf8SEdward Tomasz Napierala yyin = auto_popen(path, key, NULL); 9743914ddf8SEdward Tomasz Napierala assert(yyin != NULL); 9753914ddf8SEdward Tomasz Napierala 976f7ae8307SEdward Tomasz Napierala if (key == NULL) { 977f7ae8307SEdward Tomasz Napierala parse_map_keys_yyin(parent, map); 978f7ae8307SEdward Tomasz Napierala } else { 9793914ddf8SEdward Tomasz Napierala parse_map_yyin(parent, map, key); 980f7ae8307SEdward Tomasz Napierala } 9813914ddf8SEdward Tomasz Napierala 9823914ddf8SEdward Tomasz Napierala error = auto_pclose(yyin); 9833914ddf8SEdward Tomasz Napierala yyin = NULL; 9843914ddf8SEdward Tomasz Napierala if (error != 0) 9853914ddf8SEdward Tomasz Napierala log_errx(1, "failed to handle special map \"%s\"", map); 9863914ddf8SEdward Tomasz Napierala 9873914ddf8SEdward Tomasz Napierala node_expand_includes(parent, false); 9883914ddf8SEdward Tomasz Napierala node_expand_direct_maps(parent); 9893914ddf8SEdward Tomasz Napierala 9903914ddf8SEdward Tomasz Napierala free(path); 9913914ddf8SEdward Tomasz Napierala } 9923914ddf8SEdward Tomasz Napierala 9933914ddf8SEdward Tomasz Napierala /* 9943914ddf8SEdward Tomasz Napierala * Retrieve and parse map from directory services, e.g. LDAP. 9953914ddf8SEdward Tomasz Napierala * Note that it is different from executable maps, in that 9963914ddf8SEdward Tomasz Napierala * the include script outputs the whole map to standard output 9973914ddf8SEdward Tomasz Napierala * (as opposed to executable maps that only output a single 9983914ddf8SEdward Tomasz Napierala * entry, without the key), and it takes the map name as an 9993914ddf8SEdward Tomasz Napierala * argument, instead of key. 10003914ddf8SEdward Tomasz Napierala */ 10013914ddf8SEdward Tomasz Napierala static void 10023914ddf8SEdward Tomasz Napierala parse_included_map(struct node *parent, const char *map) 10033914ddf8SEdward Tomasz Napierala { 10043914ddf8SEdward Tomasz Napierala int error; 10053914ddf8SEdward Tomasz Napierala 10063914ddf8SEdward Tomasz Napierala assert(map[0] != '-'); 10073914ddf8SEdward Tomasz Napierala assert(map[0] != '/'); 10083914ddf8SEdward Tomasz Napierala 10093914ddf8SEdward Tomasz Napierala error = access(AUTO_INCLUDE_PATH, F_OK); 10103914ddf8SEdward Tomasz Napierala if (error != 0) { 10113914ddf8SEdward Tomasz Napierala log_errx(1, "directory services not configured;" 10123914ddf8SEdward Tomasz Napierala " %s does not exist", AUTO_INCLUDE_PATH); 10133914ddf8SEdward Tomasz Napierala } 10143914ddf8SEdward Tomasz Napierala 10153914ddf8SEdward Tomasz Napierala yyin = auto_popen(AUTO_INCLUDE_PATH, map, NULL); 10163914ddf8SEdward Tomasz Napierala assert(yyin != NULL); 10173914ddf8SEdward Tomasz Napierala 10183914ddf8SEdward Tomasz Napierala parse_map_yyin(parent, map, NULL); 10193914ddf8SEdward Tomasz Napierala 10203914ddf8SEdward Tomasz Napierala error = auto_pclose(yyin); 10213914ddf8SEdward Tomasz Napierala yyin = NULL; 10223914ddf8SEdward Tomasz Napierala if (error != 0) 10233914ddf8SEdward Tomasz Napierala log_errx(1, "failed to handle remote map \"%s\"", map); 10243914ddf8SEdward Tomasz Napierala 10253914ddf8SEdward Tomasz Napierala node_expand_includes(parent, false); 10263914ddf8SEdward Tomasz Napierala node_expand_direct_maps(parent); 10273914ddf8SEdward Tomasz Napierala } 10283914ddf8SEdward Tomasz Napierala 10293914ddf8SEdward Tomasz Napierala void 10304cdc52bdSEdward Tomasz Napierala parse_map(struct node *parent, const char *map, const char *key, 10314cdc52bdSEdward Tomasz Napierala bool *wildcards) 10323914ddf8SEdward Tomasz Napierala { 10333914ddf8SEdward Tomasz Napierala char *path = NULL; 10343914ddf8SEdward Tomasz Napierala int error, ret; 10353914ddf8SEdward Tomasz Napierala bool executable; 10363914ddf8SEdward Tomasz Napierala 10373914ddf8SEdward Tomasz Napierala assert(map != NULL); 10383914ddf8SEdward Tomasz Napierala assert(map[0] != '\0'); 10393914ddf8SEdward Tomasz Napierala 10403914ddf8SEdward Tomasz Napierala log_debugx("parsing map \"%s\"", map); 10413914ddf8SEdward Tomasz Napierala 10424cdc52bdSEdward Tomasz Napierala if (wildcards != NULL) 10434cdc52bdSEdward Tomasz Napierala *wildcards = false; 10444cdc52bdSEdward Tomasz Napierala 10454cdc52bdSEdward Tomasz Napierala if (map[0] == '-') { 10464cdc52bdSEdward Tomasz Napierala if (wildcards != NULL) 10474cdc52bdSEdward Tomasz Napierala *wildcards = true; 10483914ddf8SEdward Tomasz Napierala return (parse_special_map(parent, map, key)); 10494cdc52bdSEdward Tomasz Napierala } 10503914ddf8SEdward Tomasz Napierala 10513914ddf8SEdward Tomasz Napierala if (map[0] == '/') { 10523914ddf8SEdward Tomasz Napierala path = checked_strdup(map); 10533914ddf8SEdward Tomasz Napierala } else { 10543914ddf8SEdward Tomasz Napierala ret = asprintf(&path, "%s/%s", AUTO_MAP_PREFIX, map); 10553914ddf8SEdward Tomasz Napierala if (ret < 0) 10563914ddf8SEdward Tomasz Napierala log_err(1, "asprintf"); 10573914ddf8SEdward Tomasz Napierala log_debugx("map \"%s\" maps to \"%s\"", map, path); 10583914ddf8SEdward Tomasz Napierala 10593914ddf8SEdward Tomasz Napierala /* 10603914ddf8SEdward Tomasz Napierala * See if the file exists. If not, try to obtain the map 10613914ddf8SEdward Tomasz Napierala * from directory services. 10623914ddf8SEdward Tomasz Napierala */ 10633914ddf8SEdward Tomasz Napierala error = access(path, F_OK); 10643914ddf8SEdward Tomasz Napierala if (error != 0) { 10653914ddf8SEdward Tomasz Napierala log_debugx("map file \"%s\" does not exist; falling " 10663914ddf8SEdward Tomasz Napierala "back to directory services", path); 10673914ddf8SEdward Tomasz Napierala return (parse_included_map(parent, map)); 10683914ddf8SEdward Tomasz Napierala } 10693914ddf8SEdward Tomasz Napierala } 10703914ddf8SEdward Tomasz Napierala 10713914ddf8SEdward Tomasz Napierala executable = file_is_executable(path); 10723914ddf8SEdward Tomasz Napierala 10733914ddf8SEdward Tomasz Napierala if (executable) { 10743914ddf8SEdward Tomasz Napierala log_debugx("map \"%s\" is executable", map); 10753914ddf8SEdward Tomasz Napierala 10764cdc52bdSEdward Tomasz Napierala if (wildcards != NULL) 10774cdc52bdSEdward Tomasz Napierala *wildcards = true; 10784cdc52bdSEdward Tomasz Napierala 10793914ddf8SEdward Tomasz Napierala if (key != NULL) { 10803914ddf8SEdward Tomasz Napierala yyin = auto_popen(path, key, NULL); 10813914ddf8SEdward Tomasz Napierala } else { 10823914ddf8SEdward Tomasz Napierala yyin = auto_popen(path, NULL); 10833914ddf8SEdward Tomasz Napierala } 10843914ddf8SEdward Tomasz Napierala assert(yyin != NULL); 10853914ddf8SEdward Tomasz Napierala } else { 10863914ddf8SEdward Tomasz Napierala yyin = fopen(path, "r"); 10873914ddf8SEdward Tomasz Napierala if (yyin == NULL) 10883914ddf8SEdward Tomasz Napierala log_err(1, "unable to open \"%s\"", path); 10893914ddf8SEdward Tomasz Napierala } 10903914ddf8SEdward Tomasz Napierala 10913914ddf8SEdward Tomasz Napierala free(path); 10923914ddf8SEdward Tomasz Napierala path = NULL; 10933914ddf8SEdward Tomasz Napierala 10943914ddf8SEdward Tomasz Napierala parse_map_yyin(parent, map, executable ? key : NULL); 10953914ddf8SEdward Tomasz Napierala 10963914ddf8SEdward Tomasz Napierala if (executable) { 10973914ddf8SEdward Tomasz Napierala error = auto_pclose(yyin); 10983914ddf8SEdward Tomasz Napierala yyin = NULL; 10993914ddf8SEdward Tomasz Napierala if (error != 0) { 11003914ddf8SEdward Tomasz Napierala log_errx(1, "failed to handle executable map \"%s\"", 11013914ddf8SEdward Tomasz Napierala map); 11023914ddf8SEdward Tomasz Napierala } 11033914ddf8SEdward Tomasz Napierala } else { 11043914ddf8SEdward Tomasz Napierala fclose(yyin); 11053914ddf8SEdward Tomasz Napierala } 11063914ddf8SEdward Tomasz Napierala yyin = NULL; 11073914ddf8SEdward Tomasz Napierala 11083914ddf8SEdward Tomasz Napierala log_debugx("done parsing map \"%s\"", map); 11093914ddf8SEdward Tomasz Napierala 11103914ddf8SEdward Tomasz Napierala node_expand_includes(parent, false); 11113914ddf8SEdward Tomasz Napierala node_expand_direct_maps(parent); 11123914ddf8SEdward Tomasz Napierala } 11133914ddf8SEdward Tomasz Napierala 11143914ddf8SEdward Tomasz Napierala static void 11153914ddf8SEdward Tomasz Napierala parse_master_yyin(struct node *root, const char *master) 11163914ddf8SEdward Tomasz Napierala { 11173914ddf8SEdward Tomasz Napierala char *mountpoint = NULL, *map = NULL, *options = NULL; 11183914ddf8SEdward Tomasz Napierala int ret; 11193914ddf8SEdward Tomasz Napierala 11203914ddf8SEdward Tomasz Napierala /* 11213914ddf8SEdward Tomasz Napierala * XXX: 1 gives incorrect values; wtf? 11223914ddf8SEdward Tomasz Napierala */ 11233914ddf8SEdward Tomasz Napierala lineno = 0; 11243914ddf8SEdward Tomasz Napierala 11253914ddf8SEdward Tomasz Napierala for (;;) { 11263914ddf8SEdward Tomasz Napierala ret = yylex(); 11273914ddf8SEdward Tomasz Napierala if (ret == 0 || ret == NEWLINE) { 11283914ddf8SEdward Tomasz Napierala if (mountpoint != NULL) { 11293914ddf8SEdward Tomasz Napierala //log_debugx("adding map for %s", mountpoint); 11303914ddf8SEdward Tomasz Napierala node_new_map(root, mountpoint, options, map, 11313914ddf8SEdward Tomasz Napierala master, lineno); 11323914ddf8SEdward Tomasz Napierala } 11333914ddf8SEdward Tomasz Napierala if (ret == 0) { 11343914ddf8SEdward Tomasz Napierala break; 11353914ddf8SEdward Tomasz Napierala } else { 11363914ddf8SEdward Tomasz Napierala mountpoint = map = options = NULL; 11373914ddf8SEdward Tomasz Napierala continue; 11383914ddf8SEdward Tomasz Napierala } 11393914ddf8SEdward Tomasz Napierala } 11403914ddf8SEdward Tomasz Napierala if (mountpoint == NULL) { 11413914ddf8SEdward Tomasz Napierala mountpoint = checked_strdup(yytext); 11423914ddf8SEdward Tomasz Napierala } else if (map == NULL) { 11433914ddf8SEdward Tomasz Napierala map = checked_strdup(yytext); 11443914ddf8SEdward Tomasz Napierala } else if (options == NULL) { 11453914ddf8SEdward Tomasz Napierala /* 11463914ddf8SEdward Tomasz Napierala * +1 to skip leading "-". 11473914ddf8SEdward Tomasz Napierala */ 11483914ddf8SEdward Tomasz Napierala options = checked_strdup(yytext + 1); 11493914ddf8SEdward Tomasz Napierala } else { 11503914ddf8SEdward Tomasz Napierala log_errx(1, "too many arguments at %s, line %d", 11513914ddf8SEdward Tomasz Napierala master, lineno); 11523914ddf8SEdward Tomasz Napierala } 11533914ddf8SEdward Tomasz Napierala } 11543914ddf8SEdward Tomasz Napierala } 11553914ddf8SEdward Tomasz Napierala 11563914ddf8SEdward Tomasz Napierala void 11573914ddf8SEdward Tomasz Napierala parse_master(struct node *root, const char *master) 11583914ddf8SEdward Tomasz Napierala { 11593914ddf8SEdward Tomasz Napierala 11603914ddf8SEdward Tomasz Napierala log_debugx("parsing auto_master file at \"%s\"", master); 11613914ddf8SEdward Tomasz Napierala 11623914ddf8SEdward Tomasz Napierala yyin = fopen(master, "r"); 11633914ddf8SEdward Tomasz Napierala if (yyin == NULL) 11643914ddf8SEdward Tomasz Napierala err(1, "unable to open %s", master); 11653914ddf8SEdward Tomasz Napierala 11663914ddf8SEdward Tomasz Napierala parse_master_yyin(root, master); 11673914ddf8SEdward Tomasz Napierala 11683914ddf8SEdward Tomasz Napierala fclose(yyin); 11693914ddf8SEdward Tomasz Napierala yyin = NULL; 11703914ddf8SEdward Tomasz Napierala 11713914ddf8SEdward Tomasz Napierala log_debugx("done parsing \"%s\"", master); 11723914ddf8SEdward Tomasz Napierala 11733914ddf8SEdward Tomasz Napierala node_expand_includes(root, true); 11743914ddf8SEdward Tomasz Napierala node_expand_direct_maps(root); 11753914ddf8SEdward Tomasz Napierala } 11763914ddf8SEdward Tomasz Napierala 11773914ddf8SEdward Tomasz Napierala /* 11783914ddf8SEdward Tomasz Napierala * Two things daemon(3) does, that we actually also want to do 11793914ddf8SEdward Tomasz Napierala * when running in foreground, is closing the stdin and chdiring 11803914ddf8SEdward Tomasz Napierala * to "/". This is what we do here. 11813914ddf8SEdward Tomasz Napierala */ 11823914ddf8SEdward Tomasz Napierala void 11833914ddf8SEdward Tomasz Napierala lesser_daemon(void) 11843914ddf8SEdward Tomasz Napierala { 11853914ddf8SEdward Tomasz Napierala int error, fd; 11863914ddf8SEdward Tomasz Napierala 11873914ddf8SEdward Tomasz Napierala error = chdir("/"); 11883914ddf8SEdward Tomasz Napierala if (error != 0) 11893914ddf8SEdward Tomasz Napierala log_warn("chdir"); 11903914ddf8SEdward Tomasz Napierala 11913914ddf8SEdward Tomasz Napierala fd = open(_PATH_DEVNULL, O_RDWR, 0); 11923914ddf8SEdward Tomasz Napierala if (fd < 0) { 11933914ddf8SEdward Tomasz Napierala log_warn("cannot open %s", _PATH_DEVNULL); 11943914ddf8SEdward Tomasz Napierala return; 11953914ddf8SEdward Tomasz Napierala } 11963914ddf8SEdward Tomasz Napierala 11973914ddf8SEdward Tomasz Napierala error = dup2(fd, STDIN_FILENO); 11983914ddf8SEdward Tomasz Napierala if (error != 0) 11993914ddf8SEdward Tomasz Napierala log_warn("dup2"); 12003914ddf8SEdward Tomasz Napierala 12013914ddf8SEdward Tomasz Napierala error = close(fd); 12023914ddf8SEdward Tomasz Napierala if (error != 0) { 12033914ddf8SEdward Tomasz Napierala /* Bloody hell. */ 12043914ddf8SEdward Tomasz Napierala log_warn("close"); 12053914ddf8SEdward Tomasz Napierala } 12063914ddf8SEdward Tomasz Napierala } 12073914ddf8SEdward Tomasz Napierala 12083914ddf8SEdward Tomasz Napierala int 12093914ddf8SEdward Tomasz Napierala main(int argc, char **argv) 12103914ddf8SEdward Tomasz Napierala { 12113914ddf8SEdward Tomasz Napierala char *cmdname; 12123914ddf8SEdward Tomasz Napierala 12133914ddf8SEdward Tomasz Napierala if (argv[0] == NULL) 12143914ddf8SEdward Tomasz Napierala log_errx(1, "NULL command name"); 12153914ddf8SEdward Tomasz Napierala 12163914ddf8SEdward Tomasz Napierala cmdname = basename(argv[0]); 12173914ddf8SEdward Tomasz Napierala 12183914ddf8SEdward Tomasz Napierala if (strcmp(cmdname, "automount") == 0) 12193914ddf8SEdward Tomasz Napierala return (main_automount(argc, argv)); 12203914ddf8SEdward Tomasz Napierala else if (strcmp(cmdname, "automountd") == 0) 12213914ddf8SEdward Tomasz Napierala return (main_automountd(argc, argv)); 12223914ddf8SEdward Tomasz Napierala else if (strcmp(cmdname, "autounmountd") == 0) 12233914ddf8SEdward Tomasz Napierala return (main_autounmountd(argc, argv)); 12243914ddf8SEdward Tomasz Napierala else 12253914ddf8SEdward Tomasz Napierala log_errx(1, "binary name should be either \"automount\", " 12263914ddf8SEdward Tomasz Napierala "\"automountd\", or \"autounmountd\""); 12273914ddf8SEdward Tomasz Napierala } 1228