]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
b169249b MT |
2 | /* |
3 | * Copyright (c) 2013 SGI | |
4 | * All Rights Reserved. | |
b169249b MT |
5 | */ |
6 | ||
6b803e5a CH |
7 | #include "command.h" |
8 | #include "input.h" | |
b169249b MT |
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 | ||
00ff2b10 | 52 | static struct seekinfo { |
b169249b MT |
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 */ | |
00ff2b10 | 62 | static void |
b169249b MT |
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) { | |
866d7fcb | 138 | current = HOLE; |
dc8878f4 | 139 | offset = lseek(file->fd, start, SEEK_HOLE); |
866d7fcb AG |
140 | if (offset != -1 && offset < start) |
141 | goto bad_result; | |
b169249b MT |
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 | */ | |
b169249b MT |
149 | goto found_hole; |
150 | } | |
151 | } | |
152 | ||
153 | /* The offset is not a hole, or we are looking just for data */ | |
154 | current = DATA; | |
dc8878f4 | 155 | offset = lseek(file->fd, start, SEEK_DATA); |
866d7fcb AG |
156 | if (offset != -1 && offset < start) |
157 | goto bad_result; | |
b169249b MT |
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; | |
dc8878f4 | 197 | offset = lseek(file->fd, start, seekinfo[current].seektype); |
866d7fcb AG |
198 | if (offset != -1 && offset <= start) |
199 | goto bad_result; | |
b169249b MT |
200 | } |
201 | return 0; | |
866d7fcb AG |
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; | |
b169249b MT |
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 | } |