1 /*
2 * lib.c
3 * Global utility functions.
4 *
5 * Copyright (c) 2003-2006 Christoph Pfisterer
6 *
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation
9 * files (the "Software"), to deal in the Software without
10 * restriction, including without limitation the rights to use, copy,
11 * modify, merge, publish, distribute, sublicense, and/or sell copies
12 * of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28 #include "global.h"
29 #include <stdarg.h>
30
31 /*
32 * output functions
33 */
34
35 #define LEVELS (8)
36
37 static const char *insets[LEVELS] = {
38 "",
39 " ",
40 " ",
41 " ",
42 " ",
43 " ",
44 " ",
45 " ",
46 };
47 static char line_akku[4096];
48
print_line(int level,const char * fmt,...)49 void print_line(int level, const char *fmt, ...)
50 {
51 va_list par;
52
53 va_start(par, fmt);
54 vsnprintf(line_akku, 4096, fmt, par);
55 va_end(par);
56
57 if (level >= LEVELS)
58 bailout("Recursion loop caught");
59 printf("%s%s\n", insets[level], line_akku);
60 }
61
start_line(const char * fmt,...)62 void start_line(const char *fmt, ...)
63 {
64 va_list par;
65
66 va_start(par, fmt);
67 vsnprintf(line_akku, 4096, fmt, par);
68 va_end(par);
69 }
70
continue_line(const char * fmt,...)71 void continue_line(const char *fmt, ...)
72 {
73 va_list par;
74 int len = strlen(line_akku);
75
76 va_start(par, fmt);
77 vsnprintf(line_akku + len, 4096 - len, fmt, par);
78 va_end(par);
79 }
80
finish_line(int level)81 void finish_line(int level)
82 {
83 if (level >= LEVELS)
84 bailout("Recursion loop caught");
85 printf("%s%s\n", insets[level], line_akku);
86 }
87
88 /*
89 * formatting functions
90 */
91
92 /* TODO: make all of this safe from buffer overruns... */
93
94 /*
95 * format_raw_size() does the actual unit-suffix formatting.
96 *
97 * Returns an indicator for the format used:
98 * 0 - rounded to some unit
99 * 1 - whole multiple of some unit (return code limited to KiB)
100 * 2 - plain bytes
101 */
102
format_raw_size(char * buf,u8 size)103 static int format_raw_size(char *buf, u8 size)
104 {
105 int unit_index, dd;
106 u8 unit_size, card;
107 const char *unit_names[] =
108 { "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", NULL };
109 const int dd_mult[4] = { 1, 10, 100, 1000 };
110
111 /* just a few bytes */
112 if (size < 1024) {
113 sprintf(buf, "%llu bytes", size);
114 return 2;
115 }
116
117 /* find a suitable unit */
118 for (unit_index = 0, unit_size = 1024;
119 unit_names[unit_index] != NULL;
120 unit_index++, unit_size <<= 10) {
121
122 /* size is at least one of the next unit -> use that */
123 if (size >= 1024 * unit_size)
124 continue;
125
126 /* check integral multiples */
127 if ((size % unit_size) == 0) {
128 card = size / unit_size;
129 sprintf(buf, "%d %s",
130 (int)card,
131 unit_names[unit_index]);
132 return unit_index ? 0 : 1;
133 }
134
135 /* find suitable number of decimal digits */
136 for (dd = 3; dd >= 1; dd--) {
137 card = (size * dd_mult[dd] + (unit_size >> 1)) / unit_size;
138 if (card >= 10000)
139 continue; /* more than four significant digits */
140
141 sprintf(buf, "%d.%0*d %s",
142 (int)(card / dd_mult[dd]),
143 dd, (int)(card % dd_mult[dd]),
144 unit_names[unit_index]);
145 return 0;
146 }
147 }
148
149 /* fallback (something wrong with the numbers?) */
150 strcpy(buf, "off the scale");
151 return 0;
152 }
153
format_blocky_size(char * buf,u8 count,u4 blocksize,const char * blockname,const char * append)154 void format_blocky_size(char *buf, u8 count, u4 blocksize,
155 const char *blockname, const char *append)
156 {
157 int used;
158 u8 total_size;
159 char *p;
160 char blocksizebuf[32];
161
162 total_size = count * blocksize;
163 used = format_raw_size(buf, total_size);
164 p = strchr(buf, 0);
165
166 *p++ = ' ';
167 *p++ = '(';
168
169 if (used != 2) {
170 sprintf(p, "%llu bytes, ", total_size);
171 p = strchr(buf, 0);
172 }
173
174 if (blocksize == 512 && strcmp(blockname, "sectors") == 0) {
175 sprintf(p, "%llu %s", count, blockname);
176 } else {
177 if (blocksize < 64*1024 && (blocksize % 1024) != 0)
178 sprintf(blocksizebuf, "%lu bytes", blocksize);
179 else
180 format_raw_size(blocksizebuf, blocksize);
181 sprintf(p, "%llu %s of %s", count, blockname, blocksizebuf);
182 }
183 p = strchr(buf, 0);
184
185 if (append != NULL) {
186 strcpy(p, append);
187 p = strchr(buf, 0);
188 }
189
190 *p++ = ')';
191 *p++ = 0;
192 }
193
format_size(char * buf,u8 size)194 void format_size(char *buf, u8 size)
195 {
196 int used;
197
198 used = format_raw_size(buf, size);
199 if (used > 0)
200 return;
201
202 sprintf(strchr(buf, 0), " (%llu bytes)", size);
203 }
204
format_size_verbose(char * buf,u8 size)205 void format_size_verbose(char *buf, u8 size)
206 {
207 int used;
208
209 used = format_raw_size(buf, size);
210 if (used == 2)
211 return;
212
213 sprintf(strchr(buf, 0), " (%llu bytes)", size);
214 }
215
format_ascii(void * from,char * to)216 void format_ascii(void *from, char *to)
217 {
218 u1 *p = (u1 *)from;
219 u1 *q = (u1 *)to;
220 int c;
221
222 while ((c = *p++)) {
223 if (c >= 127 || c < 32) {
224 *q++ = '<';
225 *q++ = "0123456789ABCDEF"[c >> 4];
226 *q++ = "0123456789ABCDEF"[c & 15];
227 *q++ = '>';
228 } else {
229 *q++ = c;
230 }
231 }
232 *q = 0;
233 }
234
format_utf16_be(void * from,u4 len,char * to)235 void format_utf16_be(void *from, u4 len, char *to)
236 {
237 u2 *p = (u2 *)from;
238 u2 *p_end;
239 u1 *q = (u1 *)to;
240 u2 c;
241
242 if (len)
243 p_end = (u2 *)(((u1 *)from) + len);
244 else
245 p_end = NULL;
246
247 while (p_end == NULL || p < p_end) {
248 c = get_be_short(p);
249 if (c == 0)
250 break;
251 p++; /* advance 2 bytes */
252
253 if (c >= 127 || c < 32) {
254 *q++ = '<';
255 *q++ = "0123456789ABCDEF"[c >> 12];
256 *q++ = "0123456789ABCDEF"[(c >> 8) & 15];
257 *q++ = "0123456789ABCDEF"[(c >> 4) & 15];
258 *q++ = "0123456789ABCDEF"[c & 15];
259 *q++ = '>';
260 } else {
261 *q++ = (u1)c;
262 }
263 }
264 *q = 0;
265 }
266
format_utf16_le(void * from,u4 len,char * to)267 void format_utf16_le(void *from, u4 len, char *to)
268 {
269 u2 *p = (u2 *)from;
270 u2 *p_end;
271 u1 *q = (u1 *)to;
272 u2 c;
273
274 if (len)
275 p_end = (u2 *)(((u1 *)from) + len);
276 else
277 p_end = NULL;
278
279 while (p_end == NULL || p < p_end) {
280 c = get_le_short(p);
281 if (c == 0)
282 break;
283 p++; /* advance 2 bytes */
284
285 if (c >= 127 || c < 32) {
286 *q++ = '<';
287 *q++ = "0123456789ABCDEF"[c >> 12];
288 *q++ = "0123456789ABCDEF"[(c >> 8) & 15];
289 *q++ = "0123456789ABCDEF"[(c >> 4) & 15];
290 *q++ = "0123456789ABCDEF"[c & 15];
291 *q++ = '>';
292 } else {
293 *q++ = (u1)c;
294 }
295 }
296 *q = 0;
297 }
298
format_uuid(void * uuid,char * to)299 void format_uuid(void *uuid, char *to)
300 {
301 u1 *from = uuid;
302 int i, c, variant, version;
303
304 if (memcmp(uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
305 strcpy(to, "nil");
306 return;
307 }
308
309 variant = from[8] >> 5;
310 version = from[6] >> 4;
311
312 for (i = 0; i < 16; i++) {
313 c = *from++;
314 *to++ = "0123456789ABCDEF"[c >> 4];
315 *to++ = "0123456789ABCDEF"[c & 15];
316 if (i == 3 || i == 5 || i == 7 || i == 9)
317 *to++ = '-';
318 }
319
320 if ((variant & 4) == 0) { /* 0 x x */
321 strcpy(to, " (NCS)");
322 } else if ((variant & 2) == 0) { /* 1 0 x */
323 sprintf(to, " (DCE, v%1.1d)", version);
324 } else if ((variant & 1) == 0) { /* 1 1 0 */
325 strcpy(to, " (MS GUID)");
326 } else { /* 1 1 1 */
327 strcpy(to, " (Reserved)");
328 }
329 }
330
format_uuid_lvm(void * uuid,char * to)331 void format_uuid_lvm(void *uuid, char *to)
332 {
333 char *from = uuid;
334 int i;
335
336 for (i = 0; i < 32; i++) {
337 *to++ = *from++;
338 if ((i & 3) == 1 && i > 1 && i < 29)
339 *to++ = '-';
340 }
341 *to = 0;
342 }
343
format_guid(void * guid,char * to)344 void format_guid(void *guid, char *to)
345 {
346 u1 *from = guid;
347 int i, c;
348
349 if (memcmp(guid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
350 strcpy(to, "nil");
351 return;
352 }
353
354 for (i = 0; i < 16; i++) {
355 c = *from++;
356 *to++ = "0123456789ABCDEF"[c >> 4];
357 *to++ = "0123456789ABCDEF"[c & 15];
358 if (i == 3 || i == 5 || i == 7 || i == 9)
359 *to++ = '-';
360 }
361 *to = 0;
362 }
363
364 /*
365 * endian-aware data access
366 */
367
get_be_short(void * from)368 u2 get_be_short(void *from)
369 {
370 u1 *p = from;
371 return ((u2)(p[0]) << 8) +
372 (u2)p[1];
373 }
374
get_be_long(void * from)375 u4 get_be_long(void *from)
376 {
377 u1 *p = from;
378 return ((u4)(p[0]) << 24) +
379 ((u4)(p[1]) << 16) +
380 ((u4)(p[2]) << 8) +
381 (u4)p[3];
382 }
383
get_be_quad(void * from)384 u8 get_be_quad(void *from)
385 {
386 u1 *p = from;
387 return ((u8)(p[0]) << 56) +
388 ((u8)(p[1]) << 48) +
389 ((u8)(p[2]) << 40) +
390 ((u8)(p[3]) << 32) +
391 ((u8)(p[4]) << 24) +
392 ((u8)(p[5]) << 16) +
393 ((u8)(p[6]) << 8) +
394 (u8)p[7];
395 }
396
get_le_short(void * from)397 u2 get_le_short(void *from)
398 {
399 u1 *p = from;
400 return ((u2)(p[1]) << 8) +
401 (u2)p[0];
402 }
403
get_le_long(void * from)404 u4 get_le_long(void *from)
405 {
406 u1 *p = from;
407 return ((u4)(p[3]) << 24) +
408 ((u4)(p[2]) << 16) +
409 ((u4)(p[1]) << 8) +
410 (u4)p[0];
411 }
412
get_le_quad(void * from)413 u8 get_le_quad(void *from)
414 {
415 u1 *p = from;
416 return ((u8)(p[7]) << 56) +
417 ((u8)(p[6]) << 48) +
418 ((u8)(p[5]) << 40) +
419 ((u8)(p[4]) << 32) +
420 ((u8)(p[3]) << 24) +
421 ((u8)(p[2]) << 16) +
422 ((u8)(p[1]) << 8) +
423 (u8)p[0];
424 }
425
get_ve_short(int endianness,void * from)426 u2 get_ve_short(int endianness, void *from)
427 {
428 if (endianness)
429 return get_le_short(from);
430 else
431 return get_be_short(from);
432 }
433
get_ve_long(int endianness,void * from)434 u4 get_ve_long(int endianness, void *from)
435 {
436 if (endianness)
437 return get_le_long(from);
438 else
439 return get_be_long(from);
440 }
441
get_ve_quad(int endianness,void * from)442 u8 get_ve_quad(int endianness, void *from)
443 {
444 if (endianness)
445 return get_le_quad(from);
446 else
447 return get_be_quad(from);
448 }
449
get_ve_name(int endianness)450 const char * get_ve_name(int endianness)
451 {
452 if (endianness)
453 return "little-endian";
454 else
455 return "big-endian";
456 }
457
458 /*
459 * more data access
460 */
461
get_string(void * from,int len,char * to)462 void get_string(void *from, int len, char *to)
463 {
464 if (len > 255)
465 len = 255;
466 memcpy(to, from, len);
467 to[len] = 0;
468 }
469
get_pstring(void * from,char * to)470 void get_pstring(void *from, char *to)
471 {
472 int len = *(unsigned char *)from;
473 memcpy(to, (char *)from + 1, len);
474 to[len] = 0;
475 }
476
get_padded_string(void * from,int len,char pad,char * to)477 void get_padded_string(void *from, int len, char pad, char *to)
478 {
479 int pos;
480
481 get_string(from, len, to);
482
483 for (pos = strlen(to) - 1; pos >= 0 && to[pos] == pad; pos--)
484 to[pos] = 0;
485 }
486
find_memory(void * haystack,int haystack_len,void * needle,int needle_len)487 int find_memory(void *haystack, int haystack_len,
488 void *needle, int needle_len)
489 {
490 int searchlen = haystack_len - needle_len + 1;
491 int pos = 0;
492 void *p;
493
494 while (pos < searchlen) {
495 p = memchr((char *)haystack + pos, *(unsigned char *)needle,
496 searchlen - pos);
497 if (p == NULL)
498 return -1;
499 pos = (char *)p - (char *)haystack;
500 if (memcmp(p, needle, needle_len) == 0)
501 return pos;
502 pos++;
503 }
504
505 return -1;
506 }
507
508 /*
509 * error functions
510 */
511
error(const char * msg,...)512 void error(const char *msg, ...)
513 {
514 va_list par;
515 char buf[4096];
516
517 va_start(par, msg);
518 vsnprintf(buf, 4096, msg, par);
519 va_end(par);
520
521 fprintf(stderr, PROGNAME ": %s\n", buf);
522 }
523
errore(const char * msg,...)524 void errore(const char *msg, ...)
525 {
526 va_list par;
527 char buf[4096];
528
529 va_start(par, msg);
530 vsnprintf(buf, 4096, msg, par);
531 va_end(par);
532
533 fprintf(stderr, PROGNAME ": %s: %s\n", buf, strerror(errno));
534 }
535
bailout(const char * msg,...)536 void bailout(const char *msg, ...)
537 {
538 va_list par;
539 char buf[4096];
540
541 va_start(par, msg);
542 vsnprintf(buf, 4096, msg, par);
543 va_end(par);
544
545 fprintf(stderr, PROGNAME ": %s\n", buf);
546 exit(1);
547 }
548
bailoute(const char * msg,...)549 void bailoute(const char *msg, ...)
550 {
551 va_list par;
552 char buf[4096];
553
554 va_start(par, msg);
555 vsnprintf(buf, 4096, msg, par);
556 va_end(par);
557
558 fprintf(stderr, PROGNAME ": %s: %s\n", buf, strerror(errno));
559 exit(1);
560 }
561
562 /* EOF */
563