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