]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - rtcp/xfs_rtcp.c
force even number of 512-byte blocks when data/log/rt fills partition
[thirdparty/xfsprogs-dev.git] / rtcp / xfs_rtcp.c
CommitLineData
f91dde66
NS
1/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33#include <libxfs.h>
34#include <malloc.h>
35#include <sys/stat.h>
36#include <sys/ioctl.h>
37
38int rtcp(char *, char *, int);
39int xfsrtextsize(char *path);
40
41int pflag;
42char *progname;
43
44void
45usage()
46{
47 fprintf(stderr, "%s [-e extsize] [-p] source target\n", progname);
48 exit(2);
49}
50
51int
52main(int argc, char **argv)
53{
54 register int c, i, r, errflg = 0;
55 struct stat s2;
56 int eflag;
57 int extsize = - 1;
58
59 progname = basename(argv[0]);
60
61 while ((c = getopt(argc, argv, "pe:V")) != EOF) {
62 switch (c) {
63 case 'e':
64 eflag = 1;
65 extsize = atoi(optarg);
66 break;
67 case 'p':
68 pflag = 1;
69 break;
70 case 'V':
71 printf("%s version %s\n", progname, VERSION);
72 break;
73 default:
74 errflg++;
75 }
76 }
77
78 /*
79 * Check for sufficient arguments or a usage error.
80 */
81 argc -= optind;
82 argv = &argv[optind];
83
84 if (argc < 2) {
85 fprintf(stderr, "%s: must specify files to copy\n", progname);
86 errflg++;
87 }
88
89 if (errflg)
90 usage();
91
92 /*
93 * If there is more than a source and target,
94 * the last argument (the target) must be a directory
95 * which really exists.
96 */
97 if (argc > 2) {
98 if (stat(argv[argc-1], &s2) < 0) {
99 fprintf(stderr, "%s: stat of %s failed\n",
100 progname, argv[argc-1]);
101 exit(2);
102 }
103
104 if (!S_ISDIR(s2.st_mode)) {
105 fprintf(stderr, "%s: final argument is not directory\n",
106 progname);
107 usage();
108 }
109 }
110
111 /*
112 * Perform a multiple argument rtcp by
113 * multiple invocations of rtcp().
114 */
115 r = 0;
116 for (i = 0; i < argc-1; i++)
117 r += rtcp(argv[i], argv[argc-1], extsize);
118
119 /*
120 * Show errors by nonzero exit code.
121 */
122 exit(r?2:0);
123}
124
125int
126rtcp( char *source, char *target, int fextsize)
127{
128 int fromfd, tofd, readct, writect, iosz, reopen;
129 int remove = 0, rtextsize;
130 char *sp, *fbuf, *ptr;
131 char tbuf[ PATH_MAX ];
132 struct stat s1, s2;
133 struct fsxattr fsxattr;
134 struct dioattr dioattr;
135
136 /*
137 * While source or target have trailing /, remove them
138 * unless only "/".
139 */
140 sp = source + strlen(source);
141 if (sp) {
142 while (*--sp == '/' && sp > source)
143 *sp = '\0';
144 }
145 sp = target + strlen(target);
146 if (sp) {
147 while (*--sp == '/' && sp > target)
148 *sp = '\0';
149 }
150
151 if ( stat(source, &s1) ) {
152 fprintf(stderr, "%s: failed stat on\n", progname);
153 perror(source);
154 return( -1);
155 }
156
157 /*
158 * check for a realtime partition
159 */
160 sprintf(tbuf,"%s",target);
161 if ( stat(target, &s2) ) {
162 if (!S_ISDIR(s2.st_mode)) {
163 /* take out target file name */
164 if ((ptr = strrchr(tbuf, '/')) != NULL)
165 *ptr = '\0';
166 else
167 sprintf(tbuf, ".");
168 }
169 }
170
171 if ( (rtextsize = xfsrtextsize( tbuf )) <= 0 ) {
172 fprintf(stderr, "%s: %s filesystem has no realtime partition\n",
173 progname, tbuf);
174 return( -1 );
175 }
176
177 /*
178 * check if target is a directory
179 */
180 sprintf(tbuf,"%s",target);
181 if ( !stat(target, &s2) ) {
182 if (S_ISDIR(s2.st_mode)) {
183 sprintf(tbuf,"%s/%s",target, basename(source));
184 }
185 }
186
187 if ( stat(tbuf, &s2) ) {
188 /*
189 * create the file if it does not exist
190 */
191 if ( (tofd = open(tbuf, O_RDWR|O_CREAT|O_DIRECT, 0666)) < 0 ) {
192 fprintf(stderr, "%s: Open of %s failed.\n",
193 progname, tbuf);
194 return( -1 );
195 }
196 remove = 1;
197
198 /*
199 * mark the file as a realtime file
200 */
201 fsxattr.fsx_xflags = XFS_XFLAG_REALTIME;
202 if (fextsize != -1 )
203 fsxattr.fsx_extsize = fextsize;
204 else
205 fsxattr.fsx_extsize = 0;
206
207 if ( ioctl( tofd, XFS_IOC_FSSETXATTR, &fsxattr) ) {
208 fprintf(stderr, "%s: Set attributes on %s failed.\n",
209 progname, tbuf);
210 close( tofd );
211 unlink( tbuf );
212 return( -1 );
213 }
214 } else {
215 /*
216 * open existing file
217 */
218 if ( (tofd = open(tbuf, O_RDWR|O_DIRECT)) < 0 ) {
219 fprintf(stderr, "%s: Open of %s failed.\n",
220 progname, tbuf);
221 return( -1 );
222 }
223
224 if ( ioctl( tofd, XFS_IOC_FSGETXATTR, &fsxattr) ) {
225 fprintf(stderr, "%s: Get attributes of %s failed.\n",
226 progname, tbuf);
227 close( tofd );
228 return( -1 );
229 }
230
231 /*
232 * check if the existing file is already a realtime file
233 */
234 if ( !(fsxattr.fsx_xflags & XFS_XFLAG_REALTIME) ) {
235 fprintf(stderr, "%s: %s is not a realtime file.\n",
236 progname, tbuf);
237 return( -1 );
238 }
239
240 /*
241 * check for matching extent size
242 */
243 if ( (fextsize != -1) && (fsxattr.fsx_extsize != fextsize) ) {
244 fprintf(stderr, "%s: %s file extent size is %d, "
245 "instead of %d.\n",
246 progname, tbuf, fsxattr.fsx_extsize, fextsize);
247 return( -1 );
248 }
249 }
250
251 /*
252 * open the source file
253 */
254 reopen = 0;
255 if ( (fromfd = open(source, O_RDONLY|O_DIRECT)) < 0 ) {
256 fprintf(stderr, "%s: Open of %s source failed.\n",
257 progname, source);
258 close( tofd );
259 if (remove)
260 unlink( tbuf );
261 return( -1 );
262 }
263
264 fsxattr.fsx_xflags = 0;
265 fsxattr.fsx_extsize = 0;
266 if ( ioctl( fromfd, XFS_IOC_FSGETXATTR, &fsxattr) ) {
267 reopen = 1;
268 } else {
269 if (! (fsxattr.fsx_xflags & XFS_XFLAG_REALTIME) ){
270 fprintf(stderr, "%s: %s is not a realtime file.\n",
271 progname, source);
272 reopen = 1;
273 }
274 }
275
276 if (reopen) {
277 close( fromfd );
278 if ( (fromfd = open(source, O_RDONLY )) < 0 ) {
279 fprintf(stderr, "%s: Open of %s source failed.\n",
280 progname, source);
281 close( tofd );
282 if (remove)
283 unlink( tbuf );
284 return( -1 );
285 }
286 }
287
288 /*
289 * get direct I/O parameters
290 */
291 if ( ioctl( tofd, XFS_IOC_DIOINFO, &dioattr) ) {
292 fprintf(stderr, "%s: Could not get direct I/O information.\n",
293 progname);
294 close( fromfd );
295 close( tofd );
296 if ( remove )
297 unlink( tbuf );
298 return( -1 );
299 }
300
301 if ( rtextsize % dioattr.d_miniosz ) {
302 fprintf(stderr, "%s: extent size %d not a multiple of %d.\n",
303 progname, rtextsize, dioattr.d_miniosz);
304 close( fromfd );
305 close( tofd );
306 if ( remove )
307 unlink( tbuf );
308 return( -1 );
309 }
310
311 /*
312 * Check that the source file size is a multiple of the
313 * file system block size.
314 */
315 if ( s1.st_size % dioattr.d_miniosz ) {
316 printf("The size of %s is not a multiple of %d.\n",
317 source, dioattr.d_miniosz);
318 if ( pflag ) {
319 printf("%s will be padded to %lld bytes.\n",
e6c5396e 320 tbuf, (long long)
f91dde66
NS
321 (((s1.st_size / dioattr.d_miniosz) + 1) *
322 dioattr.d_miniosz) );
323
324 } else {
325 printf("Use the -p option to pad %s "
326 "to a size which is a multiple of %d bytes.\n",
327 tbuf, dioattr.d_miniosz);
328 close( fromfd );
329 close( tofd );
330 if ( remove )
331 unlink( tbuf );
332 return( -1 );
333 }
334 }
335
336 iosz = dioattr.d_miniosz;
337 fbuf = memalign( dioattr.d_mem, iosz);
338 bzero (fbuf, iosz);
339
340 /*
341 * read the entire source file
342 */
343 while ( ( readct = read( fromfd, fbuf, iosz) ) != 0 ) {
344 /*
345 * if there is a read error - break
346 */
347 if (readct < 0 ) {
348 break;
349 }
350
351 /*
352 * if there is a short read, pad to a block boundary
353 */
354 if ( readct != iosz ) {
355 if ( (readct % dioattr.d_miniosz) != 0 ) {
356 readct = ( (readct/dioattr.d_miniosz) + 1 ) *
357 dioattr.d_miniosz;
358 }
359 }
360
361 /*
362 * write to target file
363 */
364 writect = write( tofd, fbuf, readct);
365
366 if ( writect != readct ) {
367 fprintf(stderr, "%s: Write error.\n", progname);
368 close(fromfd);
369 close(tofd);
370 free( fbuf );
371 return( -1 );
372 }
373
374 bzero( fbuf, iosz);
375 }
376
377 close(fromfd);
378 close(tofd);
379 free( fbuf );
380 return( 0 );
381}
382
383/*
384 * Determine the realtime extent size of the XFS file system
385 */
386int
387xfsrtextsize( char *path)
388{
389 int fd, rval, rtextsize;
390 xfs_fsop_geom_t geo;
391
392 fd = open( path, O_RDONLY );
393 if ( fd < 0 ) {
394 fprintf(stderr, "%s: Could not open ", progname);
395 perror(path);
396 return -1;
397 }
398 rval = ioctl(fd, XFS_IOC_FSGEOMETRY, &geo );
399 close(fd);
400
401 rtextsize = geo.rtextsize * geo.blocksize;
402
403 if ( rval < 0 )
404 return -1;
405 return rtextsize;
406}