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