#ident "$Id$" /* ----------------------------------------------------------------------- * * * lookup_file.c - module for Linux automount to query a flat file map * * Copyright 1997 Transmeta Corporation - All Rights Reserved * * 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; incorporated herein by reference. * * ----------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #define MODULE_LOOKUP #include "automount.h" #define MAPFMT_DEFAULT "sun" #define MODPREFIX "lookup(file): " #define MAPENT_MAX_LEN 4095 struct lookup_context { const char *mapname; struct parse_mod *parse; }; int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */ int lookup_init(const char *mapfmt, int argc, const char * const *argv, void **context) { struct lookup_context *ctxt; if ( !(*context = ctxt = malloc(sizeof(struct lookup_context))) ) { syslog(LOG_CRIT, MODPREFIX "malloc: %m"); return 1; } if ( argc < 1 ) { syslog(LOG_CRIT, MODPREFIX "No map name"); return 1; } ctxt->mapname = argv[0]; if (ctxt->mapname[0] != '/') { syslog(LOG_CRIT, MODPREFIX "file map %s is not an absolute pathname", ctxt->mapname); return 1; } if ( access(ctxt->mapname, R_OK) ) { syslog(LOG_WARNING, MODPREFIX "file map %s missing or not readable", ctxt->mapname); } if ( !mapfmt ) mapfmt = MAPFMT_DEFAULT; return !(ctxt->parse = open_parse(mapfmt,MODPREFIX,argc-1,argv+1)); } int lookup_mount(const char *root, const char *name, int name_len, void *context) { struct lookup_context *ctxt = (struct lookup_context *) context; int ch, nch; char mapent[MAPENT_MAX_LEN+1], *p; const char *nptr; int mapent_len; FILE *f; enum { st_begin, st_compare, st_star, st_badent, st_entspc, st_getent } state; enum { got_nothing, got_star, got_real } getting, gotten; enum { esc_none, esc_char, esc_val } escape; syslog(LOG_DEBUG, MODPREFIX "looking up %s", name); chdir("/"); /* If this is not here the filesystem stays busy, for some reason... */ f = fopen(ctxt->mapname, "r"); if ( !f ) { syslog(LOG_ERR, MODPREFIX "could not open map file %s", ctxt->mapname); return 1; } state = st_begin; gotten = got_nothing; /* Shut up gcc */ nptr = p = NULL; mapent_len = 0; getting = got_nothing; escape = esc_none; /* This is ugly. We can't just remove \ escape sequences in the value portion of an entry, because the parsing routine may need it. */ while ( (ch = getc(f)) != EOF ) { switch ( escape ) { case esc_none: if ( ch == '\\' ) { /* Handle continuation lines */ if ( (nch = getc(f)) == '\n' ) goto next_char; ungetc(nch,f); escape = esc_char; } break; case esc_char: escape = esc_val; break; case esc_val: escape = esc_none; break; } switch(state) { case st_begin: if ( isspace(ch) && !escape ) ; else if ( escape == esc_char ) ; else if ( ch == '#' && !escape ) state = st_badent; else if ( (char)ch == name[0] ) { state = st_compare; nptr = name+1; } else if ( ch == '*' && !escape ) state = st_star; else state = st_badent; break; case st_compare: if ( ch == '\n' ) state = st_begin; else if ( isspace(ch) && !*nptr && !escape ) { getting = got_real; state = st_entspc; } else if ( escape == esc_char ) ; else if ( (char)ch != *(nptr++) ) state = st_badent; break; case st_star: if ( ch == '\n' ) state = st_begin; else if ( isspace(ch) && gotten < got_star && !escape ) { getting = got_star; state = st_entspc; } else if ( escape != esc_char ) state = st_badent; break; case st_badent: if ( ch == '\n' ) state = st_begin; break; case st_entspc: if ( ch == '\n' ) state = st_begin; else if ( !isspace(ch) || escape ) { state = st_getent; p = mapent; gotten = getting; *(p++) = ch; mapent_len = 1; } break; case st_getent: if ( ch == '\n' ) { state = st_begin; if ( gotten == got_real ) goto got_it; /* No point in parsing the rest of the file */ } else if ( mapent_len < MAPENT_MAX_LEN ) { mapent_len++; *(p++) = ch; } break; } next_char: /* End of loop, since we can't continue; inside a switch */ } got_it: fclose(f); if ( gotten == got_nothing ) { syslog(LOG_NOTICE, MODPREFIX "lookup for %s failed", name); return 1; /* Didn't found anything */ } *p = '\0'; /* Null-terminate */ syslog(LOG_DEBUG, MODPREFIX "%s -> %s", name, mapent); return ctxt->parse->parse_mount(root,name,name_len,mapent,ctxt->parse->context); } int lookup_done(void *context) { struct lookup_context *ctxt = (struct lookup_context *) context; int rv = close_parse(ctxt->parse); free(ctxt); return rv; }