]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/seek.c
xfsprogs: make static things static
[thirdparty/xfsprogs-dev.git] / io / seek.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2013 SGI
4 * All Rights Reserved.
5 */
6
7 #include "command.h"
8 #include "input.h"
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include "init.h"
12 #include "io.h"
13
14 static cmdinfo_t seek_cmd;
15
16 static void
17 seek_help(void)
18 {
19 printf(_(
20 "\n"
21 " returns the next hole and/or data offset at or after the requested offset\n"
22 "\n"
23 " Example:\n"
24 " 'seek -d 512' - offset of data at or following offset 512\n"
25 " 'seek -a -r 0' - offsets of all data and hole in entire file\n"
26 "\n"
27 " Returns the offset of the next data and/or hole. There is an implied hole\n"
28 " at the end of file. If the specified offset is past end of file, or there\n"
29 " is no data past the specified offset, EOF is returned.\n"
30 " -a -- return the next data and hole starting at the specified offset.\n"
31 " -d -- return the next data starting at the specified offset.\n"
32 " -h -- return the next hole starting at the specified offset.\n"
33 " -r -- return all remaining type(s) starting at the specified offset.\n"
34 " -s -- also print the starting offset.\n"
35 "\n"));
36 }
37
38 #ifndef HAVE_SEEK_DATA
39 #define SEEK_DATA 3 /* seek to the next data */
40 #define SEEK_HOLE 4 /* seek to the next hole */
41 #endif
42
43 /* values for flag variable */
44 #define SEEK_DFLAG (1 << 0)
45 #define SEEK_HFLAG (1 << 1)
46 #define SEEK_RFLAG (1 << 2)
47
48 /* indexes into the seekinfo array */
49 #define DATA 0
50 #define HOLE 1
51
52 static struct seekinfo {
53 char *name; /* display item name */
54 int seektype; /* data or hole */
55 int mask; /* compared for print and looping */
56 } seekinfo[] = {
57 {"DATA", SEEK_DATA, SEEK_DFLAG},
58 {"HOLE", SEEK_HOLE, SEEK_HFLAG}
59 };
60
61 /* print item type and offset. catch special cases of eof and error */
62 static void
63 seek_output(
64 int startflag,
65 char *type,
66 off64_t start,
67 off64_t offset)
68 {
69 if (offset == -1) {
70 if (errno == ENXIO) {
71 if (startflag)
72 printf("%s %lld EOF\n", type,
73 (long long)start);
74 else
75 printf("%s EOF\n", type);
76 } else {
77 printf("ERR %lld ", (long long)start);
78 fflush(stdout); /* so the printf preceded the perror */
79 perror("");
80 }
81 } else {
82 if (startflag)
83 printf("%s %lld %lld\n", type,
84 (long long)start, (long long)offset);
85 else
86 printf("%s %lld\n", type, (long long)offset);
87 }
88 }
89
90 static int
91 seek_f(
92 int argc,
93 char **argv)
94 {
95 off64_t offset, start;
96 size_t fsblocksize, fssectsize;
97 int c;
98 int current; /* specify data or hole */
99 int flag;
100 int startflag;
101
102 flag = startflag = 0;
103 init_cvtnum(&fsblocksize, &fssectsize);
104
105 while ((c = getopt(argc, argv, "adhrs")) != EOF) {
106 switch (c) {
107 case 'a':
108 flag |= (SEEK_HFLAG | SEEK_DFLAG);
109 break;
110 case 'd':
111 flag |= SEEK_DFLAG;
112 break;
113 case 'h':
114 flag |= SEEK_HFLAG;
115 break;
116 case 'r':
117 flag |= SEEK_RFLAG;
118 break;
119 case 's':
120 startflag = 1;
121 break;
122 default:
123 return command_usage(&seek_cmd);
124 }
125 }
126 if (!(flag & (SEEK_DFLAG | SEEK_HFLAG)) || optind != argc - 1)
127 return command_usage(&seek_cmd);
128
129 start = offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
130 if (offset < 0)
131 return command_usage(&seek_cmd);
132
133 /*
134 * check to see if the offset is a data or hole entry and
135 * decide if we want to display that type of entry.
136 */
137 if (flag & SEEK_HFLAG) {
138 current = HOLE;
139 offset = lseek(file->fd, start, SEEK_HOLE);
140 if (offset != -1 && offset < start)
141 goto bad_result;
142 if ((start == offset) || !(flag & SEEK_DFLAG)) {
143 /*
144 * this offset is a hole or are only displaying holes.
145 * if this offset is for data and we are displaying
146 * data, then we will fall through below to
147 * initialize the data search.
148 */
149 goto found_hole;
150 }
151 }
152
153 /* The offset is not a hole, or we are looking just for data */
154 current = DATA;
155 offset = lseek(file->fd, start, SEEK_DATA);
156 if (offset != -1 && offset < start)
157 goto bad_result;
158
159 found_hole:
160 /*
161 * At this point we know which type and the offset of the starting
162 * item. "current" alternates between data / hole entries in
163 * assending order - this alternation is needed even if only one
164 * type is to be displayed.
165 *
166 * An error or EOF will terminate the display, otherwise "flag"
167 * determines if there are more items to be displayed.
168 */
169 if (startflag)
170 printf("Whence Start Result\n");
171 else
172 printf("Whence Result\n");
173
174 for (c = 0; flag; c++) {
175 if (offset == -1) {
176 /* print error or eof if the only entry */
177 if (errno != ENXIO || c == 0 )
178 seek_output(startflag, seekinfo[current].name,
179 start, offset);
180 return 0; /* stop on error or EOF */
181 }
182
183 if (flag & seekinfo[current].mask)
184 seek_output(startflag, seekinfo[current].name, start,
185 offset);
186
187 /*
188 * When displaying only a single data and/or hole item, mask
189 * off the item as it is displayed. The loop will end when all
190 * requested items have been displayed.
191 */
192 if (!(flag & SEEK_RFLAG))
193 flag &= ~seekinfo[current].mask;
194
195 current ^= 1; /* alternate between data and hole */
196 start = offset;
197 offset = lseek(file->fd, start, seekinfo[current].seektype);
198 if (offset != -1 && offset <= start)
199 goto bad_result;
200 }
201 return 0;
202
203 bad_result:
204 fprintf(stderr, "Invalid seek result: lseek(<fd>, %lld, SEEK_%s) = %lld\n",
205 (long long)start, seekinfo[current].name, (long long)offset);
206 return 0;
207 }
208
209 void
210 seek_init(void)
211 {
212 seek_cmd.name = "seek";
213 seek_cmd.cfunc = seek_f;
214 seek_cmd.argmin = 2;
215 seek_cmd.argmax = 5;
216 seek_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
217 seek_cmd.args = _("-a | -d | -h [-r] off");
218 seek_cmd.oneline = _("locate the next data and/or hole");
219 seek_cmd.help = seek_help;
220
221 add_command(&seek_cmd);
222 }