1 /*
2  * Copyright (C) 2002-2015 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2008-2009 David Robillard <d@drobilla.net>
4  * Copyright (C) 2013 John Emmas <john@creativepost.co.uk>
5  * Copyright (C) 2014-2015 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 #ifndef  COMPILER_MSVC
22 #include <cstdio>
23 #include <cstring>
24 #include <string>
25 #include <cstring>
26 #include <limits.h>
27 
28 #include "pbd/mountpoint.h"
29 
30 using std::string;
31 
32 #ifdef WAF_BUILD
33 #include "libpbd-config.h"
34 #endif
35 
36 #ifdef HAVE_GETMNTENT
37 #include <mntent.h>
38 
39 struct mntent_sorter {
operator ()mntent_sorter40     bool operator() (const mntent *a, const mntent *b) {
41 	    return strcmp (a->mnt_dir, b->mnt_dir);
42     }
43 };
44 
45 string
mountpoint(string path)46 mountpoint (string path)
47 {
48 	FILE *mntf;
49 	mntent *mnt;
50 	unsigned int maxmatch = 0;
51 	unsigned int matchlen;
52 	const char *cpath = path.c_str();
53 	char best[PATH_MAX+1];
54 
55 	if ((mntf = setmntent ("/etc/mtab", "r")) == 0) {
56 		return "";
57 	}
58 
59 	best[0] = '\0';
60 
61 	while ((mnt = getmntent (mntf))) {
62 		unsigned int n;
63 
64 		n = 0;
65 		matchlen = 0;
66 
67 		/* note: strcmp's semantics are not
68 		   strict enough to use for this.
69 		*/
70 
71 		while (cpath[n] && mnt->mnt_dir[n]) {
72 			if (cpath[n] != mnt->mnt_dir[n]) {
73 				break;
74 			}
75 			matchlen++;
76 			n++;
77 		}
78 
79 		if (cpath[matchlen] == '\0') {
80 
81 			endmntent (mntf);
82 			return mnt->mnt_dir;
83 
84 		} else {
85 
86 			if (matchlen > maxmatch) {
87 				snprintf (best, sizeof(best), "%s", mnt->mnt_dir);
88 				maxmatch = matchlen;
89 			}
90 		}
91 	}
92 
93 	endmntent (mntf);
94 
95 	return best;
96 }
97 
98 #elif defined(PLATFORM_WINDOWS)
99 #include <assert.h>
100 string
mountpoint(string path)101 mountpoint (string path)
102 {
103 	/* this function is currently only called from 'old_peak_path()'
104 	 * via find_broken_peakfile() - only relevant for loading pre
105 	 * libsndfile Ardour 2.0 sessions.
106 	 */
107 	assert(0);
108 	return ""; // TODO ... if needed
109 }
110 
111 #else // !HAVE_GETMNTENT
112 
113 #include <sys/param.h>
114 #include <sys/ucred.h>
115 #include <sys/mount.h>
116 
117 string
mountpoint(string path)118 mountpoint (string path)
119 {
120 #if defined(__NetBSD__)
121 	struct statvfs *mntbufp = 0;
122 #else
123 	struct statfs *mntbufp = 0;
124 #endif
125 	int count;
126 	unsigned int maxmatch = 0;
127 	unsigned int matchlen;
128 	const char *cpath = path.c_str();
129 	char best[PATH_MAX+1];
130 
131 	/* From the manpage, under "BUGS" : "The memory allocated by getmntinfo() cannot be free(3)'d by the
132 	   application."
133 
134 	   Thus: we do NOT try to free memory allocated by getmntinfo()
135 	*/
136 
137 	if ((count = getmntinfo(&mntbufp, MNT_NOWAIT)) == 0) {
138 		return "\0";
139 	}
140 
141 	best[0] = '\0';
142 
143 	for (int i = 0; i < count; ++i) {
144 		unsigned int n = 0;
145 		matchlen = 0;
146 
147 		/* note: strcmp's semantics are not
148 		   strict enough to use for this.
149 		*/
150 
151 		while (cpath[n] && mntbufp[i].f_mntonname[n]) {
152 			if (cpath[n] != mntbufp[i].f_mntonname[n]) {
153 				break;
154 			}
155 			matchlen++;
156 			n++;
157 		}
158 
159 		if (cpath[matchlen] == '\0') {
160 			snprintf(best, sizeof(best), "%s", mntbufp[i].f_mntonname);
161 			return best;
162 
163 		} else {
164 
165 			if (matchlen > maxmatch) {
166 				snprintf (best, sizeof(best), "%s", mntbufp[i].f_mntonname);
167 				maxmatch = matchlen;
168 			}
169 		}
170 	}
171 
172 	return best;
173 }
174 #endif // HAVE_GETMNTENT
175 
176 #ifdef TEST_MOUNTPOINT
177 
main(int argc,char * argv[])178 main (int argc, char *argv[])
179 {
180 	printf ("mp of %s = %s\n", argv[1], mountpoint (argv[1]).c_str());
181 	exit (0);
182 }
183 
184 #endif // TEST_MOUNTPOINT
185 
186 #else  // COMPILER_MSVC
187 	const char* pbd_mountpoint = "pbd/msvc/mountpoint.cc takes precedence over this file";
188 #endif // COMPILER_MSVC
189