]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxcmd/paths.c
Update copyright/license notices to match SGI legal prefered boilerplate.
[thirdparty/xfsprogs-dev.git] / libxcmd / paths.c
1 /*
2 * Copyright (c) 2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
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
31 int fs_count;
32 struct fs_path *fs_table;
33 struct fs_path *fs_path;
34
35 char *mtab_file;
36 #define PROC_MOUNTS "/proc/self/mounts"
37
38 struct fs_path *
39 fs_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
57 static int
58 fs_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
112 void
113 fs_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
130 #if defined(HAVE_GETMNTENT)
131 #include <mntent.h>
132
133 static void
134 fs_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 */
144 if ((fslog = hasmntopt(mnt, "logdev=")))
145 fslog += 7;
146 if ((fsrt = hasmntopt(mnt, "rtdev=")))
147 fsrt += 6;
148
149 /* Do this only after we've finished processing mount options */
150 if (fslog) {
151 fslogend = strtok(fslog, " ,");
152 fslog = strdup(fslog);
153 }
154 if (fsrt) {
155 fsrtend = strtok(fsrt, " ,");
156 fsrt = strdup(fsrt);
157 }
158
159 *logp = fslog;
160 *rtp = fsrt;
161 }
162
163 static int
164 fs_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
172 if (!mtab_file) {
173 mtab_file = PROC_MOUNTS;
174 if (access(mtab_file, R_OK) != 0)
175 mtab_file = MOUNTED;
176 }
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
213 static int
214 fs_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,
242 fsname, fslog, fsrt)))
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 */
261 static struct fs_path *
262 fs_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
282 static int
283 fs_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
323 void
324 fs_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
339 void
340 fs_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
354 void
355 fs_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
378 void
379 fs_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
400 struct fs_path *
401 fs_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 }