]>
Commit | Line | Data |
---|---|---|
e246ba5f | 1 | /* |
da23017d NS |
2 | * Copyright (c) 2003-2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | |
dfc130f3 | 4 | * |
da23017d NS |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | |
e246ba5f | 7 | * published by the Free Software Foundation. |
dfc130f3 | 8 | * |
da23017d NS |
9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
dfc130f3 | 13 | * |
da23017d NS |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
e246ba5f | 17 | */ |
dfc130f3 | 18 | |
dcabd4e7 | 19 | #include "platform_defs.h" |
6b803e5a | 20 | #include "input.h" |
fd2d0648 | 21 | #include <ctype.h> |
fd537fc5 | 22 | #include <stdbool.h> |
e246ba5f | 23 | |
d4b9ebda | 24 | #if defined(ENABLE_READLINE) |
e246ba5f NS |
25 | # include <readline/history.h> |
26 | # include <readline/readline.h> | |
d4b9ebda NS |
27 | #elif defined(ENABLE_EDITLINE) |
28 | # include <histedit.h> | |
29 | #endif | |
30 | ||
2a1888c5 NS |
31 | extern char *progname; |
32 | ||
d4b9ebda NS |
33 | static char * |
34 | get_prompt(void) | |
35 | { | |
3d93ccb7 | 36 | static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; |
d4b9ebda NS |
37 | |
38 | if (!prompt[0]) | |
39 | snprintf(prompt, sizeof(prompt), "%s> ", progname); | |
40 | return prompt; | |
41 | } | |
42 | ||
43 | #if defined(ENABLE_READLINE) | |
44 | char * | |
45 | fetchline(void) | |
46 | { | |
47 | char *line; | |
48 | ||
49 | line = readline(get_prompt()); | |
50 | if (line && *line) | |
51 | add_history(line); | |
52 | return line; | |
53 | } | |
54 | #elif defined(ENABLE_EDITLINE) | |
55 | static char *el_get_prompt(EditLine *e) { return get_prompt(); } | |
56 | char * | |
57 | fetchline(void) | |
58 | { | |
59 | static EditLine *el; | |
60 | static History *hist; | |
61 | HistEvent hevent; | |
62 | char *line; | |
63 | int count; | |
64 | ||
65 | if (!el) { | |
66 | hist = history_init(); | |
67 | history(hist, &hevent, H_SETSIZE, 100); | |
68 | el = el_init(progname, stdin, stdout, stderr); | |
69 | el_source(el, NULL); | |
70 | el_set(el, EL_SIGNAL, 1); | |
71 | el_set(el, EL_PROMPT, el_get_prompt); | |
72 | el_set(el, EL_HIST, history, (const char *)hist); | |
73 | } | |
74 | line = strdup(el_gets(el, &count)); | |
75 | if (line) { | |
76 | if (count > 0) | |
77 | line[count-1] = '\0'; | |
78 | if (*line) | |
79 | history(hist, &hevent, H_ENTER, line); | |
80 | } | |
81 | return line; | |
82 | } | |
e246ba5f NS |
83 | #else |
84 | # define MAXREADLINESZ 1024 | |
d4b9ebda NS |
85 | char * |
86 | fetchline(void) | |
e246ba5f NS |
87 | { |
88 | char *p, *line = malloc(MAXREADLINESZ); | |
89 | ||
90 | if (!line) | |
91 | return NULL; | |
50a3aa89 | 92 | printf("%s", get_prompt()); |
e246ba5f NS |
93 | fflush(stdout); |
94 | if (!fgets(line, MAXREADLINESZ, stdin)) { | |
95 | free(line); | |
96 | return NULL; | |
97 | } | |
98 | p = line + strlen(line); | |
99 | if (p != line && p[-1] == '\n') | |
100 | p[-1] = '\0'; | |
101 | return line; | |
102 | } | |
e246ba5f NS |
103 | #endif |
104 | ||
e246ba5f NS |
105 | char ** |
106 | breakline( | |
107 | char *input, | |
108 | int *count) | |
109 | { | |
110 | int c = 0; | |
111 | char *p; | |
112 | char **rval = calloc(sizeof(char *), 1); | |
113 | ||
3d93ccb7 | 114 | while (rval && (p = strsep(&input, " ")) != NULL) { |
e246ba5f NS |
115 | if (!*p) |
116 | continue; | |
117 | c++; | |
118 | rval = realloc(rval, sizeof(*rval) * (c + 1)); | |
3d93ccb7 NS |
119 | if (!rval) { |
120 | c = 0; | |
121 | break; | |
122 | } | |
e246ba5f NS |
123 | rval[c - 1] = p; |
124 | rval[c] = NULL; | |
125 | } | |
126 | *count = c; | |
127 | return rval; | |
128 | } | |
129 | ||
130 | void | |
131 | doneline( | |
132 | char *input, | |
133 | char **vec) | |
134 | { | |
135 | free(input); | |
136 | free(vec); | |
137 | } | |
638473d8 | 138 | |
92d9b902 NS |
139 | #define EXABYTES(x) ((long long)(x) << 60) |
140 | #define PETABYTES(x) ((long long)(x) << 50) | |
141 | #define TERABYTES(x) ((long long)(x) << 40) | |
142 | #define GIGABYTES(x) ((long long)(x) << 30) | |
143 | #define MEGABYTES(x) ((long long)(x) << 20) | |
144 | #define KILOBYTES(x) ((long long)(x) << 10) | |
145 | ||
638473d8 NS |
146 | long long |
147 | cvtnum( | |
2c2f6d79 NS |
148 | size_t blocksize, |
149 | size_t sectorsize, | |
638473d8 NS |
150 | char *s) |
151 | { | |
152 | long long i; | |
153 | char *sp; | |
d347f827 | 154 | int c; |
638473d8 NS |
155 | |
156 | i = strtoll(s, &sp, 0); | |
157 | if (i == 0 && sp == s) | |
158 | return -1LL; | |
159 | if (*sp == '\0') | |
160 | return i; | |
161 | ||
f63b46a2 | 162 | if (sp[1] != '\0') |
d347f827 NS |
163 | return -1LL; |
164 | ||
165 | c = tolower(*sp); | |
166 | switch (c) { | |
167 | case 'b': | |
638473d8 | 168 | return i * blocksize; |
d347f827 | 169 | case 's': |
638473d8 | 170 | return i * sectorsize; |
d347f827 | 171 | case 'k': |
92d9b902 | 172 | return KILOBYTES(i); |
d347f827 | 173 | case 'm': |
92d9b902 | 174 | return MEGABYTES(i); |
d347f827 | 175 | case 'g': |
92d9b902 | 176 | return GIGABYTES(i); |
d347f827 | 177 | case 't': |
92d9b902 | 178 | return TERABYTES(i); |
d347f827 | 179 | case 'p': |
92d9b902 | 180 | return PETABYTES(i); |
d347f827 | 181 | case 'e': |
92d9b902 | 182 | return EXABYTES(i); |
d347f827 | 183 | } |
638473d8 NS |
184 | return -1LL; |
185 | } | |
92d9b902 NS |
186 | |
187 | #define TO_EXABYTES(x) ((x) / EXABYTES(1)) | |
188 | #define TO_PETABYTES(x) ((x) / PETABYTES(1)) | |
189 | #define TO_TERABYTES(x) ((x) / TERABYTES(1)) | |
190 | #define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) | |
191 | #define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) | |
192 | #define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) | |
193 | ||
194 | void | |
195 | cvtstr( | |
196 | double value, | |
197 | char *str, | |
198 | size_t size) | |
199 | { | |
200 | char *fmt; | |
201 | int precise; | |
202 | ||
203 | precise = ((double)value * 1000 == (double)(int)value * 1000); | |
204 | ||
205 | if (value >= EXABYTES(1)) { | |
206 | fmt = precise ? "%.f EiB" : "%.3f EiB"; | |
207 | snprintf(str, size, fmt, TO_EXABYTES(value)); | |
208 | } else if (value >= PETABYTES(1)) { | |
209 | fmt = precise ? "%.f PiB" : "%.3f PiB"; | |
210 | snprintf(str, size, fmt, TO_PETABYTES(value)); | |
211 | } else if (value >= TERABYTES(1)) { | |
212 | fmt = precise ? "%.f TiB" : "%.3f TiB"; | |
213 | snprintf(str, size, fmt, TO_TERABYTES(value)); | |
214 | } else if (value >= GIGABYTES(1)) { | |
215 | fmt = precise ? "%.f GiB" : "%.3f GiB"; | |
216 | snprintf(str, size, fmt, TO_GIGABYTES(value)); | |
217 | } else if (value >= MEGABYTES(1)) { | |
218 | fmt = precise ? "%.f MiB" : "%.3f MiB"; | |
219 | snprintf(str, size, fmt, TO_MEGABYTES(value)); | |
220 | } else if (value >= KILOBYTES(1)) { | |
221 | fmt = precise ? "%.f KiB" : "%.3f KiB"; | |
222 | snprintf(str, size, fmt, TO_KILOBYTES(value)); | |
223 | } else { | |
224 | snprintf(str, size, "%f bytes", value); | |
225 | } | |
226 | } | |
227 | ||
3d93ccb7 NS |
228 | #define MINUTES_TO_SECONDS(m) ((m) * 60) |
229 | #define HOURS_TO_SECONDS(h) ((h) * MINUTES_TO_SECONDS(60)) | |
230 | #define DAYS_TO_SECONDS(d) ((d) * HOURS_TO_SECONDS(24)) | |
231 | #define WEEKS_TO_SECONDS(w) ((w) * DAYS_TO_SECONDS(7)) | |
232 | ||
233 | unsigned long | |
234 | cvttime( | |
235 | char *s) | |
236 | { | |
237 | unsigned long i; | |
238 | char *sp; | |
239 | ||
240 | i = strtoul(s, &sp, 0); | |
241 | if (i == 0 && sp == s) | |
242 | return 0; | |
243 | if (*sp == '\0') | |
244 | return i; | |
245 | if ((*sp == 'm' && sp[1] == '\0') || | |
246 | (strcmp(sp, "minutes") == 0) || | |
247 | (strcmp(sp, "minute") == 0)) | |
248 | return MINUTES_TO_SECONDS(i); | |
249 | if ((*sp == 'h' && sp[1] == '\0') || | |
250 | (strcmp(sp, "hours") == 0) || | |
251 | (strcmp(sp, "hour") == 0)) | |
252 | return HOURS_TO_SECONDS(i); | |
253 | if ((*sp == 'd' && sp[1] == '\0') || | |
254 | (strcmp(sp, "days") == 0) || | |
255 | (strcmp(sp, "day") == 0)) | |
256 | return DAYS_TO_SECONDS(i); | |
257 | if ((*sp == 'w' && sp[1] == '\0') || | |
258 | (strcmp(sp, "weeks") == 0) || | |
259 | (strcmp(sp, "week") == 0)) | |
260 | return WEEKS_TO_SECONDS(i); | |
261 | return 0; | |
262 | } | |
263 | ||
264 | struct timeval | |
265 | tadd(struct timeval t1, struct timeval t2) | |
266 | { | |
267 | t1.tv_usec += t2.tv_usec; | |
268 | if (t1.tv_usec > 1000000) { | |
269 | t1.tv_usec -= 1000000; | |
270 | t1.tv_sec++; | |
271 | } | |
272 | t1.tv_sec += t2.tv_sec; | |
273 | return t1; | |
274 | } | |
275 | ||
92d9b902 NS |
276 | struct timeval |
277 | tsub(struct timeval t1, struct timeval t2) | |
278 | { | |
279 | t1.tv_usec -= t2.tv_usec; | |
280 | if (t1.tv_usec < 0) { | |
281 | t1.tv_usec += 1000000; | |
282 | t1.tv_sec--; | |
283 | } | |
284 | t1.tv_sec -= t2.tv_sec; | |
285 | return t1; | |
286 | } | |
287 | ||
288 | double | |
289 | tdiv(double value, struct timeval tv) | |
290 | { | |
291 | return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); | |
292 | } | |
293 | ||
294 | #define HOURS(sec) ((sec) / (60 * 60)) | |
295 | #define MINUTES(sec) (((sec) % (60 * 60)) / 60) | |
296 | #define SECONDS(sec) ((sec) % 60) | |
297 | ||
298 | void | |
299 | timestr( | |
300 | struct timeval *tv, | |
301 | char *ts, | |
5c7bef67 NS |
302 | size_t size, |
303 | int format) | |
92d9b902 | 304 | { |
5c7bef67 NS |
305 | double usec = (double)tv->tv_usec / 1000000.0; |
306 | ||
307 | if (format & TERSE_FIXED_TIME) { | |
308 | if (!HOURS(tv->tv_sec)) { | |
309 | snprintf(ts, size, "%u:%02u.%02u", | |
310 | (unsigned int) MINUTES(tv->tv_sec), | |
311 | (unsigned int) SECONDS(tv->tv_sec), | |
312 | (unsigned int) usec * 100); | |
313 | return; | |
314 | } | |
315 | format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ | |
316 | } | |
317 | ||
318 | if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { | |
319 | snprintf(ts, size, "%u:%02u:%02u.%02u", | |
92d9b902 NS |
320 | (unsigned int) HOURS(tv->tv_sec), |
321 | (unsigned int) MINUTES(tv->tv_sec), | |
322 | (unsigned int) SECONDS(tv->tv_sec), | |
5c7bef67 NS |
323 | (unsigned int) usec * 100); |
324 | } else { | |
325 | snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000); | |
326 | } | |
92d9b902 | 327 | } |
3d93ccb7 | 328 | |
8211d1b5 DD |
329 | /* |
330 | * Convert from a pair of arbitrary user strings into a timespec. | |
331 | */ | |
332 | ||
333 | int | |
334 | timespec_from_string( | |
335 | const char * secs, | |
336 | const char * nsecs, | |
337 | struct timespec * ts) | |
338 | { | |
339 | char* p; | |
340 | if (!secs || !nsecs || !ts) | |
341 | return 1; | |
342 | ts->tv_sec = strtoull(secs, &p, 0); | |
343 | if (*p) | |
344 | return 1; | |
345 | ts->tv_nsec = strtoull(nsecs, &p, 0); | |
346 | if (*p) | |
347 | return 1; | |
348 | return 0; | |
349 | } | |
350 | ||
3d93ccb7 NS |
351 | /* |
352 | * Convert from arbitrary user strings into a numeric ID. | |
ff1f79a7 | 353 | * If it's all numeric, we convert that inplace, else we do |
3d93ccb7 NS |
354 | * the name lookup, and return the found identifier. |
355 | */ | |
356 | ||
357 | prid_t | |
358 | prid_from_string( | |
359 | char *project) | |
360 | { | |
361 | fs_project_t *prj; | |
272f4db5 | 362 | unsigned long prid_long; |
3d93ccb7 NS |
363 | char *sp; |
364 | ||
1d9d5700 LB |
365 | /* |
366 | * Allow either a full numeric or a valid projectname, even | |
367 | * if it starts with a digit. | |
368 | */ | |
272f4db5 AM |
369 | prid_long = strtoul(project, &sp, 10); |
370 | if (*project != '\0' && *sp == '\0') { | |
371 | if ((prid_long == ULONG_MAX && errno == ERANGE) | |
372 | || (prid_long > (prid_t)-1)) | |
373 | return -1; | |
374 | return (prid_t)prid_long; | |
375 | } | |
3d93ccb7 NS |
376 | prj = getprnam(project); |
377 | if (prj) | |
378 | return prj->pr_prid; | |
379 | return -1; | |
380 | } | |
381 | ||
382 | uid_t | |
383 | uid_from_string( | |
384 | char *user) | |
385 | { | |
386 | struct passwd *pwd; | |
272f4db5 | 387 | unsigned long uid_long; |
3d93ccb7 NS |
388 | char *sp; |
389 | ||
272f4db5 | 390 | uid_long = strtoul(user, &sp, 10); |
cef37d5a | 391 | if (sp != user && *sp == '\0') { |
272f4db5 AM |
392 | if ((uid_long == ULONG_MAX && errno == ERANGE) |
393 | || (uid_long > (uid_t)-1)) | |
394 | return -1; | |
395 | return (uid_t)uid_long; | |
396 | } | |
3d93ccb7 NS |
397 | pwd = getpwnam(user); |
398 | if (pwd) | |
399 | return pwd->pw_uid; | |
400 | return -1; | |
401 | } | |
402 | ||
403 | gid_t | |
404 | gid_from_string( | |
405 | char *group) | |
406 | { | |
407 | struct group *grp; | |
272f4db5 | 408 | unsigned long gid_long; |
3d93ccb7 NS |
409 | char *sp; |
410 | ||
272f4db5 | 411 | gid_long = strtoul(group, &sp, 10); |
cef37d5a | 412 | if (sp != group && *sp == '\0') { |
272f4db5 AM |
413 | if ((gid_long == ULONG_MAX && errno == ERANGE) |
414 | || (gid_long > (gid_t)-1)) | |
415 | return -1; | |
416 | return (gid_t)gid_long; | |
417 | } | |
3d93ccb7 NS |
418 | grp = getgrnam(group); |
419 | if (grp) | |
420 | return grp->gr_gid; | |
421 | return -1; | |
422 | } | |
423 | ||
fd537fc5 RJ |
424 | bool isdigits_only( |
425 | const char *str) | |
426 | { | |
427 | int i; | |
428 | ||
429 | for (i = 0; i < strlen(str); i++) { | |
430 | if (!isdigit(str[i])) | |
431 | return false; | |
432 | } | |
433 | return true; | |
434 | } | |
435 | ||
3d93ccb7 NS |
436 | #define HAVE_FTW_H 1 /* TODO: configure me */ |
437 | ||
438 | #ifndef HAVE_FTW_H | |
439 | int | |
440 | nftw( | |
441 | char *dir, | |
442 | int (*fn)(const char *, const struct stat *, int, struct FTW *), | |
443 | int depth, | |
444 | int flags) | |
445 | { | |
446 | fprintf(stderr, "%s: not implemented, no recursion available\n", | |
447 | __FUNCTION__); | |
448 | return 0; | |
449 | } | |
450 | #endif |