]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - rtcp/xfs_rtcp.c
Minor fix up in xfs_db man page
[thirdparty/xfsprogs-dev.git] / rtcp / xfs_rtcp.c
CommitLineData
f91dde66 1/*
da23017d
NS
2 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 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
f91dde66 7 * published by the Free Software Foundation.
dfc130f3 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.
dfc130f3 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
f91dde66
NS
17 */
18
19#include <libxfs.h>
f91dde66
NS
20
21int rtcp(char *, char *, int);
22int xfsrtextsize(char *path);
23
24int pflag;
25char *progname;
26
27void
28usage()
29{
9440d84d 30 fprintf(stderr, _("%s [-e extsize] [-p] source target\n"), progname);
f91dde66
NS
31 exit(2);
32}
33
34int
35main(int argc, char **argv)
36{
37 register int c, i, r, errflg = 0;
9440d84d 38 struct stat64 s2;
f91dde66
NS
39 int eflag;
40 int extsize = - 1;
41
42 progname = basename(argv[0]);
9440d84d
NS
43 setlocale(LC_ALL, "");
44 bindtextdomain(PACKAGE, LOCALEDIR);
45 textdomain(PACKAGE);
f91dde66
NS
46
47 while ((c = getopt(argc, argv, "pe:V")) != EOF) {
48 switch (c) {
49 case 'e':
50 eflag = 1;
51 extsize = atoi(optarg);
52 break;
53 case 'p':
54 pflag = 1;
55 break;
56 case 'V':
9440d84d 57 printf(_("%s version %s\n"), progname, VERSION);
3d98fe63 58 exit(0);
f91dde66
NS
59 default:
60 errflg++;
61 }
62 }
63
64 /*
65 * Check for sufficient arguments or a usage error.
66 */
67 argc -= optind;
68 argv = &argv[optind];
69
70 if (argc < 2) {
9440d84d
NS
71 fprintf(stderr, _("%s: must specify files to copy\n"),
72 progname);
f91dde66
NS
73 errflg++;
74 }
75
76 if (errflg)
77 usage();
78
79 /*
80 * If there is more than a source and target,
81 * the last argument (the target) must be a directory
82 * which really exists.
83 */
84 if (argc > 2) {
9440d84d
NS
85 if (stat64(argv[argc-1], &s2) < 0) {
86 fprintf(stderr, _("%s: stat64 of %s failed\n"),
f91dde66
NS
87 progname, argv[argc-1]);
88 exit(2);
89 }
90
91 if (!S_ISDIR(s2.st_mode)) {
9440d84d
NS
92 fprintf(stderr,
93 _("%s: final argument is not directory\n"),
f91dde66
NS
94 progname);
95 usage();
96 }
97 }
98
99 /*
100 * Perform a multiple argument rtcp by
101 * multiple invocations of rtcp().
102 */
103 r = 0;
104 for (i = 0; i < argc-1; i++)
105 r += rtcp(argv[i], argv[argc-1], extsize);
106
107 /*
108 * Show errors by nonzero exit code.
109 */
110 exit(r?2:0);
111}
112
113int
114rtcp( char *source, char *target, int fextsize)
115{
116 int fromfd, tofd, readct, writect, iosz, reopen;
117 int remove = 0, rtextsize;
dfc130f3 118 char *sp, *fbuf, *ptr;
f91dde66 119 char tbuf[ PATH_MAX ];
9440d84d 120 struct stat64 s1, s2;
f91dde66
NS
121 struct fsxattr fsxattr;
122 struct dioattr dioattr;
123
124 /*
125 * While source or target have trailing /, remove them
126 * unless only "/".
127 */
128 sp = source + strlen(source);
129 if (sp) {
130 while (*--sp == '/' && sp > source)
131 *sp = '\0';
132 }
133 sp = target + strlen(target);
134 if (sp) {
135 while (*--sp == '/' && sp > target)
136 *sp = '\0';
137 }
138
9440d84d
NS
139 if ( stat64(source, &s1) ) {
140 fprintf(stderr, _("%s: failed stat64 on %s: %s\n"),
141 progname, source, strerror(errno));
f91dde66
NS
142 return( -1);
143 }
144
145 /*
146 * check for a realtime partition
147 */
2d9475a4 148 snprintf(tbuf, sizeof(tbuf), "%s", target);
9440d84d 149 if ( stat64(target, &s2) ) {
f91dde66
NS
150 if (!S_ISDIR(s2.st_mode)) {
151 /* take out target file name */
152 if ((ptr = strrchr(tbuf, '/')) != NULL)
153 *ptr = '\0';
154 else
2d9475a4 155 snprintf(tbuf, sizeof(tbuf), ".");
dfc130f3 156 }
f91dde66
NS
157 }
158
159 if ( (rtextsize = xfsrtextsize( tbuf )) <= 0 ) {
9440d84d
NS
160 fprintf(stderr,
161 _("%s: %s filesystem has no realtime partition\n"),
f91dde66
NS
162 progname, tbuf);
163 return( -1 );
164 }
165
166 /*
167 * check if target is a directory
168 */
2d9475a4 169 snprintf(tbuf, sizeof(tbuf), "%s", target);
9440d84d 170 if ( !stat64(target, &s2) ) {
f91dde66 171 if (S_ISDIR(s2.st_mode)) {
2d9475a4
NS
172 snprintf(tbuf, sizeof(tbuf), "%s/%s", target,
173 basename(source));
dfc130f3 174 }
f91dde66 175 }
dfc130f3 176
9440d84d 177 if ( stat64(tbuf, &s2) ) {
f91dde66
NS
178 /*
179 * create the file if it does not exist
180 */
181 if ( (tofd = open(tbuf, O_RDWR|O_CREAT|O_DIRECT, 0666)) < 0 ) {
9440d84d
NS
182 fprintf(stderr, _("%s: open of %s failed: %s\n"),
183 progname, tbuf, strerror(errno));
f91dde66
NS
184 return( -1 );
185 }
186 remove = 1;
dfc130f3 187
f91dde66
NS
188 /*
189 * mark the file as a realtime file
190 */
191 fsxattr.fsx_xflags = XFS_XFLAG_REALTIME;
192 if (fextsize != -1 )
193 fsxattr.fsx_extsize = fextsize;
194 else
195 fsxattr.fsx_extsize = 0;
196
dfc130f3 197 if ( xfsctl(tbuf, tofd, XFS_IOC_FSSETXATTR, &fsxattr) ) {
9440d84d
NS
198 fprintf(stderr,
199 _("%s: set attributes on %s failed: %s\n"),
200 progname, tbuf, strerror(errno));
f91dde66
NS
201 close( tofd );
202 unlink( tbuf );
203 return( -1 );
204 }
205 } else {
206 /*
207 * open existing file
208 */
209 if ( (tofd = open(tbuf, O_RDWR|O_DIRECT)) < 0 ) {
9440d84d
NS
210 fprintf(stderr, _("%s: open of %s failed: %s\n"),
211 progname, tbuf, strerror(errno));
f91dde66
NS
212 return( -1 );
213 }
dfc130f3 214
93d9f139 215 if ( xfsctl(tbuf, tofd, XFS_IOC_FSGETXATTR, &fsxattr) ) {
9440d84d
NS
216 fprintf(stderr,
217 _("%s: get attributes of %s failed: %s\n"),
218 progname, tbuf, strerror(errno));
f91dde66
NS
219 close( tofd );
220 return( -1 );
221 }
222
223 /*
224 * check if the existing file is already a realtime file
225 */
226 if ( !(fsxattr.fsx_xflags & XFS_XFLAG_REALTIME) ) {
9440d84d 227 fprintf(stderr, _("%s: %s is not a realtime file.\n"),
f91dde66
NS
228 progname, tbuf);
229 return( -1 );
230 }
dfc130f3 231
f91dde66
NS
232 /*
233 * check for matching extent size
234 */
235 if ( (fextsize != -1) && (fsxattr.fsx_extsize != fextsize) ) {
9440d84d
NS
236 fprintf(stderr, _("%s: %s file extent size is %d, "
237 "instead of %d.\n"),
f91dde66
NS
238 progname, tbuf, fsxattr.fsx_extsize, fextsize);
239 return( -1 );
240 }
241 }
242
243 /*
244 * open the source file
245 */
246 reopen = 0;
247 if ( (fromfd = open(source, O_RDONLY|O_DIRECT)) < 0 ) {
9440d84d
NS
248 fprintf(stderr, _("%s: open of %s source failed: %s\n"),
249 progname, source, strerror(errno));
f91dde66
NS
250 close( tofd );
251 if (remove)
252 unlink( tbuf );
253 return( -1 );
254 }
255
256 fsxattr.fsx_xflags = 0;
257 fsxattr.fsx_extsize = 0;
93d9f139 258 if ( xfsctl(source, fromfd, XFS_IOC_FSGETXATTR, &fsxattr) ) {
f91dde66
NS
259 reopen = 1;
260 } else {
261 if (! (fsxattr.fsx_xflags & XFS_XFLAG_REALTIME) ){
9440d84d 262 fprintf(stderr, _("%s: %s is not a realtime file.\n"),
f91dde66
NS
263 progname, source);
264 reopen = 1;
265 }
266 }
267
268 if (reopen) {
269 close( fromfd );
270 if ( (fromfd = open(source, O_RDONLY )) < 0 ) {
9440d84d
NS
271 fprintf(stderr, _("%s: open of %s source failed: %s\n"),
272 progname, source, strerror(errno));
f91dde66
NS
273 close( tofd );
274 if (remove)
275 unlink( tbuf );
276 return( -1 );
277 }
278 }
279
280 /*
281 * get direct I/O parameters
282 */
93d9f139 283 if ( xfsctl(tbuf, tofd, XFS_IOC_DIOINFO, &dioattr) ) {
9440d84d
NS
284 fprintf(stderr,
285 _("%s: couldn't get direct I/O information: %s\n"),
286 progname, strerror(errno));
f91dde66
NS
287 close( fromfd );
288 close( tofd );
dfc130f3 289 if ( remove )
f91dde66
NS
290 unlink( tbuf );
291 return( -1 );
292 }
293
294 if ( rtextsize % dioattr.d_miniosz ) {
9440d84d 295 fprintf(stderr, _("%s: extent size %d not a multiple of %d.\n"),
f91dde66
NS
296 progname, rtextsize, dioattr.d_miniosz);
297 close( fromfd );
298 close( tofd );
299 if ( remove )
300 unlink( tbuf );
301 return( -1 );
302 }
303
304 /*
305 * Check that the source file size is a multiple of the
306 * file system block size.
307 */
308 if ( s1.st_size % dioattr.d_miniosz ) {
9440d84d 309 printf(_("The size of %s is not a multiple of %d.\n"),
f91dde66
NS
310 source, dioattr.d_miniosz);
311 if ( pflag ) {
9440d84d 312 printf(_("%s will be padded to %lld bytes.\n"),
e6c5396e 313 tbuf, (long long)
f91dde66
NS
314 (((s1.st_size / dioattr.d_miniosz) + 1) *
315 dioattr.d_miniosz) );
dfc130f3 316
f91dde66 317 } else {
9440d84d
NS
318 printf(_("Use the -p option to pad %s to a "
319 "size which is a multiple of %d bytes.\n"),
f91dde66
NS
320 tbuf, dioattr.d_miniosz);
321 close( fromfd );
322 close( tofd );
323 if ( remove )
324 unlink( tbuf );
325 return( -1 );
326 }
327 }
328
329 iosz = dioattr.d_miniosz;
330 fbuf = memalign( dioattr.d_mem, iosz);
331 bzero (fbuf, iosz);
332
333 /*
334 * read the entire source file
335 */
336 while ( ( readct = read( fromfd, fbuf, iosz) ) != 0 ) {
337 /*
338 * if there is a read error - break
339 */
340 if (readct < 0 ) {
341 break;
342 }
343
344 /*
345 * if there is a short read, pad to a block boundary
dfc130f3 346 */
f91dde66
NS
347 if ( readct != iosz ) {
348 if ( (readct % dioattr.d_miniosz) != 0 ) {
349 readct = ( (readct/dioattr.d_miniosz) + 1 ) *
350 dioattr.d_miniosz;
351 }
352 }
353
354 /*
dfc130f3 355 * write to target file
f91dde66
NS
356 */
357 writect = write( tofd, fbuf, readct);
358
359 if ( writect != readct ) {
9440d84d
NS
360 fprintf(stderr, _("%s: write error: %s\n"),
361 progname, strerror(errno));
f91dde66
NS
362 close(fromfd);
363 close(tofd);
364 free( fbuf );
365 return( -1 );
366 }
367
368 bzero( fbuf, iosz);
369 }
370
371 close(fromfd);
372 close(tofd);
373 free( fbuf );
374 return( 0 );
375}
376
377/*
dfc130f3 378 * Determine the realtime extent size of the XFS file system
f91dde66
NS
379 */
380int
381xfsrtextsize( char *path)
382{
383 int fd, rval, rtextsize;
9d77aadd 384 xfs_fsop_geom_v1_t geo;
f91dde66
NS
385
386 fd = open( path, O_RDONLY );
387 if ( fd < 0 ) {
9440d84d
NS
388 fprintf(stderr, _("%s: could not open %s: %s\n"),
389 progname, path, strerror(errno));
f91dde66
NS
390 return -1;
391 }
93d9f139 392 rval = xfsctl( path, fd, XFS_IOC_FSGEOMETRY_V1, &geo );
f91dde66 393 close(fd);
9d77aadd
NS
394 if ( rval < 0 )
395 return -1;
f91dde66
NS
396
397 rtextsize = geo.rtextsize * geo.blocksize;
398
f91dde66
NS
399 return rtextsize;
400}