aboutsummaryrefslogtreecommitdiffstats
path: root/modules/mount_autofs.c
blob: 6ab439cff7bd48a9a76b825e7e6694c5115eeb4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#ident "$Id$"
/*
 * mount_autofs.c
 *
 * Module for recursive autofs mounts.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <signal.h>
#include <alloca.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>

#define MODULE_MOUNT
#include "automount.h"

#define MODPREFIX "mount(autofs): "
int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */

int mount_init(void **context)
{
  return 0;
}

int mount_mount(const char *root, const char *name, int name_len,
		const char *what, const char *fstype, const char *c_options,
		void *context)
{
  char *fullpath;
  const char **argv;
  int argc, status;
  struct stat sb, cb;
  char *options, *p;

  fullpath = alloca(strlen(root)+name_len+2);
  if ( !fullpath ) {
    syslog(LOG_ERR, MODPREFIX "alloca: %m");
    return 1;
  }
  sprintf(fullpath, "%s/%s", root, name);

  options = alloca(strlen(c_options)+1);
  if ( !options ) {
    syslog(LOG_ERR, MODPREFIX "alloca: %m");
    return 1;
  }
  strcpy(options, c_options);

  syslog(LOG_DEBUG, MODPREFIX "calling mkdir %s", fullpath);
  if ( mkdir(fullpath, 0555) && errno != EEXIST ) {
    syslog(LOG_NOTICE, MODPREFIX "mkdir %s failed: %m", name);
    return 1;
  }
    
  syslog(LOG_DEBUG, MODPREFIX "fullpath=%s what=%s options=%s", 
	 fullpath, what, options);

  /* Build our argument vector.  */

  argc = 5;
  if ( options ) {
    char *p = options;
    do {
      argc++;
    } while ((p = strchr(p,',')) != NULL);
  }
  argv = (const char **) alloca((argc+1) * sizeof(char *));

  argc = 0;
  argv[argc++] = _PATH_AUTOMOUNT;
  argv[argc++] = "--submount";
  argv[argc++] = fullpath;
  argv[argc++] = strcpy(alloca(strlen(what)+1), what);
  
  if ( (p = strchr(argv[argc-1], ':')) == NULL ) {
    syslog(LOG_NOTICE, MODPREFIX "%s missing script type on %s", name, what);
    goto error;
  }

  argv[argc++] = p;

  if ( options ) {
    argv[argc++] = strtok(options, ",");
    while ((argv[argc++] = strtok(NULL, ",")) != NULL)
      continue;
  }
  argv[argc] = NULL;

  /* Spawn a new daemon.  */
  status = spawnv(LOG_DEBUG, _PATH_AUTOMOUNT, argv);
  if (!WIFEXITED(status) || WEXITSTATUS(status)) {
    syslog(LOG_NOTICE, MODPREFIX "sub automount returned status %d", status);
    goto error;
  }

  /* We must wait a bit for it to get registered.  We try three times, and
     if it isn't ready after that, assume it has failed.  This is a real
     hack; we really should make --submount make the subprocess notify us. */

  stat(root, &cb);
  usleep(10000);

  stat(fullpath, &sb);
  if (cb.st_dev == sb.st_dev) {
    int i;
    /* First, to one second by tenths.  */
    for (i = 0; i < 10; ++i) {
      usleep(100000);
      stat(fullpath, &sb);
      if (cb.st_dev != sb.st_dev)
	goto ok;
    }
    /* Then to one minute by seconds.  */
    for (i = 1; i < 60; ++i) {
      sleep(1);
      stat(fullpath, &sb);
      if (cb.st_dev != sb.st_dev)
	goto ok;
    }
    syslog(LOG_NOTICE, MODPREFIX "timeout waiting for submount");
    goto error;
  }

ok:
  syslog(LOG_DEBUG, MODPREFIX "mounted %s on %s", what, fullpath);
  return 0;

error:
  rmdir(fullpath);
  syslog(LOG_NOTICE, MODPREFIX "failed to mount %s on %s", what, fullpath);
  return 1;
}

int mount_done(void *context)
{
  return 0;
}