1164829Srodrigc/*-
21558Srgrimes * Copyright (c) 1992, 1993, 1994
3164829Srodrigc *	The Regents of the University of California.
4164829Srodrigc * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
5164829Srodrigc * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org>
6164829Srodrigc * All rights reserved.
71558Srgrimes *
81558Srgrimes * This code is derived from software donated to Berkeley by
91558Srgrimes * Jan-Simon Pendry.
101558Srgrimes *
111558Srgrimes * Redistribution and use in source and binary forms, with or without
121558Srgrimes * modification, are permitted provided that the following conditions
131558Srgrimes * are met:
141558Srgrimes * 1. Redistributions of source code must retain the above copyright
151558Srgrimes *    notice, this list of conditions and the following disclaimer.
161558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171558Srgrimes *    notice, this list of conditions and the following disclaimer in the
181558Srgrimes *    documentation and/or other materials provided with the distribution.
191558Srgrimes * 4. Neither the name of the University nor the names of its contributors
201558Srgrimes *    may be used to endorse or promote products derived from this software
211558Srgrimes *    without specific prior written permission.
221558Srgrimes *
231558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
241558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
251558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
261558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
271558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
281558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
291558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
301558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
311558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
321558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
331558Srgrimes * SUCH DAMAGE.
341558Srgrimes */
351558Srgrimes
361558Srgrimes#ifndef lint
3728629Sstevestatic const char copyright[] =
381558Srgrimes"@(#) Copyright (c) 1992, 1993, 1994\n\
391558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
401558Srgrimes#endif /* not lint */
411558Srgrimes
421558Srgrimes#ifndef lint
4328629Ssteve#if 0
441558Srgrimesstatic char sccsid[] = "@(#)mount_union.c	8.5 (Berkeley) 3/27/94";
4528629Ssteve#else
4628629Sstevestatic const char rcsid[] =
4750476Speter  "$FreeBSD$";
4828629Ssteve#endif
491558Srgrimes#endif /* not lint */
501558Srgrimes
511558Srgrimes#include <sys/param.h>
521558Srgrimes#include <sys/mount.h>
53101829Smux#include <sys/uio.h>
54164829Srodrigc#include <sys/errno.h>
551558Srgrimes
561558Srgrimes#include <err.h>
571558Srgrimes#include <stdio.h>
581558Srgrimes#include <stdlib.h>
591558Srgrimes#include <string.h>
6015770Swollman#include <sysexits.h>
611558Srgrimes#include <unistd.h>
62164829Srodrigc#include <grp.h>
63164829Srodrigc#include <pwd.h>
641558Srgrimes
651558Srgrimes#include "mntopts.h"
661558Srgrimes
67164829Srodrigcstatic int
68164829Srodrigcsubdir(const char *p, const char *dir)
69164829Srodrigc{
70164829Srodrigc	int		l;
711558Srgrimes
72164829Srodrigc	l = strlen(dir);
73164829Srodrigc	if (l <= 1)
74164829Srodrigc		return (1);
751558Srgrimes
76164829Srodrigc	if ((strncmp(p, dir, l) == 0) && (p[l] == '/' || p[l] == '\0'))
77164829Srodrigc		return (1);
78164829Srodrigc
79164829Srodrigc	return (0);
80164829Srodrigc}
81164829Srodrigc
82164829Srodrigcstatic void
83164829Srodrigcusage(void)
841558Srgrimes{
85164829Srodrigc	(void)fprintf(stderr,
86164829Srodrigc	    "usage: mount_unionfs [-o options] directory uniondir\n");
87164829Srodrigc	exit(EX_USAGE);
88164829Srodrigc}
891558Srgrimes
90164829Srodrigcstatic void
91164829Srodrigcparse_gid(const char *s, char *buf, size_t bufsize)
92164829Srodrigc{
93164829Srodrigc	struct group *gr;
94164829Srodrigc	char *inval;
95164829Srodrigc
96164829Srodrigc	if ((gr = getgrnam(s)) != NULL)
97164829Srodrigc		snprintf(buf, bufsize, "%d", gr->gr_gid);
98164829Srodrigc	else {
99164829Srodrigc		strtol(s, &inval, 10);
100164829Srodrigc		if (*inval != 0) {
101164829Srodrigc                       errx(EX_NOUSER, "unknown group id: %s", s);
102164829Srodrigc                       usage();
103164829Srodrigc		} else {
104164829Srodrigc			strncpy(buf, s, bufsize);
105164829Srodrigc		}
106164829Srodrigc	}
107164829Srodrigc}
108164829Srodrigc
109164875Smaximstatic void
110164829Srodrigcparse_uid(const char *s, char *buf, size_t bufsize)
111164829Srodrigc{
112164829Srodrigc	struct passwd  *pw;
113164829Srodrigc	char *inval;
114164829Srodrigc
115164829Srodrigc	if ((pw = getpwnam(s)) != NULL)
116164829Srodrigc		snprintf(buf, bufsize, "%d", pw->pw_uid);
117164829Srodrigc	else {
118164829Srodrigc		strtol(s, &inval, 10);
119164829Srodrigc		if (*inval != 0) {
120164829Srodrigc                       errx(EX_NOUSER, "unknown user id: %s", s);
121164829Srodrigc                       usage();
122164829Srodrigc		} else {
123164829Srodrigc			strncpy(buf, s, bufsize);
124164829Srodrigc		}
125164829Srodrigc	}
126164829Srodrigc}
127164829Srodrigc
128164829Srodrigcint
129164829Srodrigcmain(int argc, char *argv[])
130164829Srodrigc{
131164829Srodrigc	struct iovec	*iov;
132164829Srodrigc	int ch, mntflags, iovlen;
133164829Srodrigc	char source [MAXPATHLEN], target[MAXPATHLEN], errmsg[255];
134164829Srodrigc	char uid_str[20], gid_str[20];
135166684Srodrigc	char fstype[] = "unionfs";
136164829Srodrigc	char *p, *val;
137164829Srodrigc
138164829Srodrigc	iov = NULL;
139164829Srodrigc	iovlen = 0;
1401558Srgrimes	mntflags = 0;
141164829Srodrigc	memset(errmsg, 0, sizeof(errmsg));
142164829Srodrigc
143164829Srodrigc	while ((ch = getopt(argc, argv, "bo:")) != -1) {
1441558Srgrimes		switch (ch) {
1451558Srgrimes		case 'b':
146164829Srodrigc			printf("\n  -b is deprecated.  Use \"-o below\" instead\n");
147164829Srodrigc			build_iovec(&iov, &iovlen, "below", NULL, 0);
1481558Srgrimes			break;
1491558Srgrimes		case 'o':
150164829Srodrigc                        p = strchr(optarg, '=');
151164829Srodrigc                        val = NULL;
152164829Srodrigc                        if (p != NULL) {
153164829Srodrigc                                *p = '\0';
154164829Srodrigc                                val = p + 1;
155165788Srodrigc				if (strcmp(optarg, "gid") == 0) {
156164829Srodrigc					parse_gid(val, gid_str, sizeof(gid_str));
157164829Srodrigc					val = gid_str;
158164829Srodrigc				}
159165788Srodrigc				else if (strcmp(optarg, "uid") == 0) {
160164829Srodrigc					parse_uid(val, uid_str, sizeof(uid_str));
161164829Srodrigc					val = uid_str;
162164829Srodrigc				}
163164829Srodrigc                        }
164164829Srodrigc                        build_iovec(&iov, &iovlen, optarg, val, (size_t)-1);
1651558Srgrimes			break;
1661558Srgrimes		case '?':
1671558Srgrimes		default:
1681558Srgrimes			usage();
1691558Srgrimes			/* NOTREACHED */
1701558Srgrimes		}
171164829Srodrigc	}
1721558Srgrimes	argc -= optind;
1731558Srgrimes	argv += optind;
1741558Srgrimes
1751558Srgrimes	if (argc != 2)
1761558Srgrimes		usage();
1771558Srgrimes
17852055Sphk	/* resolve both target and source with realpath(3) */
17952055Sphk	(void)checkpath(argv[0], target);
18052055Sphk	(void)checkpath(argv[1], source);
1811558Srgrimes
18225275Sdfr	if (subdir(target, source) || subdir(source, target))
18325275Sdfr		errx(EX_USAGE, "%s (%s) and %s (%s) are not distinct paths",
184164829Srodrigc		     argv[0], target, argv[1], source);
18525275Sdfr
186166684Srodrigc	build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
187164829Srodrigc	build_iovec(&iov, &iovlen, "fspath", source, (size_t)-1);
188164829Srodrigc	build_iovec(&iov, &iovlen, "from", target, (size_t)-1);
189164829Srodrigc	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
190164829Srodrigc
191164829Srodrigc	if (nmount(iov, iovlen, mntflags))
192164829Srodrigc		err(EX_OSERR, "%s: %s", source, errmsg);
1931558Srgrimes	exit(0);
1941558Srgrimes}
195