~ubuntu-branches/ubuntu/saucy/autofs/saucy-proposed

« back to all changes in this revision

Viewing changes to lib/mounts.c

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2012-04-23 00:30:51 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120423003051-xkl6529r55m40ltx
Tags: 5.0.6-1
* New upstream release
  - "mount(nfs): no hosts available" (Closes: #608459).
  - "new upstream version available" (Closes: #602933).
  - "autofs mounted directory are never dismounted" (Closes: #521165).
  - "autofs5 does not support recursive mount" (Closes: #626473).
  - "autofs5 crashed in a nested setup in combination with
     negative lookups on *" (Closes: #617317).
  - "autofs5-ldap: simple bind auth feature request" (Closes: #595808).
  - "autofs5-ldap: SASL auth broken" (Closes: #568813).
* package rename: dropping '5' from package names (Closes: #655351).
* NMU changes acknowledged (Closes: #603491, #583094).
* register /etc/default/autofs with ucf (Closes: #556961).
* debian/copyright to DEP-5 format; upstream copyright audit.
* packaging update:
  * use debhelper & compat version 9.
  * standards to 3.9.3
  * lintian-override for 'non-standard-file-perm'
  * install missing autofs_ldap_auth.conf.5 man page
  * source format to version 3 and .xz compression
  * debian/rules rewritten in debhelper style
* patchworks:
  + replacing upstream patches with new patchset as of 2012-04-23.
  + replacing dpatch with quilt (Closes: #668077)
  + new patch to correct manpages spelling (Closes: #660075)
    thanks to Oz Nahum Tiram and Javi Merino
  + updated SYSV init script patch:
    * removed bashisms (Closes: #626435).
    * introduce 'status' support to SYSV script
      (Closes: #651978, #667811, #565507).
    * adding 'slapd' to Should-Start/Stop (Closes: #600764, #659616).
    * LSB output (Closes: #567805) thanks to Petter Reinholdtsen.
* declare myself as Maintainer (adopting package)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#ident "$Id: mounts.c,v 1.9 2005/01/17 15:09:28 raven Exp $"
2
1
/* ----------------------------------------------------------------------- *
3
2
 *   
4
 
 *  mounts.c - module for Linux automount mount table lookup functions
 
3
 *  mounts.c - module for mount utilities.
5
4
 *
6
 
 *   Copyright 2002-2004 Ian Kent <raven@themaw.net> - All Rights Reserved
 
5
 *   Copyright 2002-2005 Ian Kent <raven@themaw.net> - All Rights Reserved
7
6
 *
8
7
 *   This program is free software; you can redistribute it and/or modify
9
8
 *   it under the terms of the GNU General Public License as published by
15
14
 
16
15
#include <stdlib.h>
17
16
#include <string.h>
18
 
#include <unistd.h>
19
 
#include <syslog.h>
20
 
#include <mntent.h>
21
17
#include <limits.h>
22
18
#include <sys/types.h>
23
19
#include <sys/stat.h>
 
20
#include <sys/ioctl.h>
 
21
#include <sys/mount.h>
 
22
#include <sys/wait.h>
 
23
#include <ctype.h>
24
24
#include <stdio.h>
 
25
#include <dirent.h>
 
26
#include <sys/vfs.h>
 
27
#include <pwd.h>
 
28
#include <grp.h>
25
29
 
26
30
#include "automount.h"
27
31
 
 
32
#define MAX_OPTIONS_LEN         80
 
33
#define MAX_MNT_NAME_LEN        30
 
34
 
 
35
#define EBUFSIZ 1024
 
36
 
 
37
const unsigned int t_indirect = AUTOFS_TYPE_INDIRECT;
 
38
const unsigned int t_direct = AUTOFS_TYPE_DIRECT;
 
39
const unsigned int t_offset = AUTOFS_TYPE_OFFSET;
 
40
const unsigned int type_count = 3;
 
41
 
 
42
static const char options_template[]       = "fd=%d,pgrp=%u,minproto=5,maxproto=%d";
 
43
static const char options_template_extra[] = "fd=%d,pgrp=%u,minproto=5,maxproto=%d,%s";
 
44
static const char mnt_name_template[]      = "automount(pid%u)";
 
45
 
 
46
static struct kernel_mod_version kver = {0, 0};
 
47
static const char kver_options_template[]  = "fd=%d,pgrp=%u,minproto=3,maxproto=5";
 
48
 
 
49
unsigned int query_kproto_ver(void)
 
50
{
 
51
        struct ioctl_ops *ops = get_ioctl_ops();
 
52
        char dir[] = "/tmp/autoXXXXXX", *t_dir;
 
53
        char options[MAX_OPTIONS_LEN + 1];
 
54
        pid_t pgrp = getpgrp();
 
55
        int pipefd[2], ioctlfd, len;
 
56
        struct stat st;
 
57
 
 
58
        t_dir = mkdtemp(dir);
 
59
        if (!t_dir)
 
60
                return 0;
 
61
 
 
62
        if (pipe(pipefd) == -1) {
 
63
                rmdir(t_dir);
 
64
                return 0;
 
65
        }
 
66
 
 
67
        len = snprintf(options, MAX_OPTIONS_LEN,
 
68
                       kver_options_template, pipefd[1], (unsigned) pgrp);
 
69
        if (len < 0) {
 
70
                close(pipefd[0]);
 
71
                close(pipefd[1]);
 
72
                rmdir(t_dir);
 
73
                return 0;
 
74
        }
 
75
 
 
76
        if (mount("automount", t_dir, "autofs", MS_MGC_VAL, options)) {
 
77
                close(pipefd[0]);
 
78
                close(pipefd[1]);
 
79
                rmdir(t_dir);
 
80
                return 0;
 
81
        }
 
82
 
 
83
        close(pipefd[1]);
 
84
 
 
85
        if (stat(t_dir, &st) == -1) {
 
86
                umount(t_dir);
 
87
                close(pipefd[0]);
 
88
                rmdir(t_dir);
 
89
                return 0;
 
90
        }
 
91
 
 
92
        ops->open(LOGOPT_NONE, &ioctlfd, st.st_dev, t_dir);
 
93
        if (ioctlfd == -1) {
 
94
                umount(t_dir);
 
95
                close(pipefd[0]);
 
96
                rmdir(t_dir);
 
97
                return 0;
 
98
        }
 
99
 
 
100
        ops->catatonic(LOGOPT_NONE, ioctlfd);
 
101
 
 
102
        /* If this ioctl() doesn't work, it is kernel version 2 */
 
103
        if (ops->protover(LOGOPT_NONE, ioctlfd, &kver.major)) {
 
104
                ops->close(LOGOPT_NONE, ioctlfd);
 
105
                umount(t_dir);
 
106
                close(pipefd[0]);
 
107
                rmdir(t_dir);
 
108
                return 0;
 
109
        }
 
110
 
 
111
        /* If this ioctl() doesn't work, version is 4 or less */
 
112
        if (ops->protosubver(LOGOPT_NONE, ioctlfd, &kver.minor)) {
 
113
                ops->close(LOGOPT_NONE, ioctlfd);
 
114
                umount(t_dir);
 
115
                close(pipefd[0]);
 
116
                rmdir(t_dir);
 
117
                return 0;
 
118
        }
 
119
 
 
120
        ops->close(LOGOPT_NONE, ioctlfd);
 
121
        umount(t_dir);
 
122
        close(pipefd[0]);
 
123
        rmdir(t_dir);
 
124
 
 
125
        return 1;
 
126
}
 
127
 
 
128
unsigned int get_kver_major(void)
 
129
{
 
130
        return kver.major;
 
131
}
 
132
 
 
133
unsigned int get_kver_minor(void)
 
134
{
 
135
        return kver.minor;
 
136
}
 
137
 
 
138
#ifdef HAVE_MOUNT_NFS
 
139
static int extract_version(char *start, struct nfs_mount_vers *vers)
 
140
{
 
141
        char *s_ver = strchr(start, ' ');
 
142
        while (*s_ver && !isdigit(*s_ver)) {
 
143
                s_ver++;
 
144
                if (!*s_ver)
 
145
                        return 0;
 
146
                break;
 
147
        }
 
148
        vers->major = atoi(strtok(s_ver, "."));
 
149
        vers->minor = (unsigned int) atoi(strtok(NULL, "."));
 
150
        vers->fix = (unsigned int) atoi(strtok(NULL, "."));
 
151
        return 1;
 
152
}
 
153
 
 
154
int check_nfs_mount_version(struct nfs_mount_vers *vers,
 
155
                            struct nfs_mount_vers *check)
 
156
{
 
157
        pid_t f;
 
158
        int ret, status, pipefd[2];
 
159
        char errbuf[EBUFSIZ + 1], *p, *sp;
 
160
        int errp, errn;
 
161
        sigset_t allsigs, tmpsig, oldsig;
 
162
        char *s_ver;
 
163
        int cancel_state;
 
164
 
 
165
        if (pipe(pipefd))
 
166
                return -1;
 
167
 
 
168
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
 
169
 
 
170
        sigfillset(&allsigs);
 
171
        pthread_sigmask(SIG_BLOCK, &allsigs, &oldsig);
 
172
 
 
173
        f = fork();
 
174
        if (f == 0) {
 
175
                reset_signals();
 
176
                close(pipefd[0]);
 
177
                dup2(pipefd[1], STDOUT_FILENO);
 
178
                dup2(pipefd[1], STDERR_FILENO);
 
179
                close(pipefd[1]);
 
180
 
 
181
                execl(PATH_MOUNT_NFS, PATH_MOUNT_NFS, "-V", (char *) NULL);
 
182
                _exit(255);     /* execv() failed */
 
183
        }
 
184
 
 
185
        ret = 0;
 
186
 
 
187
        tmpsig = oldsig;
 
188
 
 
189
        sigaddset(&tmpsig, SIGCHLD);
 
190
        pthread_sigmask(SIG_SETMASK, &tmpsig, NULL);
 
191
 
 
192
        close(pipefd[1]);
 
193
 
 
194
        if (f < 0) {
 
195
                close(pipefd[0]);
 
196
                pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
 
197
                pthread_setcancelstate(cancel_state, NULL);
 
198
                return -1;
 
199
        }
 
200
 
 
201
        errp = 0;
 
202
        do {
 
203
                while (1) {
 
204
                        errn = read(pipefd[0], errbuf + errp, EBUFSIZ - errp);
 
205
                        if (errn == -1 && errno == EINTR)
 
206
                                continue;
 
207
                        break;
 
208
                }
 
209
 
 
210
                if (errn > 0) {
 
211
                        errp += errn;
 
212
 
 
213
                        sp = errbuf;
 
214
                        while (errp && (p = memchr(sp, '\n', errp))) {
 
215
                                *p++ = '\0';
 
216
                                errp -= (p - sp);
 
217
                                sp = p;
 
218
                        }
 
219
 
 
220
                        if (errp && sp != errbuf)
 
221
                                memmove(errbuf, sp, errp);
 
222
 
 
223
                        if (errp >= EBUFSIZ) {
 
224
                                /* Line too long, split */
 
225
                                errbuf[errp] = '\0';
 
226
                                if ((s_ver = strstr(errbuf, "nfs-utils"))) {
 
227
                                        if (extract_version(s_ver, vers))
 
228
                                                ret = 1;
 
229
                                }
 
230
                                errp = 0;
 
231
                        }
 
232
 
 
233
                        if ((s_ver = strstr(errbuf, "nfs-utils"))) {
 
234
                                if (extract_version(s_ver, vers))
 
235
                                        ret = 1;
 
236
                        }
 
237
                }
 
238
        } while (errn > 0);
 
239
 
 
240
        close(pipefd[0]);
 
241
 
 
242
        if (errp > 0) {
 
243
                /* End of file without \n */
 
244
                errbuf[errp] = '\0';
 
245
                if ((s_ver = strstr(errbuf, "nfs-utils"))) {
 
246
                        if (extract_version(s_ver, vers))
 
247
                                ret = 1;
 
248
                }
 
249
        }
 
250
 
 
251
        if (ret) {
 
252
                if ((vers->major < check->major) ||
 
253
                    ((vers->major == check->major) && (vers->minor < check->minor)) ||
 
254
                    ((vers->major == check->major) && (vers->minor == check->minor) &&
 
255
                     (vers->fix < check->fix)))
 
256
                        ret = 0;
 
257
        }
 
258
 
 
259
        if (waitpid(f, &status, 0) != f) ;
 
260
 
 
261
        pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
 
262
        pthread_setcancelstate(cancel_state, NULL);
 
263
 
 
264
        return ret;
 
265
}
 
266
#else
 
267
int check_nfs_mount_version(struct nfs_mount_vers *vers,
 
268
                            struct nfs_mount_vers *check)
 
269
{
 
270
        return 0;
 
271
}
 
272
#endif
 
273
 
 
274
/*
 
275
 * Make common autofs mount options string
 
276
 */
 
277
char *make_options_string(char *path, int pipefd, const char *extra)
 
278
{
 
279
        char *options;
 
280
        int len;
 
281
 
 
282
        options = malloc(MAX_OPTIONS_LEN + 1);
 
283
        if (!options) {
 
284
                logerr("can't malloc options string");
 
285
                return NULL;
 
286
        }
 
287
 
 
288
        if (extra) 
 
289
                len = snprintf(options, MAX_OPTIONS_LEN,
 
290
                                options_template_extra,
 
291
                                pipefd, (unsigned) getpgrp(),
 
292
                                AUTOFS_MAX_PROTO_VERSION, extra);
 
293
        else
 
294
                len = snprintf(options, MAX_OPTIONS_LEN, options_template,
 
295
                        pipefd, (unsigned) getpgrp(),
 
296
                        AUTOFS_MAX_PROTO_VERSION);
 
297
 
 
298
        if (len >= MAX_OPTIONS_LEN) {
 
299
                logerr("buffer to small for options - truncated");
 
300
                len = MAX_OPTIONS_LEN - 1;
 
301
        }
 
302
 
 
303
        if (len < 0) {
 
304
                logerr("failed to malloc autofs mount options for %s", path);
 
305
                free(options);
 
306
                return NULL;
 
307
        }
 
308
        options[len] = '\0';
 
309
 
 
310
        return options;
 
311
}
 
312
 
 
313
char *make_mnt_name_string(char *path)
 
314
{
 
315
        char *mnt_name;
 
316
        int len;
 
317
 
 
318
        mnt_name = malloc(MAX_MNT_NAME_LEN + 1);
 
319
        if (!mnt_name) {
 
320
                logerr("can't malloc mnt_name string");
 
321
                return NULL;
 
322
        }
 
323
 
 
324
        len = snprintf(mnt_name, MAX_MNT_NAME_LEN,
 
325
                        mnt_name_template, (unsigned) getpid());
 
326
 
 
327
        if (len >= MAX_MNT_NAME_LEN) {
 
328
                logerr("buffer to small for mnt_name - truncated");
 
329
                len = MAX_MNT_NAME_LEN - 1;
 
330
        }
 
331
 
 
332
        if (len < 0) {
 
333
                logerr("failed setting up mnt_name for autofs path %s", path);
 
334
                free(mnt_name);
 
335
                return NULL;
 
336
        }
 
337
        mnt_name[len] = '\0';
 
338
 
 
339
        return mnt_name;
 
340
}
 
341
 
28
342
/*
29
343
 * Get list of mounts under path in longest->shortest order
30
344
 */
31
345
struct mnt_list *get_mnt_list(const char *table, const char *path, int include)
32
346
{
33
347
        FILE *tab;
34
 
        int pathlen = strlen(path);
 
348
        size_t pathlen = strlen(path);
 
349
        struct mntent mnt_wrk;
 
350
        char buf[PATH_MAX * 3];
35
351
        struct mntent *mnt;
36
352
        struct mnt_list *ent, *mptr, *last;
37
353
        struct mnt_list *list = NULL;
38
 
        struct stat st;
39
 
        int len;
 
354
        char *pgrp;
 
355
        size_t len;
40
356
 
41
357
        if (!path || !pathlen || pathlen > PATH_MAX)
42
358
                return NULL;
43
359
 
44
 
        tab = setmntent(table, "r");
 
360
        tab = open_setmntent_r(table);
45
361
        if (!tab) {
46
 
                error("get_mntlist: setmntent: %m");
 
362
                char *estr = strerror_r(errno, buf, PATH_MAX - 1);
 
363
                logerr("setmntent: %s", estr);
47
364
                return NULL;
48
365
        }
49
366
 
50
 
        while ((mnt = getmntent(tab)) != NULL) {
 
367
        while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
51
368
                len = strlen(mnt->mnt_dir);
52
369
 
53
370
                if ((!include && len <= pathlen) ||
66
383
                        free_mnt_list(list);
67
384
                        return NULL;
68
385
                }
 
386
                memset(ent, 0, sizeof(*ent));
69
387
 
70
388
                mptr = list;
71
389
                last = NULL;
72
390
                while (mptr) {
73
 
                        if (len > strlen(mptr->path))
 
391
                        if (len >= strlen(mptr->path))
74
392
                                break;
75
393
                        last = mptr;
76
394
                        mptr = mptr->next;
78
396
 
79
397
                if (mptr == list)
80
398
                        list = ent;
 
399
                else
 
400
                        last->next = ent;
81
401
 
82
402
                ent->next = mptr;
83
 
                if (last)
84
 
                        last->next = ent;
85
403
 
86
404
                ent->path = malloc(len + 1);
87
405
                if (!ent->path) {
91
409
                }
92
410
                strcpy(ent->path, mnt->mnt_dir);
93
411
 
 
412
                ent->fs_name = malloc(strlen(mnt->mnt_fsname) + 1);
 
413
                if (!ent->fs_name) {
 
414
                        endmntent(tab);
 
415
                        free_mnt_list(list);
 
416
                        return NULL;
 
417
                }
 
418
                strcpy(ent->fs_name, mnt->mnt_fsname);
 
419
 
94
420
                ent->fs_type = malloc(strlen(mnt->mnt_type) + 1);
95
421
                if (!ent->fs_type) {
96
422
                        endmntent(tab);
99
425
                }
100
426
                strcpy(ent->fs_type, mnt->mnt_type);
101
427
 
102
 
                ent->pid = 0;
103
 
                if (strncmp(ent->fs_type, "autofs", 6) == 0)
104
 
                        sscanf(mnt->mnt_fsname, "automount(pid%d)", &ent->pid);
 
428
                ent->opts = malloc(strlen(mnt->mnt_opts) + 1);
 
429
                if (!ent->opts) {
 
430
                        endmntent(tab);
 
431
                        free_mnt_list(list);
 
432
                        return NULL;
 
433
                }
 
434
                strcpy(ent->opts, mnt->mnt_opts);
 
435
 
 
436
                ent->owner = 0;
 
437
                pgrp = strstr(mnt->mnt_opts, "pgrp=");
 
438
                if (pgrp) {
 
439
                        char *end = strchr(pgrp, ',');
 
440
                        if (end)
 
441
                                *end = '\0';
 
442
                        sscanf(pgrp, "pgrp=%d", &ent->owner);
 
443
                }
105
444
        }
106
445
        endmntent(tab);
107
446
 
108
 
        mptr = list;
109
 
        while (mptr) {
110
 
                mptr->last_access = time(NULL);
111
 
 
112
 
                if (stat(mptr->path, &st) != -1)
113
 
                        mptr->last_access = st.st_atime;
114
 
 
115
 
                mptr = mptr->next;
116
 
        }
117
 
 
118
447
        return list;
119
448
}
120
449
 
132
461
        last = NULL;
133
462
        while (next) {
134
463
                struct mnt_list *this = next;
135
 
 
136
464
                next = this->next;
137
465
                this->next = last;
138
466
                last = this;
139
467
        }
140
 
 
141
468
        return last;
142
469
}
143
470
 
144
 
static struct mnt_list *copy_mnt_list_ent(struct mnt_list *ent)
145
 
{
146
 
        struct mnt_list *new;
147
 
 
148
 
        if (!ent)
149
 
                return NULL;
150
 
                
151
 
        new = malloc(sizeof(*new));
152
 
        if (!new) {
153
 
                return NULL;
154
 
        }
155
 
 
156
 
        if (!ent->path || !ent->fs_type) {
157
 
                free(new);
158
 
                return NULL;
159
 
        }
160
 
 
161
 
        new->path = malloc(strlen(ent->path) + 1);
162
 
        if (!new->path) {
163
 
                free(new);
164
 
                return NULL;
165
 
        }
166
 
        strcpy(new->path, ent->path);
167
 
 
168
 
        new->fs_type = malloc(strlen(ent->fs_type) + 1);
169
 
        if (!new->fs_type) {
170
 
                free(new->path);
171
 
                free(new);
172
 
                return NULL;
173
 
        }
174
 
        strcpy(new->fs_type, ent->fs_type);
175
 
 
176
 
        new->next = NULL;
177
 
 
178
 
        return new;
179
 
}
180
 
 
181
 
/*
182
 
 * Get list of mount points that are the base of a mount
183
 
 * tree (ie. get highest point at which we cross file
184
 
 * system boundary). Assumes mount list with
185
 
 * shortest -> longest paths.
186
 
 */
187
 
struct mnt_list *get_base_mnt_list(struct mnt_list *list)
188
 
{
189
 
        struct mnt_list *next, *ret = NULL;
190
 
        char *base;
191
 
 
192
 
        if (!list)
193
 
                return NULL;
194
 
 
195
 
        next = list;
196
 
        base = next->path;
197
 
        ret = copy_mnt_list_ent(next);
198
 
        while (next) {
199
 
                struct mnt_list *this = next;
200
 
                struct mnt_list *new;
201
 
                int blen = strlen(base);
202
 
                int nlen, eq;
203
 
 
204
 
                next = this->next;
205
 
                if (!next)
206
 
                        break;
207
 
                nlen = strlen(next->path);
208
 
 
209
 
 
210
 
                eq = strncmp(this->path, base, blen);
211
 
                if (!eq)
212
 
                        continue;
213
 
 
214
 
                if (strncmp(this->path, base, blen)) {
215
 
                        if (nlen > blen && next->path[blen + 1] == '/')
216
 
                                continue;
217
 
                }
218
 
 
219
 
                base = this->path;
220
 
 
221
 
                new = copy_mnt_list_ent(this);
222
 
                new->next = ret;
223
 
                ret = new;
224
 
        }
225
 
 
226
 
        return ret;
227
 
}
228
 
 
229
471
void free_mnt_list(struct mnt_list *list)
230
472
{
231
473
        struct mnt_list *next;
242
484
                if (this->path)
243
485
                        free(this->path);
244
486
 
 
487
                if (this->fs_name)
 
488
                        free(this->fs_name);
 
489
 
245
490
                if (this->fs_type)
246
491
                        free(this->fs_type);
247
492
 
 
493
                if (this->opts)
 
494
                        free(this->opts);
 
495
 
248
496
                free(this);
249
497
        }
250
498
}
251
499
 
252
 
static int find_mntent(const char *table, const char *path, struct mntent *ent)
 
500
int contained_in_local_fs(const char *path)
 
501
{
 
502
        struct mnt_list *mnts, *this;
 
503
        size_t pathlen = strlen(path);
 
504
        int ret;
 
505
 
 
506
        if (!path || !pathlen || pathlen > PATH_MAX)
 
507
                return 0;
 
508
 
 
509
        mnts = get_mnt_list(_PATH_MOUNTED, "/", 1);
 
510
        if (!mnts)
 
511
                return 0;
 
512
 
 
513
        ret = 0;
 
514
 
 
515
        for (this = mnts; this != NULL; this = this->next) {
 
516
                size_t len = strlen(this->path);
 
517
 
 
518
                if (!strncmp(path, this->path, len)) {
 
519
                        if (len > 1 && pathlen > len && path[len] != '/')
 
520
                                continue;
 
521
                        else if (len == 1 && this->path[0] == '/') {
 
522
                                /*
 
523
                                 * always return true on rootfs, we don't
 
524
                                 * want to break diskless clients.
 
525
                                 */
 
526
                                ret = 1;
 
527
                        } else if (this->fs_name[0] == '/') {
 
528
                                if (strlen(this->fs_name) > 1) {
 
529
                                        if (this->fs_name[1] != '/')
 
530
                                                ret = 1;
 
531
                                } else
 
532
                                        ret = 1;
 
533
                        } else if (!strncmp("LABEL=", this->fs_name, 6) ||
 
534
                                   !strncmp("UUID=", this->fs_name, 5))
 
535
                                ret = 1;
 
536
                        break;
 
537
                }
 
538
        }
 
539
 
 
540
        free_mnt_list(mnts);
 
541
 
 
542
        return ret;
 
543
}
 
544
 
 
545
static int table_is_mounted(const char *table, const char *path, unsigned int type)
253
546
{
254
547
        struct mntent *mnt;
 
548
        struct mntent mnt_wrk;
 
549
        char buf[PATH_MAX * 3];
 
550
        size_t pathlen = strlen(path);
255
551
        FILE *tab;
256
 
        int pathlen = strlen(path);
257
552
        int ret = 0;
258
553
 
259
 
        if (!path || !pathlen || pathlen > PATH_MAX)
 
554
        if (!path || !pathlen || pathlen >= PATH_MAX)
260
555
                return 0;
261
556
 
262
 
        tab = setmntent(table, "r");
 
557
        tab = open_setmntent_r(table);
263
558
        if (!tab) {
264
 
                error("find_mntent: setmntent: %m");
 
559
                char *estr = strerror_r(errno, buf, PATH_MAX - 1);
 
560
                logerr("setmntent: %s", estr);
265
561
                return 0;
266
562
        }
267
563
 
268
 
        while ((mnt = getmntent(tab)) != NULL) {
269
 
                int len = strlen(mnt->mnt_dir);
 
564
        while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
 
565
                size_t len = strlen(mnt->mnt_dir);
 
566
 
 
567
                if (type) {
 
568
                        unsigned int autofs_fs;
 
569
 
 
570
                        autofs_fs = !strcmp(mnt->mnt_type, "autofs");
 
571
 
 
572
                        if (type & MNTS_REAL)
 
573
                                if (autofs_fs)
 
574
                                        continue;
 
575
 
 
576
                        if (type & MNTS_AUTOFS)
 
577
                                if (!autofs_fs)
 
578
                                        continue;
 
579
                }
270
580
 
271
581
                if (pathlen == len && !strncmp(path, mnt->mnt_dir, pathlen)) {
272
 
                        int szent = sizeof(struct mntent);
273
 
 
274
 
                        if (ent)
275
 
                                memcpy(ent, mnt, szent);
276
 
                        ret = 1;
277
 
 
278
 
                        break;
279
 
                }
280
 
        }
281
 
        endmntent(tab);
282
 
 
283
 
        return ret;
284
 
}
285
 
        
286
 
int is_mounted(const char *table, const char *path)
287
 
{
288
 
        int ret = 0;
289
 
 
290
 
        if (find_mntent(table, path, NULL))
291
 
                ret = 1;
292
 
 
293
 
        return ret;
294
 
}
295
 
 
296
 
int has_fstab_option(const char *path, const char *opt)
297
 
{
298
 
        struct mntent ent;
299
 
        char *res = NULL;
300
 
 
301
 
        if (find_mntent(_PATH_MNTTAB, path, &ent)) {
302
 
                if ((res = hasmntopt(&ent, opt)))
303
 
                        return 1;
304
 
        }
305
 
 
306
 
        return 0;
307
 
}
308
 
 
309
 
/*
310
 
 * Check id owner option is present in fstab of requested
311
 
 * mount. If it is return iowner uid of requested dev.
312
 
 */
313
 
int allow_owner_mount(const char *path)
314
 
{
315
 
        struct mntent ent;
316
 
        int ret = 0;
317
 
 
318
 
        if (getuid() || is_mounted(_PATH_MOUNTED, path))
319
 
                return 0;
320
 
 
321
 
        if (find_mntent(_PATH_MNTTAB, path, &ent)) {
322
 
                struct stat st;
323
 
 
324
 
                if (!hasmntopt(&ent, "owner"))
325
 
                        return 0;
326
 
 
327
 
                if (stat(ent.mnt_fsname, &st) == -1)
328
 
                        return 0;
329
 
 
330
 
                ret = st.st_uid;
331
 
        }
332
 
 
333
 
        return ret;
 
582
                        ret = 1;
 
583
                        break;
 
584
                }
 
585
        }
 
586
        endmntent(tab);
 
587
 
 
588
        return ret;
 
589
}
 
590
 
 
591
static int ioctl_is_mounted(const char *path, unsigned int type)
 
592
{
 
593
        struct ioctl_ops *ops = get_ioctl_ops();
 
594
        unsigned int mounted;
 
595
 
 
596
        ops->ismountpoint(LOGOPT_NONE, -1, path, &mounted);
 
597
        if (mounted) {
 
598
                switch (type) {
 
599
                case MNTS_ALL:
 
600
                        return 1;
 
601
                case MNTS_AUTOFS:
 
602
                        return (mounted & DEV_IOCTL_IS_AUTOFS);
 
603
                case MNTS_REAL:
 
604
                        return (mounted & DEV_IOCTL_IS_OTHER);
 
605
                }
 
606
        }
 
607
        return 0;
 
608
}
 
609
 
 
610
int is_mounted(const char *table, const char *path, unsigned int type)
 
611
{
 
612
        struct ioctl_ops *ops = get_ioctl_ops();
 
613
 
 
614
        if (ops->ismountpoint)
 
615
                return ioctl_is_mounted(path, type);
 
616
        else
 
617
                return table_is_mounted(table, path, type);
 
618
}
 
619
 
 
620
int has_fstab_option(const char *opt)
 
621
{
 
622
        struct mntent *mnt;
 
623
        struct mntent mnt_wrk;
 
624
        char buf[PATH_MAX * 3];
 
625
        FILE *tab;
 
626
        int ret = 0;
 
627
 
 
628
        if (!opt)
 
629
                return 0;
 
630
 
 
631
        tab = open_setmntent_r(_PATH_MNTTAB);
 
632
        if (!tab) {
 
633
                char *estr = strerror_r(errno, buf, PATH_MAX - 1);
 
634
                logerr("setmntent: %s", estr);
 
635
                return 0;
 
636
        }
 
637
 
 
638
        while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
 
639
                if (hasmntopt(mnt, opt)) {
 
640
                        ret = 1;
 
641
                        break;
 
642
                }
 
643
        }
 
644
        endmntent(tab);
 
645
 
 
646
        return ret;
 
647
}
 
648
 
 
649
char *get_offset(const char *prefix, char *offset,
 
650
                 struct list_head *head, struct list_head **pos)
 
651
{
 
652
        struct list_head *next;
 
653
        struct mnt_list *this;
 
654
        size_t plen = strlen(prefix);
 
655
        size_t len = 0;
 
656
 
 
657
        *offset = '\0';
 
658
        next = *pos ? (*pos)->next : head->next;
 
659
        while (next != head) {
 
660
                char *pstart, *pend;
 
661
 
 
662
                this = list_entry(next, struct mnt_list, ordered);
 
663
                *pos = next;
 
664
                next = next->next;
 
665
 
 
666
                if (strlen(this->path) <= plen)
 
667
                        continue;
 
668
 
 
669
                if (!strncmp(prefix, this->path, plen)) {
 
670
                        pstart = &this->path[plen];
 
671
 
 
672
                        /* not part of this sub-tree */
 
673
                        if (*pstart != '/')
 
674
                                continue;
 
675
 
 
676
                        /* get next offset */
 
677
                        pend = pstart;
 
678
                        while (*pend++) ;
 
679
                        len = pend - pstart - 1;
 
680
                        strncpy(offset, pstart, len);
 
681
                        offset[len] ='\0';
 
682
                        break;
 
683
                }
 
684
        }
 
685
 
 
686
        while (next != head) {
 
687
                char *pstart;
 
688
 
 
689
                this = list_entry(next, struct mnt_list, ordered);
 
690
 
 
691
                if (strlen(this->path) <= plen + len)
 
692
                        break;
 
693
 
 
694
                pstart = &this->path[plen];
 
695
 
 
696
                /* not part of this sub-tree */
 
697
                if (*pstart != '/')
 
698
                        break;
 
699
 
 
700
                /* new offset */
 
701
                if (!*(pstart + len + 1))
 
702
                        break;
 
703
 
 
704
                /* compare next offset */
 
705
                if (pstart[len] != '/' || strncmp(offset, pstart, len))
 
706
                        break;
 
707
 
 
708
                *pos = next;
 
709
                next = next->next;
 
710
        }
 
711
 
 
712
        return *offset ? offset : NULL;
 
713
}
 
714
 
 
715
void add_ordered_list(struct mnt_list *ent, struct list_head *head)
 
716
{
 
717
        struct list_head *p;
 
718
        struct mnt_list *this;
 
719
 
 
720
        list_for_each(p, head) {
 
721
                size_t tlen;
 
722
                int eq;
 
723
 
 
724
                this = list_entry(p, struct mnt_list, ordered);
 
725
                tlen = strlen(this->path);
 
726
 
 
727
                eq = strncmp(this->path, ent->path, tlen);
 
728
                if (!eq && tlen == strlen(ent->path))
 
729
                        return;
 
730
 
 
731
                if (eq > 0) {
 
732
                        INIT_LIST_HEAD(&ent->ordered);
 
733
                        list_add_tail(&ent->ordered, p);
 
734
                        return;
 
735
                }
 
736
        }
 
737
        INIT_LIST_HEAD(&ent->ordered);
 
738
        list_add_tail(&ent->ordered, p);
 
739
 
 
740
        return;
 
741
}
 
742
 
 
743
/*
 
744
 * Since we have to look at the entire mount tree for direct
 
745
 * mounts (all mounts under "/") and we may have a large number
 
746
 * of entries to traverse again and again we need to
 
747
 * use a more efficient method than the routines above.
 
748
 *
 
749
 * Thre tree_... routines allow us to read the mount tree
 
750
 * once and pass it to subsequent functions for use. Since
 
751
 * it's a tree structure searching should be a low overhead
 
752
 * operation.
 
753
 */
 
754
void tree_free_mnt_tree(struct mnt_list *tree)
 
755
{
 
756
        struct list_head *head, *p;
 
757
 
 
758
        if (!tree)
 
759
                return;
 
760
 
 
761
        tree_free_mnt_tree(tree->left);
 
762
        tree_free_mnt_tree(tree->right);
 
763
 
 
764
        head = &tree->self;
 
765
        p = head->next;
 
766
        while (p != head) {
 
767
                struct mnt_list *this;
 
768
 
 
769
                this = list_entry(p, struct mnt_list, self);
 
770
 
 
771
                p = p->next;
 
772
 
 
773
                list_del(&this->self);
 
774
 
 
775
                free(this->path);
 
776
                free(this->fs_name);
 
777
                free(this->fs_type);
 
778
 
 
779
                if (this->opts)
 
780
                        free(this->opts);
 
781
 
 
782
                free(this);
 
783
        }
 
784
 
 
785
        free(tree->path);
 
786
        free(tree->fs_name);
 
787
        free(tree->fs_type);
 
788
 
 
789
        if (tree->opts)
 
790
                free(tree->opts);
 
791
 
 
792
        free(tree);
 
793
}
 
794
 
 
795
/*
 
796
 * Make tree of system mounts in /proc/mounts.
 
797
 */
 
798
struct mnt_list *tree_make_mnt_tree(const char *table, const char *path)
 
799
{
 
800
        FILE *tab;
 
801
        struct mntent mnt_wrk;
 
802
        char buf[PATH_MAX * 3];
 
803
        struct mntent *mnt;
 
804
        struct mnt_list *ent, *mptr;
 
805
        struct mnt_list *tree = NULL;
 
806
        char *pgrp;
 
807
        size_t plen;
 
808
        int eq;
 
809
 
 
810
        tab = open_setmntent_r(table);
 
811
        if (!tab) {
 
812
                char *estr = strerror_r(errno, buf, PATH_MAX - 1);
 
813
                logerr("setmntent: %s", estr);
 
814
                return NULL;
 
815
        }
 
816
 
 
817
        plen = strlen(path);
 
818
 
 
819
        while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
 
820
                size_t len = strlen(mnt->mnt_dir);
 
821
 
 
822
                /* Not matching path */
 
823
                if (strncmp(mnt->mnt_dir, path, plen))
 
824
                        continue;
 
825
 
 
826
                /* Not a subdirectory of requested path */
 
827
                if (plen > 1 && len > plen && mnt->mnt_dir[plen] != '/')
 
828
                        continue;
 
829
 
 
830
                ent = malloc(sizeof(*ent));
 
831
                if (!ent) {
 
832
                        endmntent(tab);
 
833
                        tree_free_mnt_tree(tree);
 
834
                        return NULL;
 
835
                }
 
836
                memset(ent, 0, sizeof(*ent));
 
837
 
 
838
                INIT_LIST_HEAD(&ent->self);
 
839
                INIT_LIST_HEAD(&ent->list);
 
840
                INIT_LIST_HEAD(&ent->entries);
 
841
                INIT_LIST_HEAD(&ent->sublist);
 
842
                INIT_LIST_HEAD(&ent->ordered);
 
843
 
 
844
                ent->path = malloc(len + 1);
 
845
                if (!ent->path) {
 
846
                        endmntent(tab);
 
847
                        free(ent);
 
848
                        tree_free_mnt_tree(tree);
 
849
                        return NULL;
 
850
                }
 
851
                strcpy(ent->path, mnt->mnt_dir);
 
852
 
 
853
                ent->fs_name = malloc(strlen(mnt->mnt_fsname) + 1);
 
854
                if (!ent->fs_name) {
 
855
                        free(ent->path);
 
856
                        free(ent);
 
857
                        endmntent(tab);
 
858
                        tree_free_mnt_tree(tree);
 
859
                        return NULL;
 
860
                }
 
861
                strcpy(ent->fs_name, mnt->mnt_fsname);
 
862
 
 
863
                ent->fs_type = malloc(strlen(mnt->mnt_type) + 1);
 
864
                if (!ent->fs_type) {
 
865
                        free(ent->fs_name);
 
866
                        free(ent->path);
 
867
                        free(ent);
 
868
                        endmntent(tab);
 
869
                        tree_free_mnt_tree(tree);
 
870
                        return NULL;
 
871
                }
 
872
                strcpy(ent->fs_type, mnt->mnt_type);
 
873
 
 
874
                ent->opts = malloc(strlen(mnt->mnt_opts) + 1);
 
875
                if (!ent->opts) {
 
876
                        free(ent->fs_type);
 
877
                        free(ent->fs_name);
 
878
                        free(ent->path);
 
879
                        free(ent);
 
880
                        endmntent(tab);
 
881
                        tree_free_mnt_tree(tree);
 
882
                        return NULL;
 
883
                }
 
884
                strcpy(ent->opts, mnt->mnt_opts);
 
885
 
 
886
                ent->owner = 0;
 
887
                pgrp = strstr(mnt->mnt_opts, "pgrp=");
 
888
                if (pgrp) {
 
889
                        char *end = strchr(pgrp, ',');
 
890
                        if (end)
 
891
                                *end = '\0';
 
892
                        sscanf(pgrp, "pgrp=%d", &ent->owner);
 
893
                }
 
894
 
 
895
                mptr = tree;
 
896
                while (mptr) {
 
897
                        int elen = strlen(ent->path);
 
898
                        int mlen = strlen(mptr->path);
 
899
 
 
900
                        if (elen < mlen) {
 
901
                                if (mptr->left) {
 
902
                                        mptr = mptr->left;
 
903
                                        continue;
 
904
                                } else {
 
905
                                        mptr->left = ent;
 
906
                                        break;
 
907
                                }
 
908
                        } else if (elen > mlen) {
 
909
                                if (mptr->right) {
 
910
                                        mptr = mptr->right;
 
911
                                        continue;
 
912
                                } else {
 
913
                                        mptr->right = ent;
 
914
                                        break;
 
915
                                }
 
916
                        }
 
917
 
 
918
                        eq = strcmp(ent->path, mptr->path);
 
919
                        if (eq < 0) {
 
920
                                if (mptr->left)
 
921
                                        mptr = mptr->left;
 
922
                                else {
 
923
                                        mptr->left = ent;
 
924
                                        break;
 
925
                                }
 
926
                        } else if (eq > 0) {
 
927
                                if (mptr->right)
 
928
                                        mptr = mptr->right;
 
929
                                else {
 
930
                                        mptr->right = ent;
 
931
                                        break;
 
932
                                }
 
933
                        } else {
 
934
                                list_add_tail(&ent->self, &mptr->self);
 
935
                                break;
 
936
                        }
 
937
                }
 
938
 
 
939
                if (!tree)
 
940
                        tree = ent;
 
941
        }
 
942
        endmntent(tab);
 
943
 
 
944
        return tree;
 
945
}
 
946
 
 
947
/*
 
948
 * Get list of mounts under "path" in longest->shortest order
 
949
 */
 
950
int tree_get_mnt_list(struct mnt_list *mnts, struct list_head *list, const char *path, int include)
 
951
{
 
952
        size_t mlen, plen;
 
953
 
 
954
        if (!mnts)
 
955
                return 0;
 
956
 
 
957
        plen = strlen(path);
 
958
        mlen = strlen(mnts->path);
 
959
        if (mlen < plen)
 
960
                return tree_get_mnt_list(mnts->right, list, path, include);
 
961
        else {
 
962
                struct list_head *self, *p;
 
963
 
 
964
                tree_get_mnt_list(mnts->left, list, path, include);
 
965
 
 
966
                if ((!include && mlen <= plen) ||
 
967
                                strncmp(mnts->path, path, plen))
 
968
                        goto skip;
 
969
 
 
970
                if (plen > 1 && mlen > plen && mnts->path[plen] != '/')
 
971
                        goto skip;
 
972
 
 
973
                INIT_LIST_HEAD(&mnts->list);
 
974
                list_add(&mnts->list, list);
 
975
 
 
976
                self = &mnts->self;
 
977
                list_for_each(p, self) {
 
978
                        struct mnt_list *this;
 
979
 
 
980
                        this = list_entry(p, struct mnt_list, self);
 
981
                        INIT_LIST_HEAD(&this->list);
 
982
                        list_add(&this->list, list);
 
983
                }
 
984
skip:
 
985
                tree_get_mnt_list(mnts->right, list, path, include);
 
986
        }
 
987
 
 
988
        if (list_empty(list))
 
989
                return 0;
 
990
 
 
991
        return 1;
 
992
}
 
993
 
 
994
/*
 
995
 * Get list of mounts under "path" in longest->shortest order
 
996
 */
 
997
int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include)
 
998
{
 
999
        size_t mlen, plen;
 
1000
 
 
1001
        if (!mnts)
 
1002
                return 0;
 
1003
 
 
1004
        plen = strlen(path);
 
1005
        mlen = strlen(mnts->path);
 
1006
        if (mlen < plen)
 
1007
                return tree_get_mnt_sublist(mnts->right, list, path, include);
 
1008
        else {
 
1009
                struct list_head *self, *p;
 
1010
 
 
1011
                tree_get_mnt_sublist(mnts->left, list, path, include);
 
1012
 
 
1013
                if ((!include && mlen <= plen) ||
 
1014
                                strncmp(mnts->path, path, plen))
 
1015
                        goto skip;
 
1016
 
 
1017
                if (plen > 1 && mlen > plen && mnts->path[plen] != '/')
 
1018
                        goto skip;
 
1019
 
 
1020
                INIT_LIST_HEAD(&mnts->sublist);
 
1021
                list_add(&mnts->sublist, list);
 
1022
 
 
1023
                self = &mnts->self;
 
1024
                list_for_each(p, self) {
 
1025
                        struct mnt_list *this;
 
1026
 
 
1027
                        this = list_entry(p, struct mnt_list, self);
 
1028
                        INIT_LIST_HEAD(&this->sublist);
 
1029
                        list_add(&this->sublist, list);
 
1030
                }
 
1031
skip:
 
1032
                tree_get_mnt_sublist(mnts->right, list, path, include);
 
1033
        }
 
1034
 
 
1035
        if (list_empty(list))
 
1036
                return 0;
 
1037
 
 
1038
        return 1;
 
1039
}
 
1040
 
 
1041
int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path)
 
1042
{
 
1043
        int mlen, plen;
 
1044
 
 
1045
        if (!mnts)
 
1046
                return 0;
 
1047
 
 
1048
        plen = strlen(path);
 
1049
        mlen = strlen(mnts->path);
 
1050
        if (mlen < plen)
 
1051
                return tree_find_mnt_ents(mnts->right, list, path);
 
1052
        else if (mlen > plen)
 
1053
                return tree_find_mnt_ents(mnts->left, list, path);
 
1054
        else {
 
1055
                struct list_head *self, *p;
 
1056
 
 
1057
                tree_find_mnt_ents(mnts->left, list, path);
 
1058
 
 
1059
                if (!strcmp(mnts->path, path)) {
 
1060
                        INIT_LIST_HEAD(&mnts->entries);
 
1061
                        list_add(&mnts->entries, list);
 
1062
                }
 
1063
 
 
1064
                self = &mnts->self;
 
1065
                list_for_each(p, self) {
 
1066
                        struct mnt_list *this;
 
1067
 
 
1068
                        this = list_entry(p, struct mnt_list, self);
 
1069
 
 
1070
                        if (!strcmp(this->path, path)) {
 
1071
                                INIT_LIST_HEAD(&this->entries);
 
1072
                                list_add(&this->entries, list);
 
1073
                        }
 
1074
                }
 
1075
 
 
1076
                tree_find_mnt_ents(mnts->right, list, path);
 
1077
 
 
1078
                if (!list_empty(list))
 
1079
                        return 1;
 
1080
        }
 
1081
 
 
1082
        return 0;
 
1083
}
 
1084
 
 
1085
int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type)
 
1086
{
 
1087
        struct ioctl_ops *ops = get_ioctl_ops();
 
1088
        struct list_head *p;
 
1089
        struct list_head list;
 
1090
        int mounted = 0;
 
1091
 
 
1092
        if (ops->ismountpoint)
 
1093
                return ioctl_is_mounted(path, type);
 
1094
 
 
1095
        INIT_LIST_HEAD(&list);
 
1096
 
 
1097
        if (!tree_find_mnt_ents(mnts, &list, path))
 
1098
                return 0;
 
1099
 
 
1100
        list_for_each(p, &list) {
 
1101
                struct mnt_list *mptr;
 
1102
 
 
1103
                mptr = list_entry(p, struct mnt_list, entries);
 
1104
 
 
1105
                if (type) {
 
1106
                        unsigned int autofs_fs;
 
1107
 
 
1108
                        autofs_fs = !strcmp(mptr->fs_type, "autofs");
 
1109
 
 
1110
                        if (type & MNTS_REAL) {
 
1111
                                if (!autofs_fs) {
 
1112
                                        mounted = 1;
 
1113
                                        break;
 
1114
                                }
 
1115
                        } else if (type & MNTS_AUTOFS) {
 
1116
                                if (autofs_fs) {
 
1117
                                        mounted = 1;
 
1118
                                        break;
 
1119
                                }
 
1120
                        } else {
 
1121
                                mounted = 1;
 
1122
                                break;
 
1123
                        }
 
1124
                }
 
1125
        }
 
1126
        return mounted;
 
1127
}
 
1128
 
 
1129
void set_tsd_user_vars(unsigned int logopt, uid_t uid, gid_t gid)
 
1130
{
 
1131
        struct thread_stdenv_vars *tsv;
 
1132
        struct passwd pw;
 
1133
        struct passwd *ppw = &pw;
 
1134
        struct passwd **pppw = &ppw;
 
1135
        struct group gr;
 
1136
        struct group *pgr;
 
1137
        struct group **ppgr;
 
1138
        char *pw_tmp, *gr_tmp;
 
1139
        int status, tmplen, grplen;
 
1140
 
 
1141
        /*
 
1142
         * Setup thread specific data values for macro
 
1143
         * substution in map entries during the mount.
 
1144
         * Best effort only as it must go ahead.
 
1145
         */
 
1146
 
 
1147
        tsv = malloc(sizeof(struct thread_stdenv_vars));
 
1148
        if (!tsv) {
 
1149
                error(logopt, "failed alloc tsv storage");
 
1150
                return;
 
1151
        }
 
1152
 
 
1153
        tsv->uid = uid;
 
1154
        tsv->gid = gid;
 
1155
 
 
1156
        /* Try to get passwd info */
 
1157
 
 
1158
        tmplen = sysconf(_SC_GETPW_R_SIZE_MAX);
 
1159
        if (tmplen < 0) {
 
1160
                error(logopt, "failed to get buffer size for getpwuid_r");
 
1161
                goto free_tsv;
 
1162
        }
 
1163
 
 
1164
        pw_tmp = malloc(tmplen + 1);
 
1165
        if (!pw_tmp) {
 
1166
                error(logopt, "failed to malloc buffer for getpwuid_r");
 
1167
                goto free_tsv;
 
1168
        }
 
1169
 
 
1170
        status = getpwuid_r(uid, ppw, pw_tmp, tmplen, pppw);
 
1171
        if (status || !ppw) {
 
1172
                error(logopt, "failed to get passwd info from getpwuid_r");
 
1173
                free(pw_tmp);
 
1174
                goto free_tsv;
 
1175
        }
 
1176
 
 
1177
        tsv->user = strdup(pw.pw_name);
 
1178
        if (!tsv->user) {
 
1179
                error(logopt, "failed to malloc buffer for user");
 
1180
                free(pw_tmp);
 
1181
                goto free_tsv;
 
1182
        }
 
1183
 
 
1184
        tsv->home = strdup(pw.pw_dir);
 
1185
        if (!tsv->home) {
 
1186
                error(logopt, "failed to malloc buffer for home");
 
1187
                free(pw_tmp);
 
1188
                goto free_tsv_user;
 
1189
        }
 
1190
 
 
1191
        free(pw_tmp);
 
1192
 
 
1193
        /* Try to get group info */
 
1194
 
 
1195
        grplen = sysconf(_SC_GETGR_R_SIZE_MAX);
 
1196
        if (tmplen < 0) {
 
1197
                error(logopt, "failed to get buffer size for getgrgid_r");
 
1198
                goto free_tsv_home;
 
1199
        }
 
1200
 
 
1201
        gr_tmp = NULL;
 
1202
        tmplen = grplen;
 
1203
        while (1) {
 
1204
                char *tmp = realloc(gr_tmp, tmplen + 1);
 
1205
                if (!tmp) {
 
1206
                        error(logopt, "failed to malloc buffer for getgrgid_r");
 
1207
                        if (gr_tmp)
 
1208
                                free(gr_tmp);
 
1209
                        goto free_tsv_home;
 
1210
                }
 
1211
                gr_tmp = tmp;
 
1212
                pgr = &gr;
 
1213
                ppgr = &pgr;
 
1214
                status = getgrgid_r(gid, pgr, gr_tmp, tmplen, ppgr);
 
1215
                if (status != ERANGE)
 
1216
                        break;
 
1217
                tmplen += grplen;
 
1218
        }
 
1219
 
 
1220
        if (status || !pgr) {
 
1221
                error(logopt, "failed to get group info from getgrgid_r");
 
1222
                free(gr_tmp);
 
1223
                goto free_tsv_home;
 
1224
        }
 
1225
 
 
1226
        tsv->group = strdup(gr.gr_name);
 
1227
        if (!tsv->group) {
 
1228
                error(logopt, "failed to malloc buffer for group");
 
1229
                free(gr_tmp);
 
1230
                goto free_tsv_home;
 
1231
        }
 
1232
 
 
1233
        free(gr_tmp);
 
1234
 
 
1235
        status = pthread_setspecific(key_thread_stdenv_vars, tsv);
 
1236
        if (status) {
 
1237
                error(logopt, "failed to set stdenv thread var");
 
1238
                goto free_tsv_group;
 
1239
        }
 
1240
 
 
1241
        return;
 
1242
 
 
1243
free_tsv_group:
 
1244
        free(tsv->group);
 
1245
free_tsv_home:
 
1246
        free(tsv->home);
 
1247
free_tsv_user:
 
1248
        free(tsv->user);
 
1249
free_tsv:
 
1250
        free(tsv);
 
1251
        return;
 
1252
}
 
1253
 
 
1254
const char *mount_type_str(const unsigned int type)
 
1255
{
 
1256
        static const char *str_type[] = {
 
1257
                "indirect",
 
1258
                "direct",
 
1259
                "offset"
 
1260
        };
 
1261
        unsigned int pos, i;
 
1262
 
 
1263
        for (pos = 0, i = type; pos < type_count; i >>= 1, pos++)
 
1264
                if (i & 0x1)
 
1265
                        break;
 
1266
 
 
1267
        return (pos == type_count ? NULL : str_type[pos]);
 
1268
}
 
1269
 
 
1270
void notify_mount_result(struct autofs_point *ap,
 
1271
                         const char *path, const char *type)
 
1272
{
 
1273
        if (ap->exp_timeout)
 
1274
                info(ap->logopt,
 
1275
                    "mounted %s on %s with timeout %u, freq %u seconds",
 
1276
                    type, path,
 
1277
                    (unsigned int) ap->exp_timeout,
 
1278
                    (unsigned int) ap->exp_runfreq);
 
1279
        else
 
1280
                info(ap->logopt,
 
1281
                     "mounted %s on %s with timeouts disabled",
 
1282
                     type, path);
 
1283
 
 
1284
        return;
 
1285
}
 
1286
 
 
1287
static int do_remount_direct(struct autofs_point *ap, int fd, const char *path)
 
1288
{
 
1289
        struct ioctl_ops *ops = get_ioctl_ops();
 
1290
        int status = REMOUNT_SUCCESS;
 
1291
        uid_t uid;
 
1292
        gid_t gid;
 
1293
        int ret;
 
1294
 
 
1295
        ops->requestor(ap->logopt, fd, path, &uid, &gid);
 
1296
        if (uid != -1 && gid != -1)
 
1297
                set_tsd_user_vars(ap->logopt, uid, gid);
 
1298
 
 
1299
        ret = lookup_nss_mount(ap, NULL, path, strlen(path));
 
1300
        if (ret)
 
1301
                info(ap->logopt, "re-connected to %s", path);
 
1302
        else {
 
1303
                status = REMOUNT_FAIL;
 
1304
                info(ap->logopt, "failed to re-connect %s", path);
 
1305
        }
 
1306
 
 
1307
        return status;
 
1308
}
 
1309
 
 
1310
static int do_remount_indirect(struct autofs_point *ap, int fd, const char *path)
 
1311
{
 
1312
        struct ioctl_ops *ops = get_ioctl_ops();
 
1313
        int status = REMOUNT_SUCCESS;
 
1314
        struct dirent **de;
 
1315
        char buf[PATH_MAX + 1];
 
1316
        uid_t uid;
 
1317
        gid_t gid;
 
1318
        unsigned int mounted;
 
1319
        int n, size;
 
1320
 
 
1321
        n = scandir(path, &de, 0, alphasort);
 
1322
        if (n < 0)
 
1323
                return -1;
 
1324
 
 
1325
        size = sizeof(buf);
 
1326
 
 
1327
        while (n--) {
 
1328
                int ret, len;
 
1329
 
 
1330
                if (strcmp(de[n]->d_name, ".") == 0 ||
 
1331
                    strcmp(de[n]->d_name, "..") == 0) {
 
1332
                        free(de[n]);
 
1333
                        continue;
 
1334
                }
 
1335
 
 
1336
                ret = cat_path(buf, size, path, de[n]->d_name);
 
1337
                if (!ret) {
 
1338
                        do {
 
1339
                                free(de[n]);
 
1340
                        } while (n--);
 
1341
                        free(de);
 
1342
                        return -1;
 
1343
                }
 
1344
 
 
1345
                ops->ismountpoint(ap->logopt, -1, buf, &mounted);
 
1346
                if (!mounted) {
 
1347
                        struct dirent **de2;
 
1348
                        int i, j;
 
1349
 
 
1350
                        i = j = scandir(buf, &de2, 0, alphasort);
 
1351
                        if (i < 0) {
 
1352
                                free(de[n]);
 
1353
                                continue;
 
1354
                        }
 
1355
                        while (i--)
 
1356
                                free(de2[i]);
 
1357
                        free(de2);
 
1358
                        if (j <= 2) {
 
1359
                                free(de[n]);
 
1360
                                continue;
 
1361
                        }
 
1362
                }
 
1363
 
 
1364
                ops->requestor(ap->logopt, fd, buf, &uid, &gid);
 
1365
                if (uid != -1 && gid != -1)
 
1366
                        set_tsd_user_vars(ap->logopt, uid, gid);
 
1367
 
 
1368
                len = strlen(de[n]->d_name);
 
1369
 
 
1370
                ret = lookup_nss_mount(ap, NULL, de[n]->d_name, len);
 
1371
                if (ret)
 
1372
                        info(ap->logopt, "re-connected to %s", buf);
 
1373
                else {
 
1374
                        status = REMOUNT_FAIL;
 
1375
                        info(ap->logopt, "failed to re-connect %s", buf);
 
1376
                }
 
1377
                free(de[n]);
 
1378
        }
 
1379
        free(de);
 
1380
 
 
1381
        return status;
 
1382
}
 
1383
 
 
1384
static int remount_active_mount(struct autofs_point *ap,
 
1385
                                struct mapent_cache *mc,
 
1386
                                const char *path, dev_t devid,
 
1387
                                const unsigned int type,
 
1388
                                int *ioctlfd)
 
1389
{
 
1390
        struct ioctl_ops *ops = get_ioctl_ops();
 
1391
        time_t timeout = ap->exp_timeout;
 
1392
        const char *str_type = mount_type_str(type);
 
1393
        char buf[MAX_ERR_BUF];
 
1394
        unsigned int mounted;
 
1395
        struct stat st;
 
1396
        int fd;
 
1397
 
 
1398
        *ioctlfd = -1;
 
1399
 
 
1400
        /* Open failed, no mount present */
 
1401
        ops->open(ap->logopt, &fd, devid, path);
 
1402
        if (fd == -1)
 
1403
                return REMOUNT_OPEN_FAIL;
 
1404
 
 
1405
        /* Re-reading the map, set timeout and return */
 
1406
        if (ap->state == ST_READMAP) {
 
1407
                ops->timeout(ap->logopt, fd, &timeout);
 
1408
                ops->close(ap->logopt, fd);
 
1409
                return REMOUNT_READ_MAP;
 
1410
        }
 
1411
 
 
1412
        debug(ap->logopt, "trying to re-connect to mount %s", path);
 
1413
 
 
1414
        /* Mounted so set pipefd and timeout etc. */
 
1415
        if (ops->catatonic(ap->logopt, fd) == -1) {
 
1416
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
1417
                error(ap->logopt, "set catatonic failed: %s", estr);
 
1418
                debug(ap->logopt, "couldn't re-connect to mount %s", path);
 
1419
                ops->close(ap->logopt, fd);
 
1420
                return REMOUNT_OPEN_FAIL;
 
1421
        }
 
1422
        if (ops->setpipefd(ap->logopt, fd, ap->kpipefd) == -1) {
 
1423
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
1424
                error(ap->logopt, "set pipefd failed: %s", estr);
 
1425
                debug(ap->logopt, "couldn't re-connect to mount %s", path);
 
1426
                ops->close(ap->logopt, fd);
 
1427
                return REMOUNT_OPEN_FAIL;
 
1428
        }
 
1429
        ops->timeout(ap->logopt, fd, &timeout);
 
1430
        if (fstat(fd, &st) == -1) {
 
1431
                error(ap->logopt,
 
1432
                      "failed to stat %s mount %s", str_type, path);
 
1433
                debug(ap->logopt, "couldn't re-connect to mount %s", path);
 
1434
                ops->close(ap->logopt, fd);
 
1435
                return REMOUNT_STAT_FAIL;
 
1436
        }
 
1437
        if (mc)
 
1438
                cache_set_ino_index(mc, path, st.st_dev, st.st_ino);
 
1439
        else
 
1440
                ap->dev = st.st_dev;
 
1441
        notify_mount_result(ap, path, str_type);
 
1442
 
 
1443
        *ioctlfd = fd;
 
1444
 
 
1445
        /* Any mounts on or below? */
 
1446
        if (ops->ismountpoint(ap->logopt, fd, path, &mounted) == -1) {
 
1447
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
1448
                error(ap->logopt, "ismountpoint %s failed: %s", path, estr);
 
1449
                debug(ap->logopt, "couldn't re-connect to mount %s", path);
 
1450
                ops->close(ap->logopt, fd);
 
1451
                return REMOUNT_FAIL;
 
1452
        }
 
1453
        if (!mounted) {
 
1454
                /*
 
1455
                 * If we're an indirect mount we pass back the fd.
 
1456
                 * But if were a direct or offset mount with no active
 
1457
                 * mount we don't retain an open file descriptor.
 
1458
                 */
 
1459
                if (type != t_indirect) {
 
1460
                        ops->close(ap->logopt, fd);
 
1461
                        *ioctlfd = -1;
 
1462
                }
 
1463
        } else {
 
1464
                int ret;
 
1465
                /*
 
1466
                 * What can I do if we can't remount the existing
 
1467
                 * mount(s) (possibly a partial failure), everything
 
1468
                 * following will be broken?
 
1469
                 */
 
1470
                if (type == t_indirect)
 
1471
                        ret = do_remount_indirect(ap, fd, path);
 
1472
                else
 
1473
                        ret = do_remount_direct(ap, fd, path);
 
1474
        }
 
1475
 
 
1476
        debug(ap->logopt, "re-connected to mount %s", path);
 
1477
 
 
1478
        return REMOUNT_SUCCESS;
 
1479
}
 
1480
 
 
1481
int try_remount(struct autofs_point *ap, struct mapent *me, unsigned int type)
 
1482
{
 
1483
        struct ioctl_ops *ops = get_ioctl_ops();
 
1484
        struct mapent_cache *mc;
 
1485
        const char *path;
 
1486
        int ret, fd;
 
1487
        dev_t devid;
 
1488
 
 
1489
        if (type == t_indirect) {
 
1490
                mc = NULL;
 
1491
                path = ap->path;
 
1492
        } else {
 
1493
                mc = me->mc;
 
1494
                path = me->key;
 
1495
        }
 
1496
 
 
1497
        ret = ops->mount_device(ap->logopt, path, type, &devid);
 
1498
        if (ret == -1 || ret == 0)
 
1499
                return -1;
 
1500
 
 
1501
        ret = remount_active_mount(ap, mc, path, devid, type, &fd);
 
1502
 
 
1503
        /*
 
1504
         * The directory must exist since we found a device
 
1505
         * number for the mount but we can't know if we created
 
1506
         * it or not. However, if this is an indirect mount with
 
1507
         * the nobrowse option we need to remove the mount point
 
1508
         * directory at umount anyway.
 
1509
         */
 
1510
        if (type == t_indirect) {
 
1511
                if (ap->flags & MOUNT_FLAG_GHOST)
 
1512
                        ap->flags &= ~MOUNT_FLAG_DIR_CREATED;
 
1513
                else
 
1514
                        ap->flags |= MOUNT_FLAG_DIR_CREATED;
 
1515
        } else
 
1516
                me->flags &= ~MOUNT_FLAG_DIR_CREATED;
 
1517
 
 
1518
        /*
 
1519
         * Either we opened the mount or we're re-reading the map.
 
1520
         * If we opened the mount and ioctlfd is not -1 we have
 
1521
         * a descriptor for the indirect mount so we need to
 
1522
         * record that in the mount point struct. Otherwise we're
 
1523
         * re-reading the map.
 
1524
        */
 
1525
        if (ret == REMOUNT_SUCCESS || ret == REMOUNT_READ_MAP) {
 
1526
                if (fd != -1) {
 
1527
                        if (type == t_indirect)
 
1528
                                ap->ioctlfd = fd;
 
1529
                        else
 
1530
                                me->ioctlfd = fd;
 
1531
                        return 1;
 
1532
                }
 
1533
 
 
1534
                /* Indirect mount requires a valid fd */
 
1535
                if (type != t_indirect)
 
1536
                        return 1;
 
1537
        }
 
1538
 
 
1539
        /*
 
1540
         * Since we got the device number above a mount exists so
 
1541
         * any other failure warrants a failure return here.
 
1542
         */
 
1543
        return 0;
 
1544
}
 
1545
 
 
1546
int umount_ent(struct autofs_point *ap, const char *path)
 
1547
{
 
1548
        int rv;
 
1549
 
 
1550
        rv = spawn_umount(ap->logopt, path, NULL);
 
1551
        /* We are doing a forced shutcwdown down so unlink busy mounts */
 
1552
        if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) {
 
1553
                if (ap->state == ST_SHUTDOWN_FORCE) {
 
1554
                        info(ap->logopt, "forcing umount of %s", path);
 
1555
                        rv = spawn_umount(ap->logopt, "-l", path, NULL);
 
1556
                }
 
1557
 
 
1558
                /*
 
1559
                 * Verify that we actually unmounted the thing.  This is a
 
1560
                 * belt and suspenders approach to not eating user data.
 
1561
                 * We have seen cases where umount succeeds, but there is
 
1562
                 * still a file system mounted on the mount point.  How
 
1563
                 * this happens has not yet been determined, but we want to
 
1564
                 * make sure to return failure here, if that is the case,
 
1565
                 * so that we do not try to call rmdir_path on the
 
1566
                 * directory.
 
1567
                 */
 
1568
                if (!rv && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
 
1569
                        crit(ap->logopt,
 
1570
                             "the umount binary reported that %s was "
 
1571
                             "unmounted, but there is still something "
 
1572
                             "mounted on this path.", path);
 
1573
                        rv = -1;
 
1574
                }
 
1575
        }
 
1576
 
 
1577
        return rv;
 
1578
}
 
1579
 
 
1580
int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
 
1581
                         const char *root, unsigned int start, const char *base)
 
1582
{
 
1583
        char path[PATH_MAX + 1];
 
1584
        char *offset = path;
 
1585
        struct mapent *oe;
 
1586
        struct list_head *pos = NULL;
 
1587
        unsigned int fs_path_len;
 
1588
        unsigned int mounted;
 
1589
        int ret;
 
1590
 
 
1591
        fs_path_len = start + strlen(base);
 
1592
        if (fs_path_len > PATH_MAX)
 
1593
                return -1;
 
1594
 
 
1595
        mounted = 0;
 
1596
        offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
 
1597
        while (offset) {
 
1598
                int plen = fs_path_len + strlen(offset);
 
1599
 
 
1600
                if (plen > PATH_MAX) {
 
1601
                        warn(ap->logopt, "path loo long");
 
1602
                        goto cont;
 
1603
                }
 
1604
 
 
1605
                oe = cache_lookup_offset(base, offset, start, &me->multi_list);
 
1606
                if (!oe || !oe->mapent)
 
1607
                        goto cont;
 
1608
 
 
1609
                debug(ap->logopt, "mount offset %s at %s", oe->key, root);
 
1610
 
 
1611
                ret = mount_autofs_offset(ap, oe, root, offset);
 
1612
                if (ret >= MOUNT_OFFSET_OK)
 
1613
                        mounted++;
 
1614
                else {
 
1615
                        if (ret != MOUNT_OFFSET_IGNORE)
 
1616
                                warn(ap->logopt, "failed to mount offset");
 
1617
                        else {
 
1618
                                debug(ap->logopt,
 
1619
                                      "ignoring \"nohide\" trigger %s",
 
1620
                                      oe->key);
 
1621
                                free(oe->mapent);
 
1622
                                oe->mapent = NULL;
 
1623
                        }
 
1624
                }
 
1625
cont:
 
1626
                offset = cache_get_offset(base,
 
1627
                                offset, start, &me->multi_list, &pos);
 
1628
        }
 
1629
 
 
1630
        return mounted;
 
1631
}
 
1632
 
 
1633
int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base)
 
1634
{
 
1635
        char path[PATH_MAX + 1];
 
1636
        char *offset;
 
1637
        struct mapent *oe;
 
1638
        struct list_head *mm_root, *pos;
 
1639
        const char o_root[] = "/";
 
1640
        const char *mm_base;
 
1641
        int left, start;
 
1642
 
 
1643
        left = 0;
 
1644
        start = strlen(root);
 
1645
 
 
1646
        mm_root = &me->multi->multi_list;
 
1647
 
 
1648
        if (!base)
 
1649
                mm_base = o_root;
 
1650
        else
 
1651
                mm_base = base;
 
1652
 
 
1653
        pos = NULL;
 
1654
        offset = path;
 
1655
 
 
1656
        /* Make sure "none" of the offsets have an active mount. */
 
1657
        while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
 
1658
                char *oe_base;
 
1659
 
 
1660
                oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
 
1661
                /* root offset is a special case */
 
1662
                if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
 
1663
                        continue;
 
1664
 
 
1665
                /*
 
1666
                 * Check for and umount subtree offsets resulting from
 
1667
                 * nonstrict mount fail.
 
1668
                 */
 
1669
                oe_base = oe->key + strlen(root);
 
1670
                left += umount_multi_triggers(ap, oe, root, oe_base);
 
1671
 
 
1672
                if (oe->ioctlfd != -1 ||
 
1673
                    is_mounted(_PROC_MOUNTS, oe->key, MNTS_REAL)) {
 
1674
                        left++;
 
1675
                        break;
 
1676
                }
 
1677
        }
 
1678
 
 
1679
        if (left)
 
1680
                return left;
 
1681
 
 
1682
        pos = NULL;
 
1683
        offset = path;
 
1684
 
 
1685
        /* Make sure "none" of the offsets have an active mount. */
 
1686
        while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
 
1687
                oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
 
1688
                /* root offset is a special case */
 
1689
                if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
 
1690
                        continue;
 
1691
 
 
1692
                debug(ap->logopt, "umount offset %s", oe->key);
 
1693
 
 
1694
                if (umount_autofs_offset(ap, oe)) {
 
1695
                        warn(ap->logopt, "failed to umount offset");
 
1696
                        left++;
 
1697
                }
 
1698
        }
 
1699
 
 
1700
        if (!left && me->multi == me) {
 
1701
                struct mapent_cache *mc = me->mc;
 
1702
                int status;
 
1703
 
 
1704
                /*
 
1705
                 * Special case.
 
1706
                 * If we can't umount the root container then we can't
 
1707
                 * delete the offsets from the cache and we need to put
 
1708
                 * the offset triggers back.
 
1709
                 */
 
1710
                if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) {
 
1711
                        info(ap->logopt, "unmounting dir = %s", root);
 
1712
                        if (umount_ent(ap, root)) {
 
1713
                                if (mount_multi_triggers(ap, me, root, strlen(root), "/") < 0)
 
1714
                                        warn(ap->logopt,
 
1715
                                             "failed to remount offset triggers");
 
1716
                                return left++;
 
1717
                        }
 
1718
                }
 
1719
 
 
1720
                /* We're done - clean out the offsets */
 
1721
                status = cache_delete_offset_list(mc, me->key);
 
1722
                if (status != CHE_OK)
 
1723
                        warn(ap->logopt, "couldn't delete offset list");
 
1724
        }
 
1725
 
 
1726
        return left;
334
1727
}
335
1728