~ubuntu-branches/ubuntu/natty/autofs5/natty-proposed

« back to all changes in this revision

Viewing changes to daemon/indirect.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Christoph Nordholz
  • Date: 2008-04-28 15:55:37 UTC
  • Revision ID: james.westby@ubuntu.com-20080428155537-h6h457h1fwwzhvby
Tags: upstream-5.0.3
ImportĀ upstreamĀ versionĀ 5.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ----------------------------------------------------------------------- *
 
2
 *
 
3
 *  indirect.c - Linux automounter indirect mount handling
 
4
 *   
 
5
 *   Copyright 1997 Transmeta Corporation - All Rights Reserved
 
6
 *   Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
 
7
 *   Copyright 2001-2005 Ian Kent <raven@themaw.net>
 
8
 *
 
9
 *   This program is free software; you can redistribute it and/or modify
 
10
 *   it under the terms of the GNU General Public License as published by
 
11
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
 
12
 *   USA; either version 2 of the License, or (at your option) any later
 
13
 *   version.
 
14
 *   
 
15
 *   This program is distributed in the hope that it will be useful,
 
16
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 *   GNU General Public License for more details.
 
19
 *
 
20
 * ----------------------------------------------------------------------- */
 
21
 
 
22
#include <dirent.h>
 
23
#include <fcntl.h>
 
24
#include <signal.h>
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#include <unistd.h>
 
29
#include <sys/ioctl.h>
 
30
#include <sys/types.h>
 
31
#include <sys/wait.h>
 
32
#include <sys/stat.h>
 
33
#include <sys/time.h>
 
34
#include <sys/mount.h>
 
35
#include <sched.h>
 
36
#include <pwd.h>
 
37
#include <grp.h>
 
38
 
 
39
#include "automount.h"
 
40
 
 
41
extern pthread_attr_t thread_attr;
 
42
 
 
43
static pthread_mutex_t ma_mutex = PTHREAD_MUTEX_INITIALIZER;
 
44
static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER;
 
45
 
 
46
static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
 
47
{
 
48
        struct mnt_list *this;
 
49
        int rv, ret;
 
50
        pid_t pgrp = getpgrp();
 
51
        char spgrp[20];
 
52
 
 
53
        sprintf(spgrp, "pgrp=%d", pgrp);
 
54
 
 
55
        ret = 1;
 
56
        this = mnts;
 
57
        while (this) {
 
58
                if (strstr(this->opts, spgrp)) {
 
59
                        this = this->next;
 
60
                        continue;
 
61
                }
 
62
 
 
63
                if (strcmp(this->fs_type, "autofs"))
 
64
                        rv = spawn_umount(ap->logopt, "-l", this->path, NULL);
 
65
                else
 
66
                        rv = umount2(this->path, MNT_DETACH);
 
67
                if (rv == -1) {
 
68
                        ret = 0;
 
69
                        debug(ap->logopt,
 
70
                              "can't unlink %s from mount tree", this->path);
 
71
 
 
72
                        switch (errno) {
 
73
                        case EINVAL:
 
74
                                warn(ap->logopt,
 
75
                                      "bad superblock or not mounted");
 
76
                                break;
 
77
 
 
78
                        case ENOENT:
 
79
                        case EFAULT:
 
80
                                warn(ap->logopt, "bad path for mount");
 
81
                                break;
 
82
                        }
 
83
                }
 
84
                this = this->next;
 
85
        }
 
86
        return ret;
 
87
}
 
88
 
 
89
static int do_mount_autofs_indirect(struct autofs_point *ap)
 
90
{
 
91
        time_t timeout = ap->exp_timeout;
 
92
        char *options = NULL;
 
93
        const char *type, *map_name = NULL;
 
94
        struct stat st;
 
95
        struct mnt_list *mnts;
 
96
        int cl_flags, ret;
 
97
 
 
98
        mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1);
 
99
        if (mnts) {
 
100
                ret = unlink_mount_tree(ap, mnts);
 
101
                free_mnt_list(mnts);
 
102
                if (!ret) {
 
103
                        debug(ap->logopt,
 
104
                              "already mounted as other than autofs "
 
105
                              "or failed to unlink entry in tree");
 
106
                        goto out_err;
 
107
                }
 
108
        }
 
109
 
 
110
        options = make_options_string(ap->path, ap->kpipefd, NULL);
 
111
        if (!options)
 
