]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxcmd/input.c
xfs_quota: fix input of a projectid which starts whith a digit
[thirdparty/xfsprogs-dev.git] / libxcmd / input.c
1 /*
2 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
17 */
18
19 #include <xfs/xfs.h>
20 #include <xfs/input.h>
21 #include <ctype.h>
22
23 #if defined(ENABLE_READLINE)
24 # include <readline/history.h>
25 # include <readline/readline.h>
26 #elif defined(ENABLE_EDITLINE)
27 # include <histedit.h>
28 #endif
29
30 extern char *progname;
31
32 static char *
33 get_prompt(void)
34 {
35 static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
36
37 if (!prompt[0])
38 snprintf(prompt, sizeof(prompt), "%s> ", progname);
39 return prompt;
40 }
41
42 #if defined(ENABLE_READLINE)
43 char *
44 fetchline(void)
45 {
46 char *line;
47
48 line = readline(get_prompt());
49 if (line && *line)
50 add_history(line);
51 return line;
52 }
53 #elif defined(ENABLE_EDITLINE)
54 static char *el_get_prompt(EditLine *e) { return get_prompt(); }
55 char *
56 fetchline(void)
57 {
58 static EditLine *el;
59 static History *hist;
60 HistEvent hevent;
61 char *line;
62 int count;
63
64 if (!el) {
65 hist = history_init();
66 history(hist, &hevent, H_SETSIZE, 100);
67 el = el_init(progname, stdin, stdout, stderr);
68 el_source(el, NULL);
69 el_set(el, EL_SIGNAL, 1);
70 el_set(el, EL_PROMPT, el_get_prompt);
71 el_set(el, EL_HIST, history, (const char *)hist);
72 }
73 line = strdup(el_gets(el, &count));
74 if (line) {
75 if (count > 0)
76 line[count-1] = '\0';
77 if (*line)
78 history(hist, &hevent, H_ENTER, line);
79 }
80 return line;
81 }
82 #else
83 # define MAXREADLINESZ 1024
84 char *
85 fetchline(void)
86 {
87 char *p, *line = malloc(MAXREADLINESZ);
88
89 if (!line)
90 return NULL;
91 printf(get_prompt());
92 fflush(stdout);
93 if (!fgets(line, MAXREADLINESZ, stdin)) {
94 free(line);
95 return NULL;
96 }
97 p = line + strlen(line);
98 if (p != line && p[-1] == '\n')
99 p[-1] = '\0';
100 return line;
101 }
102 #endif
103
104 char **
105 breakline(
106 char *input,
107 int *count)
108 {
109 int c = 0;
110 char *p;
111 char **rval = calloc(sizeof(char *), 1);
112
113 while (rval && (p = strsep(&input, " ")) != NULL) {
114 if (!*p)
115 continue;
116 c++;
117 rval = realloc(rval, sizeof(*rval) * (c + 1));
118 if (!rval) {
119 c = 0;
120 break;
121 }
122 rval[c - 1] = p;
123 rval[c] = NULL;
124 }
125 *count = c;
126 return rval;
127 }
128
129 void
130 doneline(
131 char *input,
132 char **vec)
133 {
134 free(input);
135 free(vec);
136 }
137
138 #define EXABYTES(x) ((long long)(x) << 60)
139 #define PETABYTES(x) ((long long)(x) << 50)
140 #define TERABYTES(x) ((long long)(x) << 40)
141 #define GIGABYTES(x) ((long long)(x) << 30)
142 #define MEGABYTES(x) ((long long)(x) << 20)
143 #define KILOBYTES(x) ((long long)(x) << 10)
144
145 long long
146 cvtnum(
147 size_t blocksize,
148 size_t sectorsize,
149 char *s)
150 {
151 long long i;
152 char *sp;
153 int c;
154
155 i = strtoll(s, &sp, 0);
156 if (i == 0 && sp == s)
157 return -1LL;
158 if (*sp == '\0')
159 return i;
160
161 if (sp[1] != '\0')
162 return -1LL;
163
164 c = tolower(*sp);
165 switch (c) {
166 case 'b':
167 return i * blocksize;
168 case 's':
169 return i * sectorsize;
170 case 'k':
171 return KILOBYTES(i);
172 case 'm':
173 return MEGABYTES(i);
174 case 'g':
175 return GIGABYTES(i);
176 case 't':
177 return TERABYTES(i);
178 case 'p':
179 return PETABYTES(i);
180 case 'e':
181 return EXABYTES(i);
182 }
183 return -1LL;
184 }
185
186 #define TO_EXABYTES(x) ((x) / EXABYTES(1))
187 #define TO_PETABYTES(x) ((x) / PETABYTES(1))
188 #define TO_TERABYTES(x) ((x) / TERABYTES(1))
189 #define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
190 #define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
191 #define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
192
193 void
194 cvtstr(
195 double value,
196 char *str,
197 size_t size)
198 {
199 char *fmt;
200 int precise;
201
202 precise = ((double)value * 1000 == (double)(int)value * 1000);
203
204 if (value >= EXABYTES(1)) {
205 fmt = precise ? "%.f EiB" : "%.3f EiB";
206 snprintf(str, size, fmt, TO_EXABYTES(value));
207 } else if (value >= PETABYTES(1)) {
208 fmt = precise ? "%.f PiB" : "%.3f PiB";
209 snprintf(str, size, fmt, TO_PETABYTES(value));
210 } else if (value >= TERABYTES(1)) {
211 fmt = precise ? "%.f TiB" : "%.3f TiB";
212 snprintf(str, size, fmt, TO_TERABYTES(value));
213 } else if (value >= GIGABYTES(1)) {
214 fmt = precise ? "%.f GiB" : "%.3f GiB";
215 snprintf(str, size, fmt, TO_GIGABYTES(value));
216 } else if (value >= MEGABYTES(1)) {
217 fmt = precise ? "%.f MiB" : "%.3f MiB";
218 snprintf(str, size, fmt, TO_MEGABYTES(value));
219 } else if (value >= KILOBYTES(1)) {
220 fmt = precise ? "%.f KiB" : "%.3f KiB";
221 snprintf(str, size, fmt, TO_KILOBYTES(value));
222 } else {
223 snprintf(str, size, "%f bytes", value);
224 }
225 }
226
227 #define MINUTES_TO_SECONDS(m) ((m) * 60)
228 #define HOURS_TO_SECONDS(h) ((h) * MINUTES_TO_SECONDS(60))
229 #define DAYS_TO_SECONDS(d) ((d) * HOURS_TO_SECONDS(24))
230 #define WEEKS_TO_SECONDS(w) ((w) * DAYS_TO_SECONDS(7))
231
232 unsigned long
233 cvttime(
234 char *s)
235 {
236 unsigned long i;
237 char *sp;
238
239 i = strtoul(s, &sp, 0);
240 if (i == 0 && sp == s)
241 return 0;
242 if (*sp == '\0')
243 return i;
244 if ((*sp == 'm' && sp[1] == '\0') ||
245 (strcmp(sp, "minutes") == 0) ||
246 (strcmp(sp, "minute") == 0))
247 return MINUTES_TO_SECONDS(i);
248 if ((*sp == 'h' && sp[1] == '\0') ||
249 (strcmp(sp, "hours") == 0) ||
250 (strcmp(sp, "hour") == 0))
251 return HOURS_TO_SECONDS(i);
252 if ((*sp == 'd' && sp[1] == '\0') ||
253 (strcmp(sp, "days") == 0) ||
254 (strcmp(sp, "day") == 0))
255 return DAYS_TO_SECONDS(i);
256 if ((*sp == 'w' && sp[1] == '\0') ||
257 (strcmp(sp, "weeks") == 0) ||
258 (strcmp(sp, "week") == 0))
259 return WEEKS_TO_SECONDS(i);
260 return 0;
261 }
262
263 struct timeval
264 tadd(struct timeval t1, struct timeval t2)
265 {
266 t1.tv_usec += t2.tv_usec;
267 if (t1.tv_usec > 1000000) {
268 t1.tv_usec -= 1000000;
269 t1.tv_sec++;
270 }
271 t1.tv_sec += t2.tv_sec;
272 return t1;
273 }
274
275 struct timeval
276 tsub(struct timeval t1, struct timeval t2)
277 {
278 t1.tv_usec -= t2.tv_usec;
279 if (t1.tv_usec < 0) {
280 t1.tv_usec += 1000000;
281 t1.tv_sec--;
282 }
283 t1.tv_sec -= t2.tv_sec;
284 return t1;
285 }
286
287 double
288 tdiv(double value, struct timeval tv)
289 {
290 return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
291 }
292
293 #define HOURS(sec) ((sec) / (60 * 60))
294 #define MINUTES(sec) (((sec) % (60 * 60)) / 60)
295 #define SECONDS(sec) ((sec) % 60)
296
297 void
298 timestr(
299 struct timeval *tv,
300 char *ts,
301 size_t size,
302 int format)
303 {
304 double usec = (double)tv->tv_usec / 1000000.0;
305
306 if (format & TERSE_FIXED_TIME) {
307 if (!HOURS(tv->tv_sec)) {
308 snprintf(ts, size, "%u:%02u.%02u",
309 (unsigned int) MINUTES(tv->tv_sec),
310 (unsigned int) SECONDS(tv->tv_sec),
311 (unsigned int) usec * 100);
312 return;
313 }
314 format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
315 }
316
317 if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
318 snprintf(ts, size, "%u:%02u:%02u.%02u",
319 (unsigned int) HOURS(tv->tv_sec),
320 (unsigned int) MINUTES(tv->tv_sec),
321 (unsigned int) SECONDS(tv->tv_sec),
322 (unsigned int) usec * 100);
323 } else {
324 snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000);
325 }
326 }
327
328 /*
329 * Convert from arbitrary user strings into a numeric ID.
330 * If its all numeric, we convert that inplace, else we do
331 * the name lookup, and return the found identifier.
332 */
333
334 prid_t
335 prid_from_string(
336 char *project)
337 {
338 fs_project_t *prj;
339 prid_t prid;
340 char *sp;
341
342 /*
343 * Allow either a full numeric or a valid projectname, even
344 * if it starts with a digit.
345 */
346 prid = (prid_t)strtoul(project, &sp, 10);
347 if (*project != '\0' && *sp == '\0')
348 return prid;
349 prj = getprnam(project);
350 if (prj)
351 return prj->pr_prid;
352 return -1;
353 }
354
355 uid_t
356 uid_from_string(
357 char *user)
358 {
359 struct passwd *pwd;
360 uid_t uid;
361 char *sp;
362
363 uid = (uid_t)strtoul(user, &sp, 10);
364 if (sp != user)
365 return uid;
366 pwd = getpwnam(user);
367 if (pwd)
368 return pwd->pw_uid;
369 return -1;
370 }
371
372 gid_t
373 gid_from_string(
374 char *group)
375 {
376 struct group *grp;
377 gid_t gid;
378 char *sp;
379
380 gid = (gid_t)strtoul(group, &sp, 10);
381 if (sp != group)
382 return gid;
383 grp = getgrnam(group);
384 if (grp)
385 return grp->gr_gid;
386 return -1;
387 }
388
389 #define HAVE_FTW_H 1 /* TODO: configure me */
390
391 #ifndef HAVE_FTW_H
392 int
393 nftw(
394 char *dir,
395 int (*fn)(const char *, const struct stat *, int, struct FTW *),
396 int depth,
397 int flags)
398 {
399 fprintf(stderr, "%s: not implemented, no recursion available\n",
400 __FUNCTION__);
401 return 0;
402 }
403 #endif