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