112
                goto out_err;
 
113
 
 
114
        /* In case the directory doesn't exist, try to mkdir it */
 
115
        if (mkdir_path(ap->path, 0555) < 0) {
 
116
                if (errno != EEXIST && errno != EROFS) {
 
117
                        crit(ap->logopt,
 
118
                             "failed to create autofs directory %s",
 
119
                             ap->path);
 
120
                        goto out_err;
 
121
                }
 
122
                /* If we recieve an error, and it's EEXIST or EROFS we know
 
123
                   the directory was not created. */
 
124
                ap->dir_created = 0;
 
125
        } else {
 
126
                /* No errors so the directory was successfully created */
 
127
                ap->dir_created = 1;
 
128
        }
 
129
 
 
130
        type = ap->entry->maps->type;
 
131
        if (type && !strcmp(ap->entry->maps->type, "hosts")) {
 
132
                char *tmp = alloca(7);
 
133
                if (tmp) {
 
134
                        strcpy(tmp, "-hosts");
 
135
                        map_name = (const char *) tmp;
 
136
                }
 
137
        } else
 
138
                map_name = ap->entry->maps->argv[0];
 
139
 
 
140
        ret = mount(map_name, ap->path, "autofs", MS_MGC_VAL, options);
 
141
        if (ret) {
 
142
                crit(ap->logopt, "failed to mount autofs path %s", ap->path);
 
143
                goto out_rmdir;
 
144
        }
 
145
 
 
146
        free(options);
 
147
 
 
148
        options = NULL;
 
149
 
 
150
        /* Root directory for ioctl()'s */
 
151
        ap->ioctlfd = open(ap->path, O_RDONLY);
 
152
        if (ap->ioctlfd < 0) {
 
153
                crit(ap->logopt,
 
154
                     "failed to create ioctl fd for autofs path %s", ap->path);
 
155
                goto out_umount;
 
156
        }
 
157
 
 
158
        if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) {
 
159
                cl_flags |= FD_CLOEXEC;
 
160
                fcntl(ap->ioctlfd, F_SETFD, cl_flags);
 
161
        }
 
162
 
 
163
        ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
 
164
 
 
165
        ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
 
166
 
 
167
        if (ap->exp_timeout)
 
168
                info(ap->logopt,
 
169
                    "mounted indirect mount on %s "
 
170
                    "with timeout %u, freq %u seconds", ap->path,
 
171
                    (unsigned int) ap->exp_timeout,
 
172
                    (unsigned int) ap->exp_runfreq);
 
173
        else
 
174
                info(ap->logopt,
 
175
                    "mounted indirect mount on %s with timeouts disabled",
 
176
                    ap->path);
 
177
 
 
178
        fstat(ap->ioctlfd, &st);
 
179
        ap->dev = st.st_dev;    /* Device number for mount point checks */
 
180
 
 
181
        return 0;
 
182
 
 
183
out_umount:
 
184
        umount(ap->path);
 
185
out_rmdir:
 
186
        if (ap->dir_created)
 
187
                rmdir_path(ap, ap->path, ap->dev);
 
188
out_err:
 
189
        if (options)
 
190
                free(options);
 
191
        close(ap->state_pipe[0]);
 
192
        close(ap->state_pipe[1]);
 
193
        close(ap->pipefd);
 
194
        close(ap->kpipefd);
 
195
 
 
196
        return -1;
 
197
}
 
198
 
 
199
int mount_autofs_indirect(struct autofs_point *ap)
 
200
{
 
201
        time_t now = time(NULL);
 
202
        int status;
 
203
        int map;
 
204
 
 
205
        /* TODO: read map, determine map type is OK */
 
206
        if (lookup_nss_read_map(ap, NULL, now))
 
207
                lookup_prune_cache(ap, now);
 
208
        else {
 
209
                error(ap->logopt, "failed to read map for %s", ap->path);
 
210
                return -1;
 
211
        }
 
212
 
 
213
        status = do_mount_autofs_indirect(ap);
 
214
        if (status < 0)
 
215
                return -1;
 
216
 
 
217
        map = lookup_ghost(ap);
 
218
        if (map & LKP_FAIL) {
 
219
                if (map & LKP_DIRECT) {
 
220
                        error(ap->logopt,
 
221
                              "bad map format,found direct, "
 
222
                              "expected indirect exiting");
 
223
                } else {
 
224
                        error(ap->logopt, "failed to load map, exiting");
 
225
                }
 
226
                /* TODO: Process cleanup ?? */
 
227
                return -1;
 
228
        }
 
229
 
 
230
        if (map & LKP_NOTSUP)
 
231
                ap->ghost = 0;
 
232
 
 
233
        return 0;
 
234
}
 
