blob: 84ca5ca109211a8a309019531ff1e8547be6407e [file] [log] [blame]
%{
/* ----------------------------------------------------------------------- *
*
* master_parser.y - master map buffer parser.
*
* Copyright 2006 Ian Kent <raven@themaw.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
* USA; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ----------------------------------------------------------------------- */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include "automount.h"
#include "master.h"
#define MAX_ERR_LEN 512
extern struct master *master_list;
char **add_argv(int, char **, char *);
const char **copy_argv(int, const char **);
int free_argv(int, const char **);
extern FILE *master_in;
extern char *master_text;
extern int master_lex(void);
extern int master_lineno;
extern void master_set_scan_buffer(const char *);
static char *master_strdup(char *);
static void local_init_vars(void);
static void local_free_vars(void);
static void trim_maptype(char *);
static int add_multi_mapstr(void);
static int master_error(const char *s);
static int master_notify(const char *s);
static int master_msg(const char *s);
static char *path;
static char *type;
static char *format;
static long timeout;
static long negative_timeout;
static unsigned symlnk;
static unsigned slave;
static unsigned private;
static unsigned nobind;
static unsigned ghost;
extern unsigned global_selection_options;
static unsigned random_selection;
static unsigned use_weight;
static unsigned long mode;
static char **tmp_argv;
static int tmp_argc;
static char **local_argv;
static int local_argc;
static char errstr[MAX_ERR_LEN];
static unsigned int verbose;
static unsigned int debug;
static int lineno;
#define YYDEBUG 0
#ifndef YYENABLE_NLS
#define YYENABLE_NLS 0
#endif
#ifndef YYLTYPE_IS_TRIVIAL
#define YYLTYPE_IS_TRIVIAL 0
#endif
#if YYDEBUG
static int master_fprintf(FILE *, char *, ...);
#undef YYFPRINTF
#define YYFPRINTF master_fprintf
#endif
%}
%union {
char strtype[2048];
int inttype;
long longtype;
}
%token COMMENT
%token MAP
%token OPT_TIMEOUT OPT_NTIMEOUT OPT_NOBIND OPT_NOGHOST OPT_GHOST OPT_VERBOSE
%token OPT_DEBUG OPT_RANDOM OPT_USE_WEIGHT OPT_SYMLINK OPT_MODE
%token OPT_SLAVE OPT_PRIVATE
%token COLON COMMA NL DDASH
%type <strtype> map
%type <strtype> options
%type <strtype> dn
%type <strtype> dnattrs
%type <strtype> dnattr
%type <strtype> option
%type <strtype> daemon_option
%type <strtype> mount_option
%token <strtype> PATH
%token <strtype> QUOTE
%token <strtype> NILL
%token <strtype> SPACE
%token <strtype> EQUAL
%token <strtype> MULTITYPE
%token <strtype> MAPTYPE
%token <strtype> DNSERVER
%token <strtype> DNATTR
%token <strtype> DNNAME
%token <strtype> MAPHOSTS
%token <strtype> MAPNULL
%token <strtype> MAPXFN
%token <strtype> MAPNAME
%token <longtype> NUMBER
%token <longtype> OCTALNUMBER
%token <strtype> OPTION
%start file
%%
file: {
master_lineno = 0;
#if YYDEBUG != 0
master_debug = YYDEBUG;
#endif
} line
;
line:
| PATH mapspec
{
path = master_strdup($1);
if (!path) {
local_free_vars();
YYABORT;
}
}
| PATH MULTITYPE maplist
{
char *tmp = NULL;
trim_maptype($2);
if (path)
free(path);
path = master_strdup($1);
if (!path) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
if ((tmp = strchr($2, ',')))
*tmp++ = '\0';
if (type)
free(type);
type = master_strdup($2);
if (!type) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
if (tmp) {
if (format)
free(format);
format = master_strdup(tmp);
if (!format) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
}
| PATH COLON { master_notify($1); YYABORT; }
| PATH OPTION { master_notify($2); YYABORT; }
| PATH NILL { master_notify($2); YYABORT; }
| PATH OPT_RANDOM { master_notify($1); YYABORT; }
| PATH OPT_USE_WEIGHT { master_notify($1); YYABORT; }
| PATH OPT_DEBUG { master_notify($1); YYABORT; }
| PATH OPT_TIMEOUT { master_notify($1); YYABORT; }
| PATH OPT_SYMLINK { master_notify($1); YYABORT; }
| PATH OPT_SLAVE { master_notify($1); YYABORT; }
| PATH OPT_PRIVATE { master_notify($1); YYABORT; }
| PATH OPT_NOBIND { master_notify($1); YYABORT; }
| PATH OPT_GHOST { master_notify($1); YYABORT; }
| PATH OPT_NOGHOST { master_notify($1); YYABORT; }
| PATH OPT_VERBOSE { master_notify($1); YYABORT; }
| PATH OPT_MODE { master_notify($1); YYABORT; }
| PATH { master_notify($1); YYABORT; }
| QUOTE { master_notify($1); YYABORT; }
| OPTION { master_notify($1); YYABORT; }
| NILL { master_notify($1); YYABORT; }
| COMMENT { YYABORT; }
;
mapspec: map
{
if (local_argv)
free_argv(local_argc, (const char **) local_argv);
local_argc = tmp_argc;
local_argv = tmp_argv;
tmp_argc = 0;
tmp_argv = NULL;
}
| map options
{
if (local_argv)
free_argv(local_argc, (const char **) local_argv);
local_argc = tmp_argc;
local_argv = tmp_argv;
tmp_argc = 0;
tmp_argv = NULL;
}
;
maplist: map
{
if (!add_multi_mapstr()) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
| map options
{
if (!add_multi_mapstr()) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
| maplist DDASH map
{
local_argc++;
local_argv = add_argv(local_argc, local_argv, "--");
if (!local_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
if (!add_multi_mapstr()) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
| maplist DDASH map options
{
local_argc++;
local_argv = add_argv(local_argc, local_argv, "--");
if (!local_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
if (!add_multi_mapstr()) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
;
map: PATH
{
tmp_argc++;
tmp_argv = add_argv(tmp_argc, tmp_argv, $1);
if (!tmp_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
| MAPNAME
{
tmp_argc++;
tmp_argv = add_argv(tmp_argc, tmp_argv, $1);
if (!tmp_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
| MAPHOSTS
{
if (type)
free(type);
type = master_strdup($1 + 1);
if (!type) {
local_free_vars();
YYABORT;
}
}
| MAPXFN
{
master_notify($1);
master_msg("X/Open Federated Naming service not supported");
YYABORT;
}
| MAPNULL
{
if (type)
free(type);
type = master_strdup($1 + 1);
if (!type) {
local_free_vars();
YYABORT;
}
}
| dnattrs
{
if (type)
free(type);
type = master_strdup("ldap");
if (!type) {
local_free_vars();
YYABORT;
}
tmp_argc++;
tmp_argv = add_argv(tmp_argc, tmp_argv, $1);
if (!tmp_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
| MAPTYPE PATH
{
char *tmp = NULL;
trim_maptype($1);
if ((tmp = strchr($1, ',')))
*tmp++ = '\0';
if (type)
free(type);
if (strcmp($1, "exec"))
type = master_strdup($1);
else
type = master_strdup("program");
if (!type) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
if (tmp) {
if (format)
free(format);
format = master_strdup(tmp);
if (!format) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
tmp_argc++;
tmp_argv = add_argv(tmp_argc, tmp_argv, $2);
if (!tmp_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
| MAPTYPE MAPNAME
{
char *tmp = NULL;
trim_maptype($1);
if ((tmp = strchr($1, ',')))
*tmp++ = '\0';
if (type)
free(type);
if (strcmp($1, "exec"))
type = master_strdup($1);
else
type = master_strdup("program");
if (!type) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
if (tmp) {
if (format)
free(format);
format = master_strdup(tmp);
if (!format) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
tmp_argc++;
tmp_argv = add_argv(tmp_argc, tmp_argv, $2);
if (!tmp_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
| MAPTYPE dn
{
char *tmp = NULL;
trim_maptype($1);
if ((tmp = strchr($1, ',')))
*tmp++ = '\0';
if (type)
free(type);
if (strcmp($1, "exec"))
type = master_strdup($1);
else
type = master_strdup("program");
if (!type) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
if (tmp) {
if (format)
free(format);
format = master_strdup(tmp);
if (!format) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
tmp_argc++;
tmp_argv = add_argv(tmp_argc, tmp_argv, $2);
if (!tmp_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
/* Add back the type for lookup_ldap.c to handle ldaps */
if (*tmp_argv[0]) {
tmp = malloc(strlen(type) + strlen(tmp_argv[0]) + 2);
if (!tmp) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
strcpy(tmp, type);
strcat(tmp, ":");
strcat(tmp, tmp_argv[0]);
free(tmp_argv[0]);
tmp_argv[0] = tmp;
}
}
;
dn: DNSERVER dnattrs
{
strcpy($$, $1);
strcat($$, $2);
}
| dnattrs
{
strcpy($$, $1);
}
|
{
master_notify("syntax error in dn");
YYABORT;
}
;
dnattrs: DNATTR EQUAL DNNAME
{
if (strcasecmp($1, "cn") &&
strcasecmp($1, "ou") &&
strcasecmp($1, "automountMapName") &&
strcasecmp($1, "nisMapName")) {
strcpy(errstr, $1);
strcat(errstr, "=");
strcat(errstr, $3);
master_notify(errstr);
YYABORT;
}
strcpy($$, $1);
strcat($$, "=");
strcat($$, $3);
}
| DNATTR EQUAL DNNAME COMMA dnattr
{
if (strcasecmp($1, "cn") &&
strcasecmp($1, "ou") &&
strcasecmp($1, "automountMapName") &&
strcasecmp($1, "nisMapName")) {
strcpy(errstr, $1);
strcat(errstr, "=");
strcat(errstr, $3);
master_notify(errstr);
YYABORT;
}
strcpy($$, $1);
strcat($$, "=");
strcat($$, $3);
strcat($$, ",");
strcat($$, $5);
}
| DNNAME
{
/* Matches map in old style syntax ldap:server:map */
strcpy($$, $1);
}
| DNATTR
{
master_notify($1);
YYABORT;
}
;
dnattr: DNATTR EQUAL DNNAME
{
if (!strcasecmp($1, "automountMapName") ||
!strcasecmp($1, "nisMapName")) {
strcpy(errstr, $1);
strcat(errstr, "=");
strcat(errstr, $3);
master_notify(errstr);
YYABORT;
}
strcpy($$, $1);
strcat($$, "=");
strcat($$, $3);
}
| DNATTR EQUAL DNNAME COMMA dnattr
{
if (!strcasecmp($1, "automountMapName") ||
!strcasecmp($1, "nisMapName")) {
strcpy(errstr, $1);
strcat(errstr, "=");
strcat(errstr, $3);
master_notify(errstr);
YYABORT;
}
strcpy($$, $1);
strcat($$, "=");
strcat($$, $3);
strcat($$, ",");
strcat($$, $5);
}
| DNATTR
{
master_notify($1);
YYABORT;
}
| DNNAME
{
master_notify($1);
YYABORT;
}
;
options: option {}
| options COMMA option {}
| options option {}
| options COMMA COMMA option
{
master_notify($1);
YYABORT;
}
| options EQUAL
{
master_notify($1);
YYABORT;
}
;
option: daemon_option
| mount_option {}
| error
{
master_notify("bogus option");
YYABORT;
}
;
daemon_option: OPT_TIMEOUT NUMBER { timeout = $2; }
| OPT_NTIMEOUT NUMBER { negative_timeout = $2; }
| OPT_SYMLINK { symlnk = 1; }
| OPT_SLAVE { slave = 1; }
| OPT_PRIVATE { private = 1; }
| OPT_NOBIND { nobind = 1; }
| OPT_NOGHOST { ghost = 0; }
| OPT_GHOST { ghost = 1; }
| OPT_VERBOSE { verbose = 1; }
| OPT_DEBUG { debug = 1; }
| OPT_RANDOM { random_selection = 1; }
| OPT_USE_WEIGHT { use_weight = 1; }
| OPT_MODE OCTALNUMBER { mode = $2; }
;
mount_option: OPTION
{
tmp_argc++;
tmp_argv = add_argv(tmp_argc, tmp_argv, $1);
if (!tmp_argv) {
master_error("memory allocation error");
local_free_vars();
YYABORT;
}
}
;
%%
#if YYDEBUG
static int master_fprintf(FILE *f, char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vsyslog(LOG_DEBUG, msg, ap);
va_end(ap);
return 1;
}
#endif
static char *master_strdup(char *str)
{
char *tmp;
tmp = strdup(str);
if (!tmp)
master_error("memory allocation error");
return tmp;
}
static int master_error(const char *s)
{
logmsg("%s while parsing map.", s);
return 0;
}
static int master_notify(const char *s)
{
logmsg("syntax error in map near [ %s ]", s);
return(0);
}
static int master_msg(const char *s)
{
logmsg("%s", s);
return 0;
}
static void local_init_vars(void)
{
path = NULL;
type = NULL;
format = NULL;
verbose = 0;
debug = 0;
timeout = -1;
negative_timeout = 0;
symlnk = 0;
slave = 0;
private = 0;
nobind = 0;
ghost = defaults_get_browse_mode();
random_selection = global_selection_options & MOUNT_FLAG_RANDOM_SELECT;
use_weight = 0;
mode = 0;
tmp_argv = NULL;
tmp_argc = 0;
local_argv = NULL;
local_argc = 0;
}
static void local_free_vars(void)
{
if (path)
free(path);
if (type)
free(type);
if (format)
free(format);
if (local_argv) {
free_argv(local_argc, (const char **) local_argv);
local_argv = NULL;
local_argc = 0;
}
if (tmp_argv) {
free_argv(tmp_argc, (const char **) tmp_argv);
tmp_argv = NULL;
tmp_argc = 0;
}
}
static void trim_maptype(char *type)
{
char *tmp;
tmp = strchr(type, ':');
if (tmp)
*tmp = '\0';
else {
int len = strlen(type);
while (len-- && isblank(type[len]))
type[len] = '\0';
}
return;
}
static int add_multi_mapstr(void)
{
if (type) {
/* If type given and format is non-null add it back */
if (format) {
int len = strlen(type) + strlen(format) + 2;
char *tmp = realloc(type, len);
if (!tmp)
return 0;
type = tmp;
strcat(type, ",");
strcat(type, format);
free(format);
format = NULL;
}
local_argc++;
local_argv = add_argv(local_argc, local_argv, type);
if (!local_argv) {
free(type);
type = NULL;
return 0;
}
free(type);
type = NULL;
}
local_argv = append_argv(local_argc, local_argv, tmp_argc, tmp_argv);
if (!local_argv) {
free(type);
type = NULL;
return 0;
}
local_argc += tmp_argc;
tmp_argc = 0;
tmp_argv = NULL;
return 1;
}
void master_init_scan(void)
{
lineno = 0;
}
int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigned int logging, time_t age)
{
struct master *master = master_list;
struct mapent_cache *nc;
struct master_mapent *entry, *new;
struct map_source *source;
unsigned int logopt = logging;
unsigned int m_logopt = master->logopt;
size_t mp_len;
int ret;
local_init_vars();
lineno++;
master_set_scan_buffer(buffer);
ret = master_parse();
if (ret != 0) {
local_free_vars();
return 0;
}
mp_len = strlen(path);
while (mp_len && path[--mp_len] == '/')
path[mp_len] = 0;
nc = master->nc;
/* Add null map entries to the null map cache */
if (type && !strcmp(type, "null")) {
cache_update(nc, NULL, path, NULL, lineno);
local_free_vars();
return 1;
}
/* Ignore all subsequent matching nulled entries */
if (cache_lookup_distinct(nc, path)) {
local_free_vars();
return 1;
}
if (debug || verbose) {
logopt = (debug ? LOGOPT_DEBUG : 0);
logopt |= (verbose ? LOGOPT_VERBOSE : 0);
}
new = NULL;
entry = master_find_mapent(master, path);
if (!entry) {
new = master_new_mapent(master, path, age);
if (!new) {
local_free_vars();
return 0;
}
entry = new;
} else {
if (entry->age && entry->age == age) {
if (strcmp(path, "/-")) {
info(m_logopt,
"ignoring duplicate indirect mount %s",
path);
local_free_vars();
return 0;
}
}
}
if (!format) {
if (conf_amd_mount_section_exists(path))
format = strdup("amd");
}
if (format && !strcmp(format, "amd")) {
unsigned int loglevel = conf_amd_get_log_options();
unsigned int flags = conf_amd_get_flags(path);
if (loglevel <= LOG_DEBUG && loglevel > LOG_INFO)
logopt = LOGOPT_DEBUG;
else if (loglevel <= LOG_INFO && loglevel > LOG_ERR)
logopt = LOGOPT_VERBOSE;
/* It isn't possible to provide the fullybrowsable amd
* browsing functionality within the autofs framework.
* This flag will not be set if browsable_dirs = full
* in the configuration or fullybrowsable is present as
* an option.
*/
if (flags & CONF_BROWSABLE_DIRS)
ghost = 1;
}
if (!entry->ap) {
ret = master_add_autofs_point(entry, logopt, nobind, ghost, 0);
if (!ret) {
error(m_logopt, "failed to add autofs_point");
if (new)
master_free_mapent(new);
local_free_vars();
return 0;
}
}
if (random_selection)
entry->ap->flags |= MOUNT_FLAG_RANDOM_SELECT;
if (use_weight)
entry->ap->flags |= MOUNT_FLAG_USE_WEIGHT_ONLY;
if (symlnk)
entry->ap->flags |= MOUNT_FLAG_SYMLINK;
if (slave)
entry->ap->flags |= MOUNT_FLAG_SLAVE;
if (private)
entry->ap->flags |= MOUNT_FLAG_PRIVATE;
if (negative_timeout)
entry->ap->negative_timeout = negative_timeout;
if (mode && mode < LONG_MAX)
entry->ap->mode = mode;
if (timeout < 0) {
/*
* If no timeout is given get the timout from the
* autofs point, or the first map, or the config
* for amd maps.
*/
if (format && !strcmp(format, "amd"))
timeout = conf_amd_get_dismount_interval(path);
else
timeout = get_exp_timeout(entry->ap, entry->maps);
}
if (format && !strcmp(format, "amd")) {
char *opts = conf_amd_get_map_options(path);
if (opts) {
/* autofs uses the equivalent of cache:=inc,sync
* (except for file maps which use cache:=all,sync)
* but if the map is large then it may be necessary
* to read the whole map at startup even if browsing
* is is not enabled, so look for cache:=all in the
* map_options configuration entry.
*/
if (strstr(opts, "cache:=all"))
entry->ap->flags |= MOUNT_FLAG_AMD_CACHE_ALL;
free(opts);
}
}
/*
source = master_find_map_source(entry, type, format,
local_argc, (const char **) local_argv);
if (!source)
source = master_add_map_source(entry, type, format, age,
local_argc, (const char **) local_argv);
else
source->age = age;
*/
source = master_add_map_source(entry, type, format, age,
local_argc, (const char **) local_argv);
if (!source) {
error(m_logopt, "failed to add source");
if (new)
master_free_mapent(new);
local_free_vars();
return 0;
}
set_exp_timeout(entry->ap, source, timeout);
source->master_line = lineno;
entry->age = age;
entry->current = NULL;
if (new)
master_add_mapent(master, entry);
local_free_vars();
return 1;
}