]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - rtcp/xfs_rtcp.c
libfrog: convert fsgeom.c functions to negative error codes
[thirdparty/xfsprogs-dev.git] / rtcp / xfs_rtcp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "libxfs.h"
8 #include "libfrog/fsgeom.h"
9
10 int rtcp(char *, char *, int);
11 int xfsrtextsize(char *path);
12
13 static int pflag;
14 char *progname;
15
16 static void
17 usage(void)
18 {
19 fprintf(stderr, _("%s [-e extsize] [-p] [-V] source target\n"), progname);
20 exit(2);
21 }
22
23 int
24 main(int argc, char **argv)
25 {
26 int c, i, r, errflg = 0;
27 struct stat s2;
28 int extsize = - 1;
29
30 progname = basename(argv[0]);
31 setlocale(LC_ALL, "");
32 bindtextdomain(PACKAGE, LOCALEDIR);
33 textdomain(PACKAGE);
34
35 while ((c = getopt(argc, argv, "pe:V")) != EOF) {
36 switch (c) {
37 case 'e':
38 extsize = atoi(optarg);
39 break;
40 case 'p':
41 pflag = 1;
42 break;
43 case 'V':
44 printf(_("%s version %s\n"), progname, VERSION);
45 exit(0);
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) {
58 fprintf(stderr, _("%s: must specify files to copy\n"),
59 progname);
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) {
72 if (stat(argv[argc-1], &s2) < 0) {
73 fprintf(stderr, _("%s: stat of %s failed\n"),
74 progname, argv[argc-1]);
75 exit(2);
76 }
77
78 if (!S_ISDIR(s2.st_mode)) {
79 fprintf(stderr,
80 _("%s: final argument is not directory\n"),
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
100 int
101 rtcp( char *source, char *target, int fextsize)
102 {
103 int fromfd, tofd, readct, writect, iosz, reopen;
104 int remove = 0, rtextsize;
105 char *sp, *fbuf, *ptr;
106 char tbuf[ PATH_MAX ];
107 struct stat s1, s2;
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
126 if ( stat(source, &s1) ) {
127 fprintf(stderr, _("%s: failed stat on %s: %s\n"),
128 progname, source, strerror(errno));
129 return( -1);
130 }
131
132 /*
133 * check for a realtime partition
134 */
135 snprintf(tbuf, sizeof(tbuf), "%s", target);
136 if ( stat(target, &s2) ) {
137 if (!S_ISDIR(s2.st_mode)) {
138 /* take out target file name */
139 if ((ptr = strrchr(tbuf, '/')) != NULL)
140 *ptr = '\0';
141 else
142 snprintf(tbuf, sizeof(tbuf), ".");
143 }
144 }
145
146 if ( (rtextsize = xfsrtextsize( tbuf )) <= 0 ) {
147 fprintf(stderr,
148 _("%s: %s filesystem has no realtime partition\n"),
149 progname, tbuf);
150 return( -1 );
151 }
152
153 /*
154 * check if target is a directory
155 */
156 snprintf(tbuf, sizeof(tbuf), "%s", target);
157 if ( !stat(target, &s2) ) {
158 if (S_ISDIR(s2.st_mode)) {
159 snprintf(tbuf, sizeof(tbuf), "%s/%s", target,
160 basename(source));
161 }
162 }
163
164 if ( stat(tbuf, &s2) ) {
165 /*
166 * create the file if it does not exist
167 */
168 if ( (tofd = open(tbuf, O_RDWR|O_CREAT|O_DIRECT, 0666)) < 0 ) {
169 fprintf(stderr, _("%s: open of %s failed: %s\n"),
170 progname, tbuf, strerror(errno));
171 return( -1 );
172 }
173 remove = 1;
174
175 /*
176 * mark the file as a realtime file
177 */
178 fsxattr.fsx_xflags = FS_XFLAG_REALTIME;
179 if (fextsize != -1 )
180 fsxattr.fsx_extsize = fextsize;
181 else
182 fsxattr.fsx_extsize = 0;
183
184 if ( xfsctl(tbuf, tofd, FS_IOC_FSSETXATTR, &fsxattr) ) {
185 fprintf(stderr,
186 _("%s: set attributes on %s failed: %s\n"),
187 progname, tbuf, strerror(errno));
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 ) {
197 fprintf(stderr, _("%s: open of %s failed: %s\n"),
198 progname, tbuf, strerror(errno));
199 return( -1 );
200 }
201
202 if ( xfsctl(tbuf, tofd, FS_IOC_FSGETXATTR, &fsxattr) ) {
203 fprintf(stderr,
204 _("%s: get attributes of %s failed: %s\n"),
205 progname, tbuf, strerror(errno));
206 close( tofd );
207 return( -1 );
208 }
209
210 /*
211 * check if the existing file is already a realtime file
212 */
213 if ( !(fsxattr.fsx_xflags & FS_XFLAG_REALTIME) ) {
214 fprintf(stderr, _("%s: %s is not a realtime file.\n"),
215 progname, tbuf);
216 close( tofd );
217 return( -1 );
218 }
219
220 /*
221 * check for matching extent size
222 */
223 if ( (fextsize != -1) && (fsxattr.fsx_extsize != fextsize) ) {
224 fprintf(stderr, _("%s: %s file extent size is %d, "
225 "instead of %d.\n"),
226 progname, tbuf, fsxattr.fsx_extsize, fextsize);
227 close( tofd );
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 ) {
237 fprintf(stderr, _("%s: open of %s source failed: %s\n"),
238 progname, source, strerror(errno));
239 close( tofd );
240 if (remove)
241 unlink( tbuf );
242 return( -1 );
243 }
244
245 fsxattr.fsx_xflags = 0;
246 fsxattr.fsx_extsize = 0;
247 if ( xfsctl(source, fromfd, FS_IOC_FSGETXATTR, &fsxattr) ) {
248 reopen = 1;
249 } else {
250 if (! (fsxattr.fsx_xflags & FS_XFLAG_REALTIME) ){
251 fprintf(stderr, _("%s: %s is not a realtime file.\n"),
252 progname, source);
253 reopen = 1;
254 }
255 }
256
257 if (reopen) {
258 close( fromfd );
259 if ( (fromfd = open(source, O_RDONLY )) < 0 ) {
260 fprintf(stderr, _("%s: open of %s source failed: %s\n"),
261 progname, source, strerror(errno));
262 close( tofd );
263 if (remove)
264 unlink( tbuf );
265 return( -1 );
266 }
267 }
268
269 /*
270 * get direct I/O parameters
271 */
272 if ( xfsctl(tbuf, tofd, XFS_IOC_DIOINFO, &dioattr) ) {
273 fprintf(stderr,
274 _("%s: couldn't get direct I/O information: %s\n"),
275 progname, strerror(errno));
276 close( fromfd );
277 close( tofd );
278 if ( remove )
279 unlink( tbuf );
280 return( -1 );
281 }
282
283 if ( rtextsize % dioattr.d_miniosz ) {
284 fprintf(stderr, _("%s: extent size %d not a multiple of %d.\n"),
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 ) {
298 printf(_("The size of %s is not a multiple of %d.\n"),
299 source, dioattr.d_miniosz);
300 if ( pflag ) {
301 printf(_("%s will be padded to %lld bytes.\n"),
302 tbuf, (long long)
303 (((s1.st_size / dioattr.d_miniosz) + 1) *
304 dioattr.d_miniosz) );
305
306 } else {
307 printf(_("Use the -p option to pad %s to a "
308 "size which is a multiple of %d bytes.\n"),
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);
320 memset(fbuf, 0, iosz);
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
335 */
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 /*
344 * write to target file
345 */
346 writect = write( tofd, fbuf, readct);
347
348 if ( writect != readct ) {
349 fprintf(stderr, _("%s: write error: %s\n"),
350 progname, strerror(errno));
351 close(fromfd);
352 close(tofd);
353 free( fbuf );
354 return( -1 );
355 }
356
357 memset( fbuf, 0, iosz);
358 }
359
360 close(fromfd);
361 close(tofd);
362 free( fbuf );
363 return( 0 );
364 }
365
366 /*
367 * Determine the realtime extent size of the XFS file system
368 */
369 int
370 xfsrtextsize( char *path)
371 {
372 struct xfs_fsop_geom geo;
373 int fd, rval, rtextsize;
374
375 fd = open( path, O_RDONLY );
376 if ( fd < 0 ) {
377 fprintf(stderr, _("%s: could not open %s: %s\n"),
378 progname, path, strerror(errno));
379 return -1;
380 }
381 rval = -xfrog_geometry(fd, &geo);
382 close(fd);
383 if (rval)
384 return -1;
385
386 rtextsize = geo.rtextsize * geo.blocksize;
387
388 return rtextsize;
389 }