235
 
 
236
int umount_autofs_indirect(struct autofs_point *ap)
 
237
{
 
238
        char buf[MAX_ERR_BUF];
 
239
        int ret, rv, retries;
 
240
 
 
241
        /*
 
242
         * Since submounts look after themselves the parent never knows
 
243
         * it needs to close the ioctlfd for offset mounts so we have
 
244
         * to do it here. If the cache entry isn't found then there aren't
 
245
         * any offset mounts.
 
246
         */
 
247
        if (ap->submount)
 
248
                lookup_source_close_ioctlfd(ap->parent, ap->path);
 
249
 
 
250
        /* If we are trying to shutdown make sure we can umount */
 
251
        rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret);
 
252
        if (rv == -1) {
 
253
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
254
                logerr("ioctl failed: %s", estr);
 
255
                return 1;
 
256
        } else if (!ret) {
 
257
                error(ap->logopt, "ask umount returned busy %s", ap->path);
 
258
                return 1;
 
259
        }
 
260
 
 
261
        ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
 
262
        close(ap->ioctlfd);
 
263
        ap->ioctlfd = -1;
 
264
        close(ap->state_pipe[0]);
 
265
        close(ap->state_pipe[1]);
 
266
        ap->state_pipe[0] = -1;
 
267
        ap->state_pipe[1] = -1;
 
268
 
 
269
        if (ap->pipefd >= 0)
 
270
                close(ap->pipefd);
 
271
 
 
272
        if (ap->kpipefd >= 0)
 
273
                close(ap->kpipefd);
 
274
 
 
275
        sched_yield();
 
276
 
 
277
        retries = UMOUNT_RETRIES;
 
278
        while ((rv = umount(ap->path)) == -1 && retries--) {
 
279
                struct timespec tm = {0, 100000000};
 
280
                if (errno != EBUSY)
 
281
                        break;
 
282
                nanosleep(&tm, NULL);
 
283
        }
 
284
 
 
285
        if (rv == -1) {
 
286
                switch (errno) {
 
287
                case ENOENT:
 
288
                case EINVAL:
 
289
                        error(ap->logopt,
 
290
                              "mount point %s does not exist", ap->path);
 
291
                        return 0;
 
292
                        break;
 
293
                case EBUSY:
 
294
                        error(ap->logopt,
 
295
                              "mount point %s is in use", ap->path);
 
296
                        if (ap->state == ST_SHUTDOWN_FORCE)
 
297
                                goto force_umount;
 
298
                        else
 
299
                                return 0;
 
300
                        break;
 
301
                case ENOTDIR:
 
302
                        error(ap->logopt, "mount point is not a directory");
 
303
                        return 0;
 
304
                        break;
 
305
                }
 
306
                return 1;
 
307
        }
 
308
 
 
309
force_umount:
 
310
        if (rv != 0) {
 
311
                warn(ap->logopt,
 
312
                     "forcing umount of indirect mount %s", ap->path);
 
313
                rv = umount2(ap->path, MNT_DETACH);
 
314
        } else {
 
315
                info(ap->logopt, "umounted indirect mount %s", ap->path);
 
316
                if (ap->submount)
 
317
                        rm_unwanted(ap->logopt, ap->path, 1, ap->dev);
 
318
        }
 
319
 
 
320
        return rv;
 
321
}
 
322
 
 
323
static int expire_indirect(struct autofs_point *ap, int ioctlfd, const char *path, unsigned int when)
 
