1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * where.c - get full pathname including host:
29 */
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33#include <netdb.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38#include <fcntl.h>
39#include <errno.h>
40#include <string.h>
41
42#include <sys/mntent.h>
43
44#include <sys/mnttab.h>
45#include <sys/param.h>
46#include <sys/stat.h>
47
48#include <sharefs/share.h>
49#include "sharetab.h"
50
51extern	FILE	*setmntent();
52
53FILE *setsharetab();
54void endsharetab();
55
56
57
58extern	int	Debug;
59
60/*
61 * where(pn, host, fsname, within)
62 *
63 * pn is the pathname we are looking for,
64 * host gets the name of the host owning the file system,
65 * fsname gets the file system name on the host,
66 * within gets whatever is left from the pathname
67 *
68 * Returns: 0 if ERROR, 1 if OK
69 */
70int
71where(pn, host, fsname, within)
72char *pn;
73char *host;
74char *fsname;
75char *within;
76{
77	struct stat sb;
78	char curdir[MAXPATHLEN];
79	char qualpn[MAXPATHLEN];
80	char *p;
81
82	if (Debug)
83	    printf("where: pn %s\n", pn);
84
85	if (stat(pn, &sb) < 0) {
86		char *errstr;
87
88		if ((errstr = strerror(errno)) == NULL)
89			errstr = "unknown error";
90
91		if (Debug)
92		    printf("where: stat failed");
93		strcpy(within, errstr);
94		return (0);
95	}
96	/*
97	 * first get the working directory,
98	 */
99	if (getcwd(curdir, MAXPATHLEN) == NULL) {
100		sprintf(within, "Unable to get working directory (%s)",
101			curdir);
102		return (0);
103	}
104	if (chdir(pn) == 0) {
105		getcwd(qualpn, MAXPATHLEN);
106		chdir(curdir);
107	} else {
108		if (p = strrchr(pn, '/')) {
109			*p = 0;
110			chdir(pn);
111			(void) getcwd(qualpn, MAXPATHLEN);
112			chdir(curdir);
113			strcat(qualpn, "/");
114			strcat(qualpn, p+1);
115		} else {
116			strcpy(qualpn, curdir);
117			strcat(qualpn, "/");
118			strcat(qualpn, pn);
119		}
120	}
121	return (findmount(qualpn, host, fsname, within));
122}
123
124/*
125 * findmount(qualpn, host, fsname, within)
126 *
127 * Searches the mount table to find the appropriate file system
128 * for a given absolute path name.
129 * host gets the name of the host owning the file system,
130 * fsname gets the file system name on the host,
131 * within gets whatever is left from the pathname
132 *
133 * Returns: 0 on failure, 1 on success.
134 */
135int
136findmount(qualpn, host, fsname, within)
137char *qualpn;
138char *host;
139char *fsname;
140char *within;
141{
142	FILE	*mfp;
143	char	bestname[MAXPATHLEN];
144	int	bestlen = 0,
145	bestnfs = 0;
146	struct	share *exp;
147	struct	mnttab		mp,
148	*mnt;
149	char	*endhost;	/* points past the colon in name */
150	int	i,
151	len;
152
153	if (Debug)
154		printf("findmount: qualpn %s\n", qualpn);
155
156	for (i = 0; i < 10; i++) {
157		mfp = setmntent("/etc/mnttab", "r");
158		if (mfp != NULL)
159			break;
160		sleep(1);
161	}
162
163	if (mfp == NULL) {
164		sprintf(within, "mount table problem");
165		return (0);
166	}
167
168	bestname[0] = '\0';
169	while ((getmntent(mfp, &mp)) == 0) {
170		if (strcmp(mp.mnt_fstype, "nfs") != 0)
171			/*
172			 * If it is not nfs filesystem type, skip the
173			 * entry
174			 */
175			continue;
176
177		len = preflen(qualpn, mp.mnt_mountp);
178
179		if (Debug)
180			printf("preflen: %d %s %s", len, qualpn, mp.mnt_mountp);
181
182		if (qualpn[len] != '/' && qualpn[len] != '\0' && len > 1)
183			/*
184			 * If the last matching character is neither / nor
185			 * the end of the pathname, not a real match
186			 * (except for matching root, len==1)
187			 */
188			continue;
189
190		if (len > bestlen) {
191			bestlen = len;
192			strncpy(bestname, mp.mnt_special, sizeof (bestname));
193		}
194		if (Debug)
195			printf(" %s\n", bestname);
196	}
197
198	endmntent(mfp);
199
200	endhost = strchr(bestname, ':');
201
202	/*
203	 * If the file system was of type NFS, then there should already
204	 * be a host name, otherwise, use ours.
205	 */
206	if (endhost) {
207		*endhost++ = 0;
208		strncpy(host, bestname, MAXHOSTNAMELEN);
209		strncpy(fsname, endhost, MAXPATHLEN);
210
211		/*
212		 * special case to keep the "/" when we match root
213		 */
214		if (bestlen == 1)
215			bestlen = 0;
216	} else {
217		gethostname(host, MAXHOSTNAMELEN);
218
219		/*
220		 *	If this is our file system, try for an even longer
221		 *	match from /etc/xtab.
222		 */
223		if (mfp = setsharetab()) {
224			while (getshare(mfp, &exp) > 0)
225				if (len = preflen(qualpn, exp->sh_path))
226					if (len > bestlen) {
227						bestlen = len;
228						strncpy(bestname, exp->sh_path,
229							sizeof (bestname));
230					}
231			endsharetab(mfp);
232		}
233		strncpy(fsname, qualpn, bestlen);
234		fsname[bestlen] = 0;
235	}
236	strncpy(within, qualpn + bestlen, MAXPATHLEN);
237
238	if (Debug)
239		printf("findmount: qualpn %s\nhost %s\nfsname %s\nwithin %s\n",
240			qualpn, host, fsname, within);
241	return (1);
242}
243
244/*
245 * Returns: length of second argument if it is a prefix of the
246 * first argument, otherwise zero.
247 */
248int
249preflen(str, pref)
250char	*str, *pref;
251{
252	int len;
253
254	len = strlen(pref);
255	if (strncmp(str, pref, len) == 0)
256		return (len);
257	return (0);
258}
259
260FILE
261*setsharetab()
262{
263	FILE	*f;
264
265	f = fopen(SHARETAB, "r");
266	if (f == NULL) {
267		return (NULL);
268	}
269
270	return (f);
271}
272
273
274void
275endsharetab(f)
276FILE	*f;
277{
278	(void) fclose(f);
279}
280