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