324
{
 
325
        char buf[MAX_ERR_BUF];
 
326
        int ret, retries;
 
327
        struct stat st;
 
328
 
 
329
        if (fstat(ioctlfd, &st) == -1) {
 
330
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
331
                error(ap->logopt, "fstat failed: %s", estr);
 
332
                return 0;
 
333
        }
 
334
 
 
335
        retries = (count_mounts(ap->logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
 
336
 
 
337
        while (retries--) {
 
338
                struct timespec tm = {0, 100000000};
 
339
 
 
340
                /* Ggenerate expire message for the mount. */
 
341
                ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
 
342
                if (ret == -1) {
 
343
                        /* Mount has gone away */
 
344
                        if (errno == EBADF || errno == EINVAL)
 
345
                                return 1;
 
346
 
 
347
                        /* Other than need to wait for the kernel ? */
 
348
                        if (errno != EAGAIN)
 
349
                                return 0;
 
350
                }
 
351
 
 
352
                nanosleep(&tm, NULL);
 
353
        }
 
354
 
 
355
        if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
 
356
                if (!ret)
 
357
                        return 0;
 
358
        }
 
359
 
 
360
        return 1;
 
361
}
 
362
 
 
363
static void mnts_cleanup(void *arg)
 
364
{
 
365
        struct mnt_list *mnts = (struct mnt_list *) arg;
 
366
        free_mnt_list(mnts);
 
367
        return;
 
368
}
 
369
 
 
370
void *expire_proc_indirect(void *arg)
 
371
{
 
372
        struct autofs_point *ap;
 
373
        struct mapent *me = NULL;
 
374
        struct mnt_list *mnts = NULL, *next;
 
375
        struct expire_args *ea;
 
376
        struct expire_args ec;
 
377
        unsigned int now;
 
378
        int offsets, submnts, count;
 
379
        int ioctlfd, cur_state;
 
380
        int status, ret, left;
 
381
 
 
382
        ea = (struct expire_args *) arg;
 
383
 
 
384
        status = pthread_mutex_lock(&ea->mutex);
 
385
        if (status)
 
386
                fatal(status);
 
387
 
 
388
        ap = ec.ap = ea->ap;
 
389
        now = ea->when;
 
390
        ec.status = -1;
 
391
 
 
392
        ea->signaled = 1;
 
393
        status = pthread_cond_signal(&ea->cond);
 
394
        if (status)
 
395
                fatal(status);
 
396
 
 
397
        status = pthread_mutex_unlock(&ea->mutex);
 
398
        if (status)
 
399
                fatal(status);
 
400
 
 
401
        pthread_cleanup_push(expire_cleanup, &ec);
 
402
 
 
403
        left = 0;
 
404
 
 
405
        /* Get a list of real mounts and expire them if possible */
 
406
        mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0);
 
407
        pthread_cleanup_push(mnts_cleanup, mnts);
 
408
        for (next = mnts; next; next = next->next) {
 
409
                char *ind_key;
 
410
                int ret;
 
411
 
 
412
                if (!strcmp(next->fs_type, "autofs")) {
 
413
                        /*
 
414
                         * If we have submounts check if this path lives below
 
415
                         * one of them and pass on the state change.
 
416
                         */
 
417
                        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
 
418
                        if (strstr(next->opts, "indirect"))
 
419
                                master_notify_submount(ap, next->path, ap->state);
 
420
                        pthread_setcancelstate(cur_state, NULL);
 
421
 
 
422
                        continue;
 
423
                }
 
424
 
 
425
                if (ap->state == ST_EXPIRE || ap->state == ST_PRUNE)
 
426
                        pthread_testcancel();
 
427
 
 
428
                /*
 
429
                 * If the mount corresponds to an offset trigger then
 
430
                 * the key is the path, otherwise it's the last component.
 
431
                 */
 
432
                ind_key = strrchr(next->path, '/');
 
433
                if (ind_key)
 
434
                        ind_key++;
 
435
 
 
436
                /*
 
437
                 * If me->key starts with a '/' and it's not an autofs
 
438
                 * filesystem it's a nested mount and we need to use
 
439
                 * the ioctlfd of the mount to send the expire.
 
440
                 * Otherwise it's a top level indirect mount (possibly
 
441
                 * with offsets in it) and we use the usual ioctlfd.
 
442
                 */
 
443
                me = lookup_source_mapent(ap, next->path, LKP_DISTINCT);
 
444
                if (!me && ind_key)
 
445
                        me = lookup_source_mapent(ap, ind_key, LKP_NORMAL);
 
446
                if (!me)
 
447
                        continue;
 
448
 
 
449
                if (*me->key == '/') {
 
450
                        ioctlfd = me->ioctlfd;
 
451
                } else {
 
452
                        ioctlfd = ap->ioctlfd;
 
453
                }
 
454
                cache_unlock(me->mc);
 
455
 
 
456
                debug(ap->logopt, "expire %s", next->path);
 
457
 
 
458
                pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
 
459
                ret = expire_indirect(ap, ioctlfd, next->path, now);
 
460
                if (!ret)
 
461
                        left++;
 
462
                pthread_setcancelstate(cur_state, NULL);
 
463
        }
 
464
        pthread_cleanup_pop(1);
 
465
 
 
466
        /*
 
467
         * If there are no more real mounts left we could still
 
468
         * have some offset mounts with no '/' offset so we need to
 
469
         * umount them here.
 
470
         */
 
471
        if (mnts) {
 
472
                pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
 
473
                ret = expire_indirect(ap, ap->ioctlfd, ap->path, now);
 
474
                if (!ret)
 
475
                        left++;
 
476
                pthread_setcancelstate(cur_state, NULL);
 
477
        }
 
478
 
 
479
        count = offsets = submnts = 0;
 
480
        mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0);
 
