1
/* ----------------------------------------------------------------------- *
3
* parse_subs.c - misc parser subroutines
6
* Copyright 1997 Transmeta Corporation - All Rights Reserved
7
* Copyright 2000 Jeremy Fitzhardinge <jeremy@goop.org>
8
* Copyright 2004-2006 Ian Kent <raven@themaw.net>
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
13
* USA; either version 2 of the License, or (at your option) any later
14
* version; incorporated herein by reference.
16
* ----------------------------------------------------------------------- */
21
#include <sys/types.h>
25
#include "automount.h"
28
* Skip whitespace in a string; if we hit a #, consider the rest of the
31
const char *skipspace(const char *whence)
44
case '#': /* comment: skip to end of string */
45
while (*whence != '\0')
56
* Check a string to see if a colon appears before the next '/'.
58
int check_colon(const char *str)
60
char *ptr = (char *) str;
66
while (*ptr && *ptr != ':' && *ptr != '/') {
70
if (!*ptr || *ptr == '/')
76
/* Get the length of a chunk delimitered by whitespace */
77
int chunklen(const char *whence, int expect_colon)
79
char *str = (char *) whence;
83
for (; *str; str++, n++) {
110
/* Skip space or tab if we expect a colon */
132
* Compare str with pat. Return 0 if compare equal or
133
* str is an abbreviation of pat of no less than mchr characters.
135
int strmcmp(const char *str, const char *pat, int mchr)
139
while (*str == *pat) {
147
if (!*str && nchr > mchr)
153
char *dequote(const char *str, int origlen, unsigned int logopt)
155
char *ret = malloc(origlen + 1);
159
int quote = 0, dquote = 0;
165
/* first thing to do is strip white space from the end */
167
while (isspace(str[i])) {
168
/* of course, we have to keep escaped white-space */
170
if (j > 0 && (str[j] == '\\' || str[j] == '"'))
176
for (scp = str; len > 0 && *scp; scp++, len--) {
199
debug(logopt, "unmatched quote in %.*s", origlen, str);
207
int span_space(const char *str, unsigned int maxlen)
210
unsigned int len = 0;
212
while (*p && !isblank(*p) && len < maxlen) {
214
while (*p++ && len++ < maxlen) {
218
} else if (*p == '\\') {
229
char *sanitize_path(const char *path, int origlen, unsigned int type, unsigned int logopt)
231
char *slash, *cp, *s_path;
234
unsigned int seen_slash = 0, quote = 0, dquote = 0;
236
if (type & (LKP_INDIRECT | LKP_DIRECT)) {
237
slash = strchr(path, '/');
239
if (type == LKP_INDIRECT)
244
if (type == LKP_DIRECT)
249
s_path = malloc(origlen + 1);
253
for (cp = s_path, scp = path; len > 0; scp++, len--) {
264
/* Badness in string - go away */
277
* Not really proper but we get problems with
278
* paths with multiple slashes. The kernel
279
* compresses them so when we get a query there
280
* should be only single slashes.
295
debug(logopt, "unmatched quote in %.*s", origlen, path);
300
/* Remove trailing / but watch out for a quoted / alone */
301
if (strlen(cp) > 1 && origlen > 1 && *(cp - 1) == '/')
307
int umount_ent(struct autofs_point *ap, const char *path)
312
int status, is_smbfs = 0;
315
ret = statfs(path, &fs);
317
warn(ap->logopt, "could not stat fs of %s", path);
320
int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER;
321
int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC;
322
is_smbfs = (cifsfs | smbfs) ? 1 : 0;
325
status = lstat(path, &st);
329
warn(ap->logopt, "lstat of %s failed with %d", path, status);
332
* lstat failed and we're an smbfs fs returning an error that is not
333
* EIO or EBADSLT or the lstat failed so it's a bad path. Return
336
* EIO appears to correspond to an smb mount that has gone away
337
* and EBADSLT relates to CD changer not responding.
339
if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) {
340
rv = spawn_umount(ap->logopt, path, NULL);
341
} else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) {
342
rv = spawn_umount(ap->logopt, path, NULL);
345
/* We are doing a forced shutcwdown down so unlink busy mounts */
346
if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) {
347
ret = stat(path, &st);
348
if (ret == -1 && errno == ENOENT) {
349
warn(ap->logopt, "mount point does not exist");
353
if (ret == 0 && !S_ISDIR(st.st_mode)) {
354
warn(ap->logopt, "mount point is not a directory");
358
if (ap->state == ST_SHUTDOWN_FORCE) {
359
info(ap->logopt, "forcing umount of %s", path);
360
rv = spawn_umount(ap->logopt, "-l", path, NULL);
364
* Verify that we actually unmounted the thing. This is a
365
* belt and suspenders approach to not eating user data.
366
* We have seen cases where umount succeeds, but there is
367
* still a file system mounted on the mount point. How
368
* this happens has not yet been determined, but we want to
369
* make sure to return failure here, if that is the case,
370
* so that we do not try to call rmdir_path on the
373
if (!rv && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
375
"the umount binary reported that %s was "
376
"unmounted, but there is still something "
377
"mounted on this path.", path);
385
int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
387
char path[PATH_MAX + 1];
390
struct list_head *pos = NULL;
391
unsigned int fs_path_len;
392
unsigned int mounted;
395
fs_path_len = strlen(root) + strlen(base);
396
if (fs_path_len > PATH_MAX)
403
start = strlen(root);
404
offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
406
int plen = fs_path_len + strlen(offset);
408
if (plen > PATH_MAX) {
409
warn(ap->logopt, "path loo long");
413
oe = cache_lookup_offset(base, offset, start, &me->multi_list);
417
debug(ap->logopt, "mount offset %s", oe->key);
419
if (mount_autofs_offset(ap, oe) < 0)
420
warn(ap->logopt, "failed to mount offset");
424
offset = cache_get_offset(base,
425
offset, start, &me->multi_list, &pos);
431
int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
433
char path[PATH_MAX + 1];
436
struct list_head *mm_root, *pos;
437
const char o_root[] = "/";
442
start = strlen(root);
444
mm_root = &me->multi->multi_list;
454
/* Make sure "none" of the offsets have an active mount. */
455
while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
458
oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
459
/* root offset is a special case */
460
if (!oe || (strlen(oe->key) - start) == 1)
464
* Check for and umount subtree offsets resulting from
465
* nonstrict mount fail.
467
oe_base = oe->key + strlen(root);
468
left += umount_multi_triggers(ap, root, oe, oe_base);
470
if (oe->ioctlfd != -1)
480
/* Make sure "none" of the offsets have an active mount. */
481
while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
482
oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
483
/* root offset is a special case */
484
if (!oe || (strlen(oe->key) - start) == 1)
487
debug(ap->logopt, "umount offset %s", oe->key);
489
if (umount_autofs_offset(ap, oe)) {
490
warn(ap->logopt, "failed to umount offset");
495
if (!left && me->multi == me) {
496
struct mapent_cache *mc = me->mc;
501
* If we can't umount the root container then we can't
502
* delete the offsets from the cache and we need to put
503
* the offset triggers back.
505
if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) {
506
info(ap->logopt, "unmounting dir = %s", root);
507
if (umount_ent(ap, root)) {
508
if (!mount_multi_triggers(ap, root, me, "/"))
510
"failed to remount offset triggers");
515
/* We're done - clean out the offsets */
516
status = cache_delete_offset_list(mc, me->key);
517
if (status != CHE_OK)
518
warn(ap->logopt, "couldn't delete offset list");