]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - rtcp/xfs_rtcp.c
xfsprogs: replace [fl]stat64 by equivalent [fl]stat
[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
6b803e5a 19#include "libxfs.h"
f91dde66
NS
20
21int rtcp(char *, char *, int);
22int xfsrtextsize(char *path);
23
24int pflag;
25char *progname;
26
27void
24e04791 28usage(void)
f91dde66 29{
30626ef6 30 fprintf(stderr, _("%s [-e extsize] [-p] [-V] source target\n"), progname);
f91dde66
NS
31 exit(2);
32}
33
34int
35main(int argc, char **argv)
36{
0c2a7d46 37 int c, i, r, errflg = 0;
f594a0d1 38 struct stat s2;
f91dde66
NS
39 int extsize = - 1;
40
41 progname = basename(argv[0]);
9440d84d
NS
42 setlocale(LC_ALL, "");
43 bindtextdomain(PACKAGE, LOCALEDIR);
44 textdomain(PACKAGE);
f91dde66
NS
45
46 while ((c = getopt(argc, argv, "pe:V")) != EOF) {
47 switch (c) {
48 case 'e':
f91dde66
NS
49 extsize = atoi(optarg);
50 break;
51 case 'p':
52 pflag = 1;
53 break;
54 case 'V':
9440d84d 55 printf(_("%s version %s\n"), progname, VERSION);
3d98fe63 56 exit(0);
f91dde66
NS
57 default:
58 errflg++;
59 }
60 }
61
62 /*
63 * Check for sufficient arguments or a usage error.
64 */
65 argc -= optind;
66 argv = &argv[optind];
67
68 if (argc < 2) {
9440d84d
NS
69 fprintf(stderr, _("%s: must specify files to copy\n"),
70 progname);
f91dde66
NS
71 errflg++;
72 }
73
74 if (errflg)
75 usage();
76
77 /*
78 * If there is more than a source and target,
79 * the last argument (the target) must be a directory
80 * which really exists.
81 */
82 if (argc > 2) {
f594a0d1
FJ
83 if (stat(argv[argc-1], &s2) < 0) {
84 fprintf(stderr, _("%s: stat of %s failed\n"),
f91dde66
NS
85 progname, argv[argc-1]);
86 exit(2);
87 }
88
89 if (!S_ISDIR(s2.st_mode)) {
9440d84d
NS
90 fprintf(stderr,
91 _("%s: final argument is not directory\n"),
f91dde66
NS
92 progname);
93 usage();
94 }
95 }
96
97 /*
98 * Perform a multiple argument rtcp by
99 * multiple invocations of rtcp().
100 */
101 r = 0;
102 for (i = 0; i < argc-1; i++)
103 r += rtcp(argv[i], argv[argc-1], extsize);
104
105 /*
106 * Show errors by nonzero exit code.
107 */
108 exit(r?2:0);
109}
110
111int
112rtcp( char *source, char *target, int fextsize)
113{
114 int fromfd, tofd, readct, writect, iosz, reopen;
115 int remove = 0, rtextsize;
dfc130f3 116 char *sp, *fbuf, *ptr;
f91dde66 117 char tbuf[ PATH_MAX ];
f594a0d1 118 struct stat s1, s2;
f91dde66
NS
119 struct fsxattr fsxattr;
120 struct dioattr dioattr;
121
122 /*
123 * While source or target have trailing /, remove them
124 * unless only "/".
125 */
126 sp = source + strlen(source);
127 if (sp) {
128 while (*--sp == '/' && sp > source)
129 *sp = '\0';
130 }
131 sp = target + strlen(target);
132 if (sp) {
133 while (*--sp == '/' && sp > target)
134 *sp = '\0';
135 }
136
f594a0d1
FJ
137 if ( stat(source, &s1) ) {
138 fprintf(stderr, _("%s: failed stat on %s: %s\n"),
9440d84d 139 progname, source, strerror(errno));
f91dde66
NS
140 return( -1);
141 }
142
143 /*
144 * check for a realtime partition
145 */
2d9475a4 146 snprintf(tbuf, sizeof(tbuf), "%s", target);
f594a0d1 147 if ( stat(target, &s2) ) {
f91dde66
NS
148 if (!S_ISDIR(s2.st_mode)) {
149 /* take out target file name */
150 if ((ptr = strrchr(tbuf, '/')) != NULL)
151 *ptr = '\0';
152 else
2d9475a4 153 snprintf(tbuf, sizeof(tbuf), ".");
dfc130f3 154 }
f91dde66
NS
155 }
156
157 if ( (rtextsize = xfsrtextsize( tbuf )) <= 0 ) {
9440d84d
NS
158 fprintf(stderr,
159 _("%s: %s filesystem has no realtime partition\n"),
f91dde66
NS
160 progname, tbuf);
161 return( -1 );
162 }
163
164 /*
165 * check if target is a directory
166 */
2d9475a4 167 snprintf(tbuf, sizeof(tbuf), "%s", target);
f594a0d1 168 if ( !stat(target, &s2) ) {
f91dde66 169 if (S_ISDIR(s2.st_mode)) {
2d9475a4
NS
170 snprintf(tbuf, sizeof(tbuf), "%s/%s", target,
171 basename(source));
dfc130f3 172 }
f91dde66 173 }
dfc130f3 174
f594a0d1 175 if ( stat(tbuf, &s2) ) {
f91dde66
NS
176 /*
177 * create the file if it does not exist
178 */
179 if ( (tofd = open(tbuf, O_RDWR|O_CREAT|O_DIRECT, 0666)) < 0 ) {
9440d84d
NS
180 fprintf(stderr, _("%s: open of %s failed: %s\n"),
181 progname, tbuf, strerror(errno));
f91dde66
NS
182 return( -1 );
183 }
184 remove = 1;
dfc130f3 185
f91dde66
NS
186 /*
187 * mark the file as a realtime file
188 */
83f4b5ac 189 fsxattr.fsx_xflags = FS_XFLAG_REALTIME;
f91dde66
NS
190 if (fextsize != -1 )
191 fsxattr.fsx_extsize = fextsize;
192 else
193 fsxattr.fsx_extsize = 0;
194
83f4b5ac 195 if ( xfsctl(tbuf, tofd, FS_IOC_FSSETXATTR, &fsxattr) ) {
9440d84d
NS
196 fprintf(stderr,
197 _("%s: set attributes on %s failed: %s\n"),
198 progname, tbuf, strerror(errno));
f91dde66
NS
199 close( tofd );
200 unlink( tbuf );
201 return( -1 );
202 }
203 } else {
204 /*
205 * open existing file
206 */
207 if ( (tofd = open(tbuf, O_RDWR|O_DIRECT)) < 0 ) {
9440d84d
NS
208 fprintf(stderr, _("%s: open of %s failed: %s\n"),
209 progname, tbuf, strerror(errno));
f91dde66
NS
210 return( -1 );
211 }
dfc130f3 212
83f4b5ac 213 if ( xfsctl(tbuf, tofd, FS_IOC_FSGETXATTR, &fsxattr) ) {
9440d84d
NS
214 fprintf(stderr,
215 _("%s: get attributes of %s failed: %s\n"),
216 progname, tbuf, strerror(errno));
f91dde66
NS
217 close( tofd );
218 return( -1 );
219 }
220
221 /*
222 * check if the existing file is already a realtime file
223 */
83f4b5ac 224 if ( !(fsxattr.fsx_xflags & FS_XFLAG_REALTIME) ) {
9440d84d 225 fprintf(stderr, _("%s: %s is not a realtime file.\n"),
f91dde66 226 progname, tbuf);
11e06961 227 close( tofd );
f91dde66
NS
228 return( -1 );
229 }
dfc130f3 230
f91dde66
NS
231 /*
232 * check for matching extent size
233 */
234 if ( (fextsize != -1) && (fsxattr.fsx_extsize != fextsize) ) {
9440d84d
NS
235 fprintf(stderr, _("%s: %s file extent size is %d, "
236 "instead of %d.\n"),
f91dde66 237 progname, tbuf, fsxattr.fsx_extsize, fextsize);
11e06961 238 close( tofd );
f91dde66
NS
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;
83f4b5ac 258 if ( xfsctl(source, fromfd, FS_IOC_FSGETXATTR, &fsxattr) ) {
f91dde66
NS
259 reopen = 1;
260 } else {
83f4b5ac 261 if (! (fsxattr.fsx_xflags & FS_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);
dab9b8d6 331 memset(fbuf, 0, iosz);
f91dde66
NS
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
dab9b8d6 368 memset( fbuf, 0, iosz);
f91dde66
NS
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}