481
        pthread_cleanup_push(mnts_cleanup, mnts);
 
482
        /* Are there any real mounts left */
 
483
        for (next = mnts; next; next = next->next) {
 
484
                if (strcmp(next->fs_type, "autofs"))
 
485
                        count++;
 
486
                else {
 
487
                        if (strstr(next->opts, "indirect"))
 
488
                                submnts++;
 
489
                        else
 
490
                                offsets++;
 
491
                }
 
492
        }
 
493
        pthread_cleanup_pop(1);
 
494
 
 
495
        if (submnts)
 
496
                debug(ap->logopt,
 
497
                      "%d submounts remaining in %s", submnts, ap->path);
 
498
 
 
499
        /* 
 
500
         * EXPIRE_MULTI is synchronous, so we can be sure (famous last
 
501
         * words) the umounts are done by the time we reach here
 
502
         */
 
503
        if (count)
 
504
                info(ap->logopt, "%d remaining in %s", count, ap->path);
 
505
 
 
506
        ec.status = left;
 
507
 
 
508
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
 
509
        pthread_cleanup_pop(1);
 
510
        pthread_setcancelstate(cur_state, NULL);
 
511
 
 
512
        return NULL;
 
513
}
 
514
 
 
515
static void pending_cond_destroy(void *arg)
 
516
{
 
517
        struct pending_args *mt;
 
518
        int status;
 
519
 
 
520
        mt = (struct pending_args *) arg;
 
521
        status = pthread_cond_destroy(&mt->cond);
 
522
        if (status)
 
523
                fatal(status);
 
524
}
 
525
 
 
526
static void expire_send_fail(void *arg)
 
527
{
 
528
        struct pending_args *mt = arg;
 
529
        send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
 
530
}
 
531
 
 
532
static void free_pending_args(void *arg)
 
533
{
 
534
        struct pending_args *mt = arg;
 
535
        free(mt);
 
536
}
 
537
 
 
538
static void expire_mutex_unlock(void *arg)
 
539
{
 
540
        int status = pthread_mutex_unlock(&ea_mutex);
 
541
        if (status)
 
542
                fatal(status);
 
543
}
 
544
 
 
545
static void *do_expire_indirect(void *arg)
 
546
{
 
547
        struct pending_args *mt;
 
548
        struct autofs_point *ap;
 
549
        int status, state;
 
550
 
 
551
        mt = (struct pending_args *) arg;
 
552
 
 
553
        status = pthread_mutex_lock(&ea_mutex);
 
554
        if (status)
 
555
                fatal(status);
 
556
 
 
557
        ap = mt->ap;
 
558
 
 
559
        mt->signaled = 1;
 
560
        status = pthread_cond_signal(&mt->cond);
 
561
        if (status)
 
562
                fatal(status);
 
563
 
 
564
        expire_mutex_unlock(NULL);
 
565
 
 
566
        pthread_cleanup_push(free_pending_args, mt);
 
567
        pthread_cleanup_push(pending_cond_destroy, mt);
 
568
        pthread_cleanup_push(expire_send_fail, mt);
 
569
 
 
570
        status = do_expire(mt->ap, mt->name, mt->len);
 
571
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
572
        if (status)
 
573
                send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
 
574
        else
 
575
                send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
 
576
        pthread_setcancelstate(state, NULL);
 
577
 
 
578
        pthread_cleanup_pop(0);
 
579
        pthread_cleanup_pop(1);
 
580
        pthread_cleanup_pop(1);
 
581
 
 
582
        return NULL;
 
583
}
 
