]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxcmd/paths.c
Update copyright/license notices to match SGI legal prefered boilerplate.
[thirdparty/xfsprogs-dev.git] / libxcmd / paths.c
CommitLineData
3d93ccb7 1/*
da23017d
NS
2 * Copyright (c) 2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
3d93ccb7 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
3d93ccb7
NS
7 * published by the Free Software Foundation.
8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
3d93ccb7 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3d93ccb7
NS
17 */
18
19#include <paths.h>
20#include <errno.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <xfs/path.h>
28#include <xfs/input.h>
29#include <xfs/project.h>
30
3d93ccb7
NS
31int fs_count;
32struct fs_path *fs_table;
33struct fs_path *fs_path;
8fc372bc 34
3d93ccb7 35char *mtab_file;
8fc372bc 36#define PROC_MOUNTS "/proc/self/mounts"
3d93ccb7
NS
37
38struct fs_path *
39fs_table_lookup(
40 const char *dir,
41 uint flags)
42{
43 struct stat64 sbuf;
44 uint i;
45
46 if (stat64(dir, &sbuf) < 0)
47 return NULL;
48 for (i = 0; i < fs_count; i++) {
49 if ((flags & fs_table[i].fs_flags) == 0)
50 continue;
51 if (sbuf.st_dev == fs_table[i].fs_datadev)
52 return &fs_table[i];
53 }
54 return NULL;
55}
56
57static int
58fs_table_insert(
59 char *dir,
60 uint prid,
61 uint flags,
62 char *fsname,
63 char *fslog,
64 char *fsrt)
65{
66 struct stat64 sbuf;
67 dev_t datadev, logdev, rtdev;
68
69 if (!dir || !fsname)
70 return EINVAL;
71
72 datadev = logdev = rtdev = 0;
73 if (stat64(dir, &sbuf) < 0)
74 return errno;
75 datadev = sbuf.st_dev;
76 if (fslog) {
77 if (stat64(fslog, &sbuf) < 0)
78 return errno;
79 logdev = sbuf.st_dev;
80 }
81 if (fsrt) {
82 if (stat64(fsrt, &sbuf) < 0)
83 return errno;
84 rtdev = sbuf.st_dev;
85 }
86
87 fs_table = realloc(fs_table, sizeof(fs_path_t) * (fs_count + 1));
88 if (!fs_table)
89 goto error;
90
91 fs_path = &fs_table[fs_count];
92 fs_path->fs_dir = dir;
93 fs_path->fs_prid = prid;
94 fs_path->fs_flags = flags;
95 fs_path->fs_name = fsname;
96 fs_path->fs_log = fslog;
97 fs_path->fs_rt = fsrt;
98 fs_path->fs_datadev = datadev;
99 fs_path->fs_logdev = logdev;
100 fs_path->fs_rtdev = rtdev;
101 fs_count++;
102 return 0;
103
104 error:
105 if (dir) free(dir);
106 if (fsrt) free(fsrt);
107 if (fslog) free(fslog);
108 if (fsname) free(fsname);
109 return errno;
110}
111
112void
113fs_table_destroy(void)
114{
115 while (--fs_count >= 0) {
116 free(fs_table[fs_count].fs_name);
117 if (fs_table[fs_count].fs_log)
118 free(fs_table[fs_count].fs_log);
119 if (fs_table[fs_count].fs_rt)
120 free(fs_table[fs_count].fs_rt);
121 free(fs_table[fs_count].fs_dir);
122 }
123 if (fs_table)
124 free(fs_table);
125 fs_table = NULL;
126 fs_count = 0;
127}
128
129
cfe6e3f0 130#if defined(HAVE_GETMNTENT)
3d93ccb7
NS
131#include <mntent.h>
132
133static void
134fs_extract_mount_options(
135 struct mntent *mnt,
136 char **logp,
137 char **rtp)
138{
139 char *fslog, *fsrt, *fslogend, *fsrtend;
140
141 fslog = fsrt = fslogend = fsrtend = NULL;
142
143 /* Extract log device and realtime device from mount options */
0c222c69 144 if ((fslog = hasmntopt(mnt, "logdev=")))
3d93ccb7 145 fslog += 7;
0c222c69 146 if ((fsrt = hasmntopt(mnt, "rtdev=")))
3d93ccb7 147 fsrt += 6;
3d93ccb7
NS
148
149 /* Do this only after we've finished processing mount options */
150 if (fslog) {
0c222c69 151 fslogend = strtok(fslog, " ,");
3d93ccb7
NS
152 fslog = strdup(fslog);
153 }
154 if (fsrt) {
0c222c69 155 fsrtend = strtok(fsrt, " ,");
3d93ccb7
NS
156 fsrt = strdup(fsrt);
157 }
158
159 *logp = fslog;
160 *rtp = fsrt;
161}
162
163static int
164fs_table_initialise_mounts(
165 char *path)
166{
167 struct mntent *mnt;
168 FILE *mtp;
169 char *dir = NULL, *fsname = NULL, *fslog, *fsrt;
170 int error = 0, found = 0;
171
8fc372bc
NS
172 if (!mtab_file) {
173 mtab_file = PROC_MOUNTS;
174 if (access(mtab_file, R_OK) != 0)
175 mtab_file = MOUNTED;
176 }
3d93ccb7
NS
177
178 if ((mtp = setmntent(mtab_file, "r")) == NULL)
179 return ENOENT;
180
181 while ((mnt = getmntent(mtp)) != NULL) {
182 if (strcmp(mnt->mnt_type, "xfs") != 0)
183 continue;
184 if (path &&
185 ((strcmp(path, mnt->mnt_dir) != 0) &&
186 (strcmp(path, mnt->mnt_fsname) != 0)))
187 continue;
188 found = 1;
189 dir = strdup(mnt->mnt_dir);
190 fsname = strdup(mnt->mnt_fsname);
191 if (!dir || !fsname) {
192 error = ENOMEM;
193 break;
194 }
195 fs_extract_mount_options(mnt, &fslog, &fsrt);
196 if ((error = fs_table_insert(dir, 0, FS_MOUNT_POINT,
197 fsname, fslog, fsrt)))
198 break;
199 }
200 endmntent(mtp);
201 if (!error && path && !found)
202 error = ENXIO;
203 if (error) {
204 free(dir);
205 free(fsname);
206 }
207 return error;
208}
209
210#elif defined(HAVE_GETMNTINFO)
211#include <sys/mount.h>
212
213static int
214fs_table_initialise_mounts(
215 char *path)
216{
217 struct statfs *stats;
218 char *dir = NULL, *fsname = NULL, *fslog = NULL, *fsrt = NULL;
219 int i, count, found = 0, error = 0;
220
221 if ((count = getmntinfo(&stats, 0)) < 0) {
222 perror("getmntinfo");
223 return 0;
224 }
225
226 for (i = 0; i < count; i++) {
227 if (strcmp(stats[i].f_fstypename, "xfs") != 0)
228 continue;
229 if (path &&
230 ((strcmp(path, stats[i].f_mntonname) != 0) &&
231 (strcmp(path, stats[i].f_mntfromname) != 0)))
232 continue;
233 found = 1;
234 dir = strdup(stats[i].f_mntonname);
235 fsname = strdup(stats[i].f_mntfromname);
236 if (!dir || !fsname) {
237 error = ENOMEM;
238 break;
239 }
240 /* TODO: external log and realtime device? */
241 if ((error = fs_table_insert(dir, 0, FS_MOUNT_POINT,
cfe6e3f0 242 fsname, fslog, fsrt)))
3d93ccb7
NS
243 break;
244 }
245 if (!error && path && !found)
246 error = ENXIO;
247 if (error) {
248 free(dir);
249 free(fsname);
250 }
251 return error;
252}
253
254#else
255# error "How do I extract info about mounted filesystems on this platform?"
256#endif
257
258/*
259 * Given a directory, match it up to a filesystem mount point.
260 */
261static struct fs_path *
262fs_mount_point_from_path(
263 const char *dir)
264{
265 fs_cursor_t cursor;
266 fs_path_t *fs;
267 struct stat64 s;
268
269 if (stat64(dir, &s) < 0) {
270 perror(dir);
271 return NULL;
272 }
273
274 fs_cursor_initialise(NULL, FS_MOUNT_POINT, &cursor);
275 while ((fs = fs_cursor_next_entry(&cursor))) {
276 if (fs->fs_datadev == s.st_dev)
277 break;
278 }
279 return fs;
280}
281
282static int
283fs_table_initialise_projects(
284 char *project)
285{
286 fs_project_path_t *path;
287 fs_path_t *fs;
288 prid_t prid = 0;
289 char *dir = NULL, *fsname = NULL;
290 int error = 0, found = 0;
291
292 if (project)
293 prid = prid_from_string(project);
294
295 setprpathent();
296 while ((path = getprpathent()) != NULL) {
297 if (project && prid != path->pp_prid)
298 continue;
299 if ((fs = fs_mount_point_from_path(path->pp_pathname)) == NULL)
300 continue;
301 found = 1;
302 dir = strdup(path->pp_pathname);
303 fsname = strdup(fs->fs_name);
304 if (!dir || !fsname) {
305 error = ENOMEM;
306 break;
307 }
308 if ((error = fs_table_insert(dir, path->pp_prid,
309 FS_PROJECT_PATH, fsname, NULL, NULL)))
310 break;
311 }
312 endprpathent();
313
314 if (!error && project && !found)
315 error = ENOENT;
316 if (error) {
317 free(dir);
318 free(fsname);
319 }
320 return error;
321}
322
323void
324fs_table_initialise(void)
325{
326 int error;
327
328 error = fs_table_initialise_mounts(NULL);
329 if (!error)
330 error = fs_table_initialise_projects(NULL);
331 if (error) {
332 fs_table_destroy();
333 fprintf(stderr, _("%s: cannot initialise path table: %s\n"),
334 progname, strerror(error));
335 exit(1);
336 }
337}
338
339void
340fs_table_insert_mount(
341 char *mount)
342{
343 int error;
344
345 error = fs_table_initialise_mounts(mount);
346 if (error) {
347 fs_table_destroy();
348 fprintf(stderr, _("%s: cannot setup path for mount %s: %s\n"),
349 progname, mount, strerror(error));
350 exit(1);
351 }
352}
353
354void
355fs_table_insert_project(
356 char *project)
357{
358 int error;
359
360 if (!fs_count) {
361 fprintf(stderr, _("%s: no mount table yet, so no projects\n"),
362 progname);
363 exit(1);
364 }
365 error = fs_table_initialise_projects(project);
366 if (error) {
367 fs_table_destroy();
368 fprintf(stderr, _("%s: cannot setup path for project %s: %s\n"),
369 progname, project, strerror(error));
370 exit(1);
371 }
372}
373
374/*
375 * Table iteration (cursor-based) interfaces
376 */
377
378void
379fs_cursor_initialise(
380 char *dir,
381 uint flags,
382 fs_cursor_t *cur)
383{
384 fs_path_t *path;
385
386 memset(cur, 0, sizeof(*cur));
387 if (dir) {
388 if ((path = fs_table_lookup(dir, flags)) == NULL)
389 return;
390 cur->local = *path;
391 cur->count = 1;
392 cur->table = &cur->local;
393 } else {
394 cur->count = fs_count;
395 cur->table = fs_table;
396 }
397 cur->flags = flags;
398}
399
400struct fs_path *
401fs_cursor_next_entry(
402 fs_cursor_t *cur)
403{
404 fs_path_t *next = NULL;
405
406 while (cur->index < cur->count) {
407 next = &cur->table[cur->index++];
408 if (cur->flags & next->fs_flags)
409 break;
410 next = NULL;
411 }
412 return next;
413}