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