584
 
 
585
int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_indirect_t *pkt)
 
586
{
 
587
        struct pending_args *mt;
 
588
        char buf[MAX_ERR_BUF];
 
589
        pthread_t thid;
 
590
        int status, state;
 
591
 
 
592
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
593
 
 
594
        debug(ap->logopt, "token %ld, name %s",
 
595
                  (unsigned long) pkt->wait_queue_token, pkt->name);
 
596
 
 
597
        mt = malloc(sizeof(struct pending_args));
 
598
        if (!mt) {
 
599
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
600
                logerr("malloc: %s", estr);
 
601
                send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
 
602
                pthread_setcancelstate(state, NULL);
 
603
                return 1;
 
604
        }
 
605
 
 
606
        status = pthread_cond_init(&mt->cond, NULL);
 
607
        if (status)
 
608
                fatal(status);
 
609
 
 
610
        status = pthread_mutex_lock(&ea_mutex);
 
611
        if (status)
 
612
                fatal(status);
 
613
 
 
614
        mt->ap = ap;
 
615
        strncpy(mt->name, pkt->name, pkt->len);
 
616
        mt->name[pkt->len] = '\0';
 
617
        mt->len = pkt->len;
 
618
        mt->wait_queue_token = pkt->wait_queue_token;
 
619
 
 
620
        status = pthread_create(&thid, &thread_attr, do_expire_indirect, mt);
 
621
        if (status) {
 
622
                error(ap->logopt, "expire thread create failed");
 
623
                send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
 
624
                expire_mutex_unlock(NULL);
 
625
                pending_cond_destroy(mt);
 
626
                free_pending_args(mt);
 
627
                pthread_setcancelstate(state, NULL);
 
628
                return 1;
 
629
        }
 
630
 
 
631
        pthread_cleanup_push(expire_mutex_unlock, NULL);
 
632
        pthread_setcancelstate(state, NULL);
 
633
 
 
634
        mt->signaled = 0;
 
635
        while (!mt->signaled) {
 
636
                status = pthread_cond_wait(&mt->cond, &ea_mutex);
 
637
                if (status)
 
638
                        fatal(status);
 
639
        }
 
640
 
 
641
        pthread_cleanup_pop(1);
 
642
 
 
643
        return 0;
 
644
}
 
645
 
 
646
static void mount_send_fail(void *arg)
 
647
{
 
648
        struct pending_args *mt = arg;
 
649
        send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
 
650
}
 
651
 
 
652
static void mount_mutex_unlock(void *arg)
 
653
{
 
654
        int status = pthread_mutex_unlock(&ma_mutex);
 
655
        if (status)
 
656
                fatal(status);
 
657
}
 
658
 
 
659
static void *do_mount_indirect(void *arg)
 
