]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - rtcp/xfs_rtcp.c
xfsprogs: Fix up usage() errors and omissions
[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{
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{
37 register int c, i, r, errflg = 0;
9440d84d 38 struct stat64 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) {
9440d84d
NS
83 if (stat64(argv[argc-1], &s2) < 0) {
84 fprintf(stderr, _("%s: stat64 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 ];
9440d84d 118 struct stat64 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
9440d84d
NS
137 if ( stat64(source, &s1) ) {
138 fprintf(stderr, _("%s: failed stat64 on %s: %s\n"),
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);
9440d84d 147 if ( stat64(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);
9440d84d 168 if ( !stat64(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
9440d84d 175 if ( stat64(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 */
189 fsxattr.fsx_xflags = XFS_XFLAG_REALTIME;
190 if (fextsize != -1 )
191 fsxattr.fsx_extsize = fextsize;
192 else
193 fsxattr.fsx_extsize = 0;
194
dfc130f3 195 if ( xfsctl(tbuf, tofd, XFS_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
93d9f139 213 if ( xfsctl(tbuf, tofd, XFS_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 */
224 if ( !(fsxattr.fsx_xflags & XFS_XFLAG_REALTIME) ) {
9440d84d 225 fprintf(stderr, _("%s: %s is not a realtime file.\n"),
f91dde66
NS
226 progname, tbuf);
227 return( -1 );
228 }
dfc130f3 229
f91dde66
NS
230 /*
231 * check for matching extent size
232 */
233 if ( (fextsize != -1) && (fsxattr.fsx_extsize != fextsize) ) {
9440d84d
NS
234 fprintf(stderr, _("%s: %s file extent size is %d, "
235 "instead of %d.\n"),
f91dde66
NS
236 progname, tbuf, fsxattr.fsx_extsize, fextsize);
237 return( -1 );
238 }
239 }
240
241 /*
242 * open the source file
243 */
244 reopen = 0;
245 if ( (fromfd = open(source, O_RDONLY|O_DIRECT)) < 0 ) {
9440d84d
NS
246 fprintf(stderr, _("%s: open of %s source failed: %s\n"),
247 progname, source, strerror(errno));
f91dde66
NS
248 close( tofd );
249 if (remove)
250 unlink( tbuf );
251 return( -1 );
252 }
253
254 fsxattr.fsx_xflags = 0;
255 fsxattr.fsx_extsize = 0;
93d9f139 256 if ( xfsctl(source, fromfd, XFS_IOC_FSGETXATTR, &fsxattr) ) {
f91dde66
NS
257 reopen = 1;
258 } else {
259 if (! (fsxattr.fsx_xflags & XFS_XFLAG_REALTIME) ){
9440d84d 260 fprintf(stderr, _("%s: %s is not a realtime file.\n"),
f91dde66
NS
261 progname, source);
262 reopen = 1;
263 }
264 }
265
266 if (reopen) {
267 close( fromfd );
268 if ( (fromfd = open(source, O_RDONLY )) < 0 ) {
9440d84d
NS
269 fprintf(stderr, _("%s: open of %s source failed: %s\n"),
270 progname, source, strerror(errno));
f91dde66
NS
271 close( tofd );
272 if (remove)
273 unlink( tbuf );
274 return( -1 );
275 }
276 }
277
278 /*
279 * get direct I/O parameters
280 */
93d9f139 281 if ( xfsctl(tbuf, tofd, XFS_IOC_DIOINFO, &dioattr) ) {
9440d84d
NS
282 fprintf(stderr,
283 _("%s: couldn't get direct I/O information: %s\n"),
284 progname, strerror(errno));
f91dde66
NS
285 close( fromfd );
286 close( tofd );
dfc130f3 287 if ( remove )
f91dde66
NS
288 unlink( tbuf );
289 return( -1 );
290 }
291
292 if ( rtextsize % dioattr.d_miniosz ) {
9440d84d 293 fprintf(stderr, _("%s: extent size %d not a multiple of %d.\n"),
f91dde66
NS
294 progname, rtextsize, dioattr.d_miniosz);
295 close( fromfd );
296 close( tofd );
297 if ( remove )
298 unlink( tbuf );
299 return( -1 );
300 }
301
302 /*
303 * Check that the source file size is a multiple of the
304 * file system block size.
305 */
306 if ( s1.st_size % dioattr.d_miniosz ) {
9440d84d 307 printf(_("The size of %s is not a multiple of %d.\n"),
f91dde66
NS
308 source, dioattr.d_miniosz);
309 if ( pflag ) {
9440d84d 310 printf(_("%s will be padded to %lld bytes.\n"),
e6c5396e 311 tbuf, (long long)
f91dde66
NS
312 (((s1.st_size / dioattr.d_miniosz) + 1) *
313 dioattr.d_miniosz) );
dfc130f3 314
f91dde66 315 } else {
9440d84d
NS
316 printf(_("Use the -p option to pad %s to a "
317 "size which is a multiple of %d bytes.\n"),
f91dde66
NS
318 tbuf, dioattr.d_miniosz);
319 close( fromfd );
320 close( tofd );
321 if ( remove )
322 unlink( tbuf );
323 return( -1 );
324 }
325 }
326
327 iosz = dioattr.d_miniosz;
328 fbuf = memalign( dioattr.d_mem, iosz);
dab9b8d6 329 memset(fbuf, 0, iosz);
f91dde66
NS
330
331 /*
332 * read the entire source file
333 */
334 while ( ( readct = read( fromfd, fbuf, iosz) ) != 0 ) {
335 /*
336 * if there is a read error - break
337 */
338 if (readct < 0 ) {
339 break;
340 }
341
342 /*
343 * if there is a short read, pad to a block boundary
dfc130f3 344 */
f91dde66
NS
345 if ( readct != iosz ) {
346 if ( (readct % dioattr.d_miniosz) != 0 ) {
347 readct = ( (readct/dioattr.d_miniosz) + 1 ) *
348 dioattr.d_miniosz;
349 }
350 }
351
352 /*
dfc130f3 353 * write to target file
f91dde66
NS
354 */
355 writect = write( tofd, fbuf, readct);
356
357 if ( writect != readct ) {
9440d84d
NS
358 fprintf(stderr, _("%s: write error: %s\n"),
359 progname, strerror(errno));
f91dde66
NS
360 close(fromfd);
361 close(tofd);
362 free( fbuf );
363 return( -1 );
364 }
365
dab9b8d6 366 memset( fbuf, 0, iosz);
f91dde66
NS
367 }
368
369 close(fromfd);
370 close(tofd);
371 free( fbuf );
372 return( 0 );
373}
374
375/*
dfc130f3 376 * Determine the realtime extent size of the XFS file system
f91dde66
NS
377 */
378int
379xfsrtextsize( char *path)
380{
381 int fd, rval, rtextsize;
9d77aadd 382 xfs_fsop_geom_v1_t geo;
f91dde66
NS
383
384 fd = open( path, O_RDONLY );
385 if ( fd < 0 ) {
9440d84d
NS
386 fprintf(stderr, _("%s: could not open %s: %s\n"),
387 progname, path, strerror(errno));
f91dde66
NS
388 return -1;
389 }
93d9f139 390 rval = xfsctl( path, fd, XFS_IOC_FSGEOMETRY_V1, &geo );
f91dde66 391 close(fd);
9d77aadd
NS
392 if ( rval < 0 )
393 return -1;
f91dde66
NS
394
395 rtextsize = geo.rtextsize * geo.blocksize;
396
f91dde66
NS
397 return rtextsize;
398}