660
{
 
661
        struct pending_args *mt;
 
662
        struct autofs_point *ap;
 
663
        char buf[PATH_MAX + 1];
 
664
        struct stat st;
 
665
        struct passwd pw;
 
666
        struct passwd *ppw = &pw;
 
667
        struct passwd **pppw = &ppw;
 
668
        struct group gr;
 
669
        struct group *pgr;
 
670
        struct group **ppgr;
 
671
        char *pw_tmp, *gr_tmp;
 
672
        struct thread_stdenv_vars *tsv;
 
673
        int len, tmplen, grplen, status, state;
 
674
 
 
675
        mt = (struct pending_args *) arg;
 
676
 
 
677
        status = pthread_mutex_lock(&ma_mutex);
 
678
        if (status)
 
679
                fatal(status);
 
680
 
 
681
        ap = mt->ap;
 
682
        mt->status = 0;
 
683
 
 
684
        mt->signaled = 1;
 
685
        status = pthread_cond_signal(&mt->cond);
 
686
        if (status)
 
687
                fatal(status);
 
688
 
 
689
        mount_mutex_unlock(NULL);
 
690
 
 
691
        pthread_cleanup_push(free_pending_args, mt);
 
692
        pthread_cleanup_push(pending_cond_destroy, mt);
 
693
        pthread_cleanup_push(mount_send_fail, mt);
 
694
 
 
695
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
696
 
 
697
        len = ncat_path(buf, sizeof(buf), ap->path, mt->name, mt->len);
 
698
        if (!len) {
 
699
                crit(ap->logopt, "path to be mounted is to long");
 
700
                pthread_setcancelstate(state, NULL);
 
701
                pthread_exit(NULL);
 
702
        }
 
703
 
 
704
        status = lstat(buf, &st);
 
705
        if (status != -1 && !(S_ISDIR(st.st_mode) && st.st_dev == mt->dev)) {
 
706
                error(ap->logopt,
 
707
                      "indirect trigger not valid or already mounted %s", buf);
 
708
                pthread_setcancelstate(state, NULL);
 
709
                pthread_exit(NULL);
 
710
        }
 
711
 
 
712
        pthread_setcancelstate(state, NULL);
 
713
 
 
714
        info(ap->logopt, "attempting to mount entry %s", buf);
 
715
 
 
716
        /*
 
717
         * Setup thread specific data values for macro
 
718
         * substution in map entries during the mount.
 
719
         * Best effort only as it must go ahead.
 
720
         */
 
721
 
 
722
        tsv = malloc(sizeof(struct thread_stdenv_vars));
 
723
        if (!tsv) 
 
724
                goto cont;
 
725
 
 
726
        tsv->uid = mt->uid;
 
727
        tsv->gid = mt->gid;
 
728
 
 
729
        /* Try to get passwd info */
 
730
 
 
731
        tmplen = sysconf(_SC_GETPW_R_SIZE_MAX);
 
732
        if (tmplen < 0) {
 
733
                error(ap->logopt, "failed to get buffer size for getpwuid_r");
 
734
                free(tsv);
 
735
                goto cont;
 
736
        }
 
737
 
 
738
        pw_tmp = malloc(tmplen + 1);
 
739
        if (!pw_tmp) {
 
740
                error(ap->logopt, "failed to malloc buffer for getpwuid_r");
 
741
                free(tsv);
 
742
                goto cont;
 
743
        }
 
744
 
 
745
        status = getpwuid_r(mt->uid, ppw, pw_tmp, tmplen, pppw);
 
746
        if (status || !ppw) {
 
747
                error(ap->logopt, "failed to get passwd info from getpwuid_r");
 
748
                free(tsv);
 
749
                free(pw_tmp);
 
750
                goto cont;
 
751
        }
 
752
 
 
753
        tsv->user = strdup(pw.pw_name);
 
754
        if (!tsv->user) {
 
755
                error(ap->logopt, "failed to malloc buffer for user");
 
756
                free(tsv);
 
757
                free(pw_tmp);
 
758
                goto cont;
 
759
        }
 
760
 
 
761
        tsv->home = strdup(pw.pw_dir);
 
762
        if (!tsv->user) {
 
763
                error(ap->logopt, "failed to malloc buffer for home");
 
764
                free(pw_tmp);
 
765
                free(tsv->user);
 
766
                free(tsv);
 
767
                goto cont;
 
768
        }
 
769
 
 
770
        free(pw_tmp);
 
771
 
 
772
        /* Try to get group info */
 
773
 
 
774
        grplen = sysconf(_SC_GETGR_R_SIZE_MAX);
 
775
        if (tmplen < 0) {
 
776
                error(ap->logopt, "failed to get buffer size for getgrgid_r");
 
777
                free(tsv->user);
 
778
                free(tsv->home);
 
779
                free(tsv);
 
780
                goto cont;
 
781
        }
 
782
 
 
783
        gr_tmp = NULL;
 
784
        tmplen = grplen;
 
785
        while (1) {
 
786
                char *tmp = realloc(gr_tmp, tmplen + 1);
 
787
                if (!tmp) {
 
788
                        error(ap->logopt, "failed to malloc buffer for getgrgid_r");
 
789
                        if (gr_tmp)
 
790
                                free(gr_tmp);
 
791
                        free(tsv->user);
 
792
                        free(tsv->home);
 
793
                        free(tsv);
 
794
                        goto cont;
 
795
                }
 
796
                gr_tmp = tmp;
 
797
                pgr = &gr;
 
798
                ppgr = &pgr;
 
799
                status = getgrgid_r(mt->gid, pgr, gr_tmp, tmplen, ppgr);
 
800
                if (status != ERANGE)
 
801
                        break;
 
802
                tmplen += grplen;
 
803
        }
 
804
 
 
805
        if (status || !pgr) {
 
806
                error(ap->logopt, "failed to get group info from getgrgid_r");
 
807
                free(tsv->user);
 
808
                free(tsv->home);
 
809
                free(tsv);
 
810
                free(gr_tmp);
 
811
                goto cont;
 
812
        }
 
813
 
 
814
        tsv->group = strdup(gr.gr_name);
 
815
        if (!tsv->group) {
 
816
                error(ap->logopt, "failed to malloc buffer for group");
 
817
                free(tsv->user);
 
818
                free(tsv->home);
 
819
                free(tsv);
 
820
                free(gr_tmp);
 
821
                goto cont;
 
822
        }
 
823
 
 
824
        free(gr_tmp);
 
825
 
 
826
        status = pthread_setspecific(key_thread_stdenv_vars, tsv);
 
827
        if (status) {
 
828
                error(ap->logopt, "failed to set stdenv thread var");
 
829
                free(tsv->group);
 
830
                free(tsv->user);
 
831
                free(tsv->home);
 
832
                free(tsv);
 
833
        }
 
834
cont:
 
835
        status = lookup_nss_mount(ap, NULL, mt->name, mt->len);
 
836
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
837
        if (status) {
 
838
                send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
 
839
                info(ap->logopt, "mounted %s", buf);
 
840
        } else {
 
841
                send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
 
842
                info(ap->logopt, "failed to mount %s", buf);
 
843
        }
 
844
        pthread_setcancelstate(state, NULL);
 
845
 
 
846
        pthread_cleanup_pop(0);
 
847
        pthread_cleanup_pop(1);
 
848
        pthread_cleanup_pop(1);
 
849
 
 
850
        return NULL;
 
851
}
 
852
 
 
853
int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missing_indirect_t *pkt)
 
854
{
 
855
        pthread_t thid;
 
856
        char buf[MAX_ERR_BUF];
 
857
        struct pending_args *mt;
 
858
        int status, state;
 
859
 
 
860
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
861
 
 
862
        debug(ap->logopt, "token %ld, name %s, request pid %u",
 
863
                (unsigned long) pkt->wait_queue_token, pkt->name, pkt->pid);
 
864
 
 
865
        /* Ignore packet if we're trying to shut down */
 
866
        if (ap->shutdown ||
 
867
            ap->state == ST_SHUTDOWN_FORCE ||
 
868
            ap->state == ST_SHUTDOWN) {
 
869
                send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
 
870
                pthread_setcancelstate(state, NULL);
 
871
                return 0;
 
872
        }
 
873
 
 
874
        mt = malloc(sizeof(struct pending_args));
 
875
        if (!mt) {
 
876
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 
877
                logerr("malloc: %s", estr);
 
878
                send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
 
879
                pthread_setcancelstate(state, NULL);
 
880
                return 1;
 
881
        }
 
882
        memset(mt, 0, sizeof(struct pending_args));
 
883
 
 
884
        status = pthread_cond_init(&mt->cond, NULL);
 
885
        if (status)
 
886
                fatal(status);
 
887
 
 
888
        status = pthread_mutex_lock(&ma_mutex);
 
889
        if (status)
 
890
                fatal(status);
 
891
 
 
892
        mt->ap = ap;
 
893
        strncpy(mt->name, pkt->name, pkt->len);
 
894
        mt->name[pkt->len] = '\0';
 
895
        mt->len = pkt->len;
 
896
        mt->dev = pkt->dev;
 
897
        mt->uid = pkt->uid;
 
898
        mt->gid = pkt->gid;
 
899
        mt->wait_queue_token = pkt->wait_queue_token;
 
900
 
 
901
        status = pthread_create(&thid, &thread_attr, do_mount_indirect, mt);
 
902
        if (status) {
 
903
                error(ap->logopt, "expire thread create failed");
 
904
                send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
 
905
                mount_mutex_unlock(NULL);
 
906
                pending_cond_destroy(mt);
 
907
                free_pending_args(mt);
 
908
                pthread_setcancelstate(state, NULL);
 
909
                return 1;
 
910
        }
 
911
 
 
912
        pthread_cleanup_push(mount_mutex_unlock, NULL);
 
913
        pthread_setcancelstate(state, NULL);
 
914
 
 
915
        mt->signaled = 0;
 
916
        while (!mt->signaled) {
 
917
                status = pthread_cond_wait(&mt->cond, &ma_mutex);
 
918
                if (status)
 
919
                        fatal(status);
 
920
        }
 
921
 
 
922
        pthread_cleanup_pop(1);
 
923
 
 
924
        return 0;
 
925
}
 
926