1 /*
2  *  linux/lib/vsprintf.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6 
7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8 /*
9  * Wirzenius wrote this portably, Torvalds fucked it up :-)
10  */
11 
12 /*
13  * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
14  * - changed to provide snprintf and vsnprintf functions
15  * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
16  * - scnprintf and vscnprintf
17  */
18 
19 #include <xen/ctype.h>
20 #include <xen/symbols.h>
21 #include <xen/lib.h>
22 #include <xen/sched.h>
23 #include <xen/livepatch.h>
24 #include <asm/div64.h>
25 #include <asm/page.h>
26 
skip_atoi(const char ** s)27 static int skip_atoi(const char **s)
28 {
29     int i=0;
30 
31     while (isdigit(**s))
32         i = i*10 + *((*s)++) - '0';
33     return i;
34 }
35 
36 #define ZEROPAD 1               /* pad with zero */
37 #define SIGN    2               /* unsigned/signed long */
38 #define PLUS    4               /* show plus */
39 #define SPACE   8               /* space if plus */
40 #define LEFT    16              /* left justified */
41 #define SPECIAL 32              /* 0x */
42 #define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
43 
number(char * buf,const char * end,unsigned long long num,int base,int size,int precision,int type)44 static char *number(
45     char *buf, const char *end, unsigned long long num,
46     int base, int size, int precision, int type)
47 {
48     char c,sign,tmp[66];
49     const char *digits;
50     static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
51     static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
52     int i;
53 
54     ASSERT(base >= 2 && base <= 36);
55 
56     digits = (type & LARGE) ? large_digits : small_digits;
57     if (type & LEFT)
58         type &= ~ZEROPAD;
59     c = (type & ZEROPAD) ? '0' : ' ';
60     sign = 0;
61     if (type & SIGN) {
62         if ((signed long long) num < 0) {
63             sign = '-';
64             num = - (signed long long) num;
65             size--;
66         } else if (type & PLUS) {
67             sign = '+';
68             size--;
69         } else if (type & SPACE) {
70             sign = ' ';
71             size--;
72         }
73     }
74     if (type & SPECIAL) {
75         if (num == 0)
76             type &= ~SPECIAL;
77         else if (base == 16)
78             size -= 2;
79         else if (base == 8)
80             size--;
81         else
82             type &= ~SPECIAL;
83     }
84     i = 0;
85     if (num == 0)
86         tmp[i++]='0';
87     else while (num != 0)
88         tmp[i++] = digits[do_div(num,base)];
89     if (i > precision)
90         precision = i;
91     size -= precision;
92     if (!(type&(ZEROPAD+LEFT))) {
93         while(size-->0) {
94             if (buf < end)
95                 *buf = ' ';
96             ++buf;
97         }
98     }
99     if (sign) {
100         if (buf < end)
101             *buf = sign;
102         ++buf;
103     }
104     if (type & SPECIAL) {
105         if (buf < end)
106             *buf = '0';
107         ++buf;
108         if (base == 16) {
109             if (buf < end)
110                 *buf = digits[33];
111             ++buf;
112         }
113     }
114     if (!(type & LEFT)) {
115         while (size-- > 0) {
116             if (buf < end)
117                 *buf = c;
118             ++buf;
119         }
120     }
121     while (i < precision--) {
122         if (buf < end)
123             *buf = '0';
124         ++buf;
125     }
126     while (i-- > 0) {
127         if (buf < end)
128             *buf = tmp[i];
129         ++buf;
130     }
131     while (size-- > 0) {
132         if (buf < end)
133             *buf = ' ';
134         ++buf;
135     }
136     return buf;
137 }
138 
string(char * str,const char * end,const char * s,int field_width,int precision,int flags)139 static char *string(char *str, const char *end, const char *s,
140                     int field_width, int precision, int flags)
141 {
142     int i, len = (precision < 0) ? strlen(s) : strnlen(s, precision);
143 
144     if (!(flags & LEFT)) {
145         while (len < field_width--) {
146             if (str < end)
147                 *str = ' ';
148             ++str;
149         }
150     }
151     for (i = 0; i < len; ++i) {
152         if (str < end)
153             *str = *s;
154         ++str; ++s;
155     }
156     while (len < field_width--) {
157         if (str < end)
158             *str = ' ';
159         ++str;
160     }
161 
162     return str;
163 }
164 
165 /* Print a bitmap as '0-3,6-15' */
print_bitmap_list(char * str,const char * end,const unsigned long * bitmap,unsigned int nr_bits)166 static char *print_bitmap_list(char *str, const char *end,
167                                const unsigned long *bitmap,
168                                unsigned int nr_bits)
169 {
170     /* current bit is 'cur', most recently seen range is [rbot, rtop] */
171     unsigned int cur, rbot, rtop;
172     bool first = true;
173 
174     rbot = cur = find_first_bit(bitmap, nr_bits);
175     while ( cur < nr_bits )
176     {
177         rtop = cur;
178         cur = find_next_bit(bitmap, nr_bits, cur + 1);
179 
180         if ( cur < nr_bits && cur <= rtop + 1 )
181             continue;
182 
183         if ( !first )
184         {
185             if ( str < end )
186                 *str = ',';
187             str++;
188         }
189         first = false;
190 
191         str = number(str, end, rbot, 10, -1, -1, 0);
192         if ( rbot < rtop )
193         {
194             if ( str < end )
195                 *str = '-';
196             str++;
197 
198             str = number(str, end, rtop, 10, -1, -1, 0);
199         }
200 
201         rbot = cur;
202     }
203 
204     return str;
205 }
206 
207 /* Print a bitmap as a comma separated hex string. */
print_bitmap_string(char * str,const char * end,const unsigned long * bitmap,unsigned int nr_bits)208 static char *print_bitmap_string(char *str, const char *end,
209                                  const unsigned long *bitmap,
210                                  unsigned int nr_bits)
211 {
212     const unsigned int CHUNKSZ = 32;
213     unsigned int chunksz;
214     int i;
215     bool first = true;
216 
217     chunksz = nr_bits & (CHUNKSZ - 1);
218     if ( chunksz == 0 )
219         chunksz = CHUNKSZ;
220 
221     /*
222      * First iteration copes with the trailing partial word if nr_bits isn't a
223      * round multiple of CHUNKSZ.  All subsequent iterations work on a
224      * complete CHUNKSZ block.
225      */
226     for ( i = ROUNDUP(nr_bits, CHUNKSZ) - CHUNKSZ; i >= 0; i -= CHUNKSZ )
227     {
228         unsigned int chunkmask = (1ULL << chunksz) - 1;
229         unsigned int word      = i / BITS_PER_LONG;
230         unsigned int offset    = i % BITS_PER_LONG;
231         unsigned long val      = (bitmap[word] >> offset) & chunkmask;
232 
233         if ( !first )
234         {
235             if ( str < end )
236                 *str = ',';
237             str++;
238         }
239         first = false;
240 
241         str = number(str, end, val, 16, DIV_ROUND_UP(chunksz, 4), -1, ZEROPAD);
242 
243         chunksz = CHUNKSZ;
244     }
245 
246     return str;
247 }
248 
249 /* Print a domain id, using names for system domains.  (e.g. d0 or d[IDLE]) */
print_domain(char * str,const char * end,const struct domain * d)250 static char *print_domain(char *str, const char *end, const struct domain *d)
251 {
252     const char *name = NULL;
253 
254     /* Some debugging may have an optionally-NULL pointer. */
255     if ( unlikely(!d) )
256         return string(str, end, "NULL", -1, -1, 0);
257 
258     switch ( d->domain_id )
259     {
260     case DOMID_IO:   name = "[IO]";   break;
261     case DOMID_XEN:  name = "[XEN]";  break;
262     case DOMID_COW:  name = "[COW]";  break;
263     case DOMID_IDLE: name = "[IDLE]"; break;
264         /*
265          * In principle, we could ASSERT_UNREACHABLE() in the default case.
266          * However, this path is used to print out crash information, which
267          * risks recursing infinitely and not printing any useful information.
268          */
269     }
270 
271     if ( str < end )
272         *str = 'd';
273 
274     if ( name )
275         return string(str + 1, end, name, -1, -1, 0);
276     else
277         return number(str + 1, end, d->domain_id, 10, -1, -1, 0);
278 }
279 
280 /* Print a vcpu id.  (e.g. d0v1 or d[IDLE]v0) */
print_vcpu(char * str,const char * end,const struct vcpu * v)281 static char *print_vcpu(char *str, const char *end, const struct vcpu *v)
282 {
283     /* Some debugging may have an optionally-NULL pointer. */
284     if ( unlikely(!v) )
285         return string(str, end, "NULL", -1, -1, 0);
286 
287     str = print_domain(str, end, v->domain);
288 
289     if ( str < end )
290         *str = 'v';
291 
292     return number(str + 1, end, v->vcpu_id, 10, -1, -1, 0);
293 }
294 
print_pci_addr(char * str,const char * end,const pci_sbdf_t * sbdf)295 static char *print_pci_addr(char *str, const char *end, const pci_sbdf_t *sbdf)
296 {
297     str = number(str, end, sbdf->seg, 16, 4, -1, ZEROPAD);
298     if ( str < end )
299         *str = ':';
300     str = number(str + 1, end, sbdf->bus, 16, 2, -1, ZEROPAD);
301     if ( str < end )
302         *str = ':';
303     str = number(str + 1, end, sbdf->dev, 16, 2, -1, ZEROPAD);
304     if ( str < end )
305         *str = '.';
306     return number(str + 1, end, sbdf->fn, 8, -1, -1, 0);
307 }
308 
pointer(char * str,const char * end,const char ** fmt_ptr,const void * arg,int field_width,int precision,int flags)309 static char *pointer(char *str, const char *end, const char **fmt_ptr,
310                      const void *arg, int field_width, int precision,
311                      int flags)
312 {
313     const char *fmt = *fmt_ptr, *s;
314 
315     /* Custom %p suffixes. See XEN_ROOT/docs/misc/printk-formats.txt */
316     switch ( fmt[1] )
317     {
318     case 'b': /* Bitmap as hex, or list */
319         ++*fmt_ptr;
320 
321         if ( field_width < 0 )
322             return str;
323 
324         if ( fmt[2] == 'l' )
325         {
326             ++*fmt_ptr;
327 
328             return print_bitmap_list(str, end, arg, field_width);
329         }
330 
331         return print_bitmap_string(str, end, arg, field_width);
332 
333     case 'd': /* Domain ID from a struct domain *. */
334         ++*fmt_ptr;
335         return print_domain(str, end, arg);
336 
337     case 'h': /* Raw buffer as hex string. */
338     {
339         const uint8_t *hex_buffer = arg;
340         char sep = ' '; /* Separator character. */
341         unsigned int i;
342 
343         /* Consumed 'h' from the format string. */
344         ++*fmt_ptr;
345 
346         /* Bound user count from %* to between 0 and 64 bytes. */
347         if ( field_width <= 0 )
348             return str;
349         if ( field_width > 64 )
350             field_width = 64;
351 
352         /*
353          * Peek ahead in the format string to see if a recognised separator
354          * modifier is present.
355          */
356         switch ( fmt[2] )
357         {
358         case 'C': /* Colons. */
359             ++*fmt_ptr;
360             sep = ':';
361             break;
362 
363         case 'D': /* Dashes. */
364             ++*fmt_ptr;
365             sep = '-';
366             break;
367 
368         case 'N': /* No separator. */
369             ++*fmt_ptr;
370             sep = 0;
371             break;
372         }
373 
374         for ( i = 0; ; )
375         {
376             /* Each byte: 2 chars, 0-padded, base 16, no hex prefix. */
377             str = number(str, end, hex_buffer[i], 16, 2, -1, ZEROPAD);
378 
379             if ( ++i == field_width )
380                 break;
381 
382             if ( sep )
383             {
384                 if ( str < end )
385                     *str = sep;
386                 ++str;
387             }
388         }
389 
390         return str;
391     }
392 
393     case 'p': /* PCI SBDF. */
394         ++*fmt_ptr;
395         return print_pci_addr(str, end, arg);
396 
397     case 's': /* Symbol name with offset and size (iff offset != 0) */
398     case 'S': /* Symbol name unconditionally with offset and size */
399     {
400         unsigned long sym_size, sym_offset;
401         char namebuf[KSYM_NAME_LEN+1];
402 
403         /* Advance parents fmt string, as we have consumed 's' or 'S' */
404         ++*fmt_ptr;
405 
406         s = symbols_lookup((unsigned long)arg, &sym_size, &sym_offset, namebuf);
407 
408         /* If the symbol is not found, fall back to printing the address */
409         if ( !s )
410             break;
411 
412         /* Print symbol name */
413         str = string(str, end, s, -1, -1, 0);
414 
415         if ( fmt[1] == 'S' || sym_offset != 0 )
416         {
417             /* Print '+<offset>/<len>' */
418             str = number(str, end, sym_offset, 16, -1, -1, SPECIAL|SIGN|PLUS);
419             if ( str < end )
420                 *str = '/';
421             ++str;
422             str = number(str, end, sym_size, 16, -1, -1, SPECIAL);
423         }
424 
425         /*
426          * namebuf contents and s for core hypervisor are same but for Live Patch
427          * payloads they differ (namebuf contains the name of the payload).
428          */
429         if ( namebuf != s )
430         {
431             str = string(str, end, " [", -1, -1, 0);
432             str = string(str, end, namebuf, -1, -1, 0);
433             str = string(str, end, "]", -1, -1, 0);
434         }
435 
436         return str;
437     }
438 
439     case 'v': /* d<domain-id>v<vcpu-id> from a struct vcpu */
440         ++*fmt_ptr;
441         return print_vcpu(str, end, arg);
442     }
443 
444     if ( field_width == -1 )
445     {
446         field_width = 2 * sizeof(void *);
447         flags |= ZEROPAD;
448     }
449 
450     return number(str, end, (unsigned long)arg,
451                   16, field_width, precision, flags);
452 }
453 
454 /**
455  * vsnprintf - Format a string and place it in a buffer
456  * @buf: The buffer to place the result into
457  * @size: The size of the buffer, including the trailing null space
458  * @fmt: The format string to use
459  * @args: Arguments for the format string
460  *
461  * The return value is the number of characters which would
462  * be generated for the given input, excluding the trailing
463  * '\0', as per ISO C99. If you want to have the exact
464  * number of characters written into @buf as return value
465  * (not including the trailing '\0'), use vscnprintf. If the
466  * return is greater than or equal to @size, the resulting
467  * string is truncated.
468  *
469  * Call this function if you are already dealing with a va_list.
470  * You probably want snprintf instead.
471  */
vsnprintf(char * buf,size_t size,const char * fmt,va_list args)472 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
473 {
474     unsigned long long num;
475     int base;
476     char *str, *end, c;
477     const char *s;
478 
479     int flags;          /* flags to number() */
480 
481     int field_width;    /* width of output field */
482     int precision;              /* min. # of digits for integers; max
483                                    number of chars for from string */
484     int qualifier;              /* 'h', 'l', or 'L' for integer fields */
485                                 /* 'z' support added 23/7/1999 S.H.    */
486                                 /* 'z' changed to 'Z' --davidm 1/25/99 */
487 
488     /* Reject out-of-range values early */
489     BUG_ON(((int)size < 0) || ((unsigned int)size != size));
490 
491     str = buf;
492     end = buf + size;
493 
494     if (end < buf) {
495         end = ((void *) -1);
496         size = end - buf;
497     }
498 
499     for (; *fmt ; ++fmt) {
500         if (*fmt != '%') {
501             if (str < end)
502                 *str = *fmt;
503             ++str;
504             continue;
505         }
506 
507         /* process flags */
508         flags = 0;
509     repeat:
510         ++fmt;          /* this also skips first '%' */
511         switch (*fmt) {
512         case '-': flags |= LEFT; goto repeat;
513         case '+': flags |= PLUS; goto repeat;
514         case ' ': flags |= SPACE; goto repeat;
515         case '#': flags |= SPECIAL; goto repeat;
516         case '0': flags |= ZEROPAD; goto repeat;
517         }
518 
519         /* get field width */
520         field_width = -1;
521         if (isdigit(*fmt))
522             field_width = skip_atoi(&fmt);
523         else if (*fmt == '*') {
524             ++fmt;
525             /* it's the next argument */
526             field_width = va_arg(args, int);
527             if (field_width < 0) {
528                 field_width = -field_width;
529                 flags |= LEFT;
530             }
531         }
532 
533         /* get the precision */
534         precision = -1;
535         if (*fmt == '.') {
536             ++fmt;
537             if (isdigit(*fmt))
538                 precision = skip_atoi(&fmt);
539             else if (*fmt == '*') {
540                 ++fmt;
541                           /* it's the next argument */
542                 precision = va_arg(args, int);
543             }
544             if (precision < 0)
545                 precision = 0;
546         }
547 
548         /* get the conversion qualifier */
549         qualifier = -1;
550         if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
551             *fmt =='Z' || *fmt == 'z') {
552             qualifier = *fmt;
553             ++fmt;
554             if (qualifier == 'l' && *fmt == 'l') {
555                 qualifier = 'L';
556                 ++fmt;
557             }
558         }
559 
560         /* default base */
561         base = 10;
562 
563         switch (*fmt) {
564         case 'c':
565             if (!(flags & LEFT)) {
566                 while (--field_width > 0) {
567                     if (str < end)
568                         *str = ' ';
569                     ++str;
570                 }
571             }
572             c = (unsigned char) va_arg(args, int);
573             if (str < end)
574                 *str = c;
575             ++str;
576             while (--field_width > 0) {
577                 if (str < end)
578                     *str = ' ';
579                 ++str;
580             }
581             continue;
582 
583         case 's':
584             s = va_arg(args, char *);
585             if ((unsigned long)s < PAGE_SIZE)
586                 s = "<NULL>";
587 
588             str = string(str, end, s, field_width, precision, flags);
589             continue;
590 
591         case 'p':
592             /* pointer() might advance fmt (%pS for example) */
593             str = pointer(str, end, &fmt, va_arg(args, const void *),
594                           field_width, precision, flags);
595             continue;
596 
597 
598         case 'n':
599             if (qualifier == 'l') {
600                 long * ip = va_arg(args, long *);
601                 *ip = (str - buf);
602             } else if (qualifier == 'Z' || qualifier == 'z') {
603                 size_t * ip = va_arg(args, size_t *);
604                 *ip = (str - buf);
605             } else {
606                 int * ip = va_arg(args, int *);
607                 *ip = (str - buf);
608             }
609             continue;
610 
611         case '%':
612             if (str < end)
613                 *str = '%';
614             ++str;
615             continue;
616 
617             /* integer number formats - set up the flags and "break" */
618         case 'o':
619             base = 8;
620             break;
621 
622         case 'X':
623             flags |= LARGE;
624             fallthrough;
625         case 'x':
626             base = 16;
627             break;
628 
629         case 'd':
630         case 'i':
631             flags |= SIGN;
632             fallthrough;
633         case 'u':
634             break;
635 
636         default:
637             if (str < end)
638                 *str = '%';
639             ++str;
640             if (*fmt) {
641                 if (str < end)
642                     *str = *fmt;
643                 ++str;
644             } else {
645                 --fmt;
646             }
647             continue;
648         }
649         if (qualifier == 'L')
650             num = va_arg(args, long long);
651         else if (qualifier == 'l') {
652             num = va_arg(args, unsigned long);
653             if (flags & SIGN)
654                 num = (signed long) num;
655         } else if (qualifier == 'Z' || qualifier == 'z') {
656             num = va_arg(args, size_t);
657         } else if (qualifier == 'h') {
658             num = (unsigned short) va_arg(args, int);
659             if (flags & SIGN)
660                 num = (signed short) num;
661         } else {
662             num = va_arg(args, unsigned int);
663             if (flags & SIGN)
664                 num = (signed int) num;
665         }
666 
667         str = number(str, end, num, base,
668                      field_width, precision, flags);
669     }
670 
671     /* don't write out a null byte if the buf size is zero */
672     if (size > 0) {
673         if (str < end)
674             *str = '\0';
675         else
676             end[-1] = '\0';
677     }
678     /* the trailing null byte doesn't count towards the total
679      * ++str;
680      */
681     return str-buf;
682 }
683 
684 EXPORT_SYMBOL(vsnprintf);
685 
686 /**
687  * vscnprintf - Format a string and place it in a buffer
688  * @buf: The buffer to place the result into
689  * @size: The size of the buffer, including the trailing null space
690  * @fmt: The format string to use
691  * @args: Arguments for the format string
692  *
693  * The return value is the number of characters which have been written into
694  * the @buf not including the trailing '\0'. If @size is <= 0 the function
695  * returns 0.
696  *
697  * Call this function if you are already dealing with a va_list.
698  * You probably want scnprintf instead.
699  */
vscnprintf(char * buf,size_t size,const char * fmt,va_list args)700 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
701 {
702     int i;
703 
704     i = vsnprintf(buf,size,fmt,args);
705     if (i >= size)
706         i = size - 1;
707     return (i > 0) ? i : 0;
708 }
709 
710 EXPORT_SYMBOL(vscnprintf);
711 
712 /**
713  * snprintf - Format a string and place it in a buffer
714  * @buf: The buffer to place the result into
715  * @size: The size of the buffer, including the trailing null space
716  * @fmt: The format string to use
717  * @...: Arguments for the format string
718  *
719  * The return value is the number of characters which would be
720  * generated for the given input, excluding the trailing null,
721  * as per ISO C99.  If the return is greater than or equal to
722  * @size, the resulting string is truncated.
723  */
snprintf(char * buf,size_t size,const char * fmt,...)724 int snprintf(char * buf, size_t size, const char *fmt, ...)
725 {
726     va_list args;
727     int i;
728 
729     va_start(args, fmt);
730     i=vsnprintf(buf,size,fmt,args);
731     va_end(args);
732     return i;
733 }
734 
735 EXPORT_SYMBOL(snprintf);
736 
737 /**
738  * scnprintf - Format a string and place it in a buffer
739  * @buf: The buffer to place the result into
740  * @size: The size of the buffer, including the trailing null space
741  * @fmt: The format string to use
742  * @...: Arguments for the format string
743  *
744  * The return value is the number of characters written into @buf not including
745  * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
746  * greater than or equal to @size, the resulting string is truncated.
747  */
748 
scnprintf(char * buf,size_t size,const char * fmt,...)749 int scnprintf(char * buf, size_t size, const char *fmt, ...)
750 {
751     va_list args;
752     int i;
753 
754     va_start(args, fmt);
755     i = vsnprintf(buf, size, fmt, args);
756     va_end(args);
757     if (i >= size)
758         i = size - 1;
759     return (i > 0) ? i : 0;
760 }
761 EXPORT_SYMBOL(scnprintf);
762 
763 /**
764  * xvasprintf - Format a string and allocate a buffer to place it in
765  *
766  * @bufp: Pointer to a pointer to receive the allocated buffer
767  * @fmt: The format string to use
768  * @args: Arguments for the format string
769  *
770  * -ENOMEM is returned on failure and @bufp is not touched.
771  * On success, 0 is returned. The buffer passed back is
772  * guaranteed to be null terminated. The memory is allocated
773  * from xenheap, so the buffer should be freed with xfree().
774  */
xvasprintf(char ** bufp,const char * fmt,va_list args)775 int xvasprintf(char **bufp, const char *fmt, va_list args)
776 {
777     va_list args_copy;
778     size_t size;
779     char *buf;
780 
781     va_copy(args_copy, args);
782     size = vsnprintf(NULL, 0, fmt, args_copy);
783     va_end(args_copy);
784 
785     buf = xmalloc_array(char, ++size);
786     if ( !buf )
787         return -ENOMEM;
788 
789     (void) vsnprintf(buf, size, fmt, args);
790 
791     *bufp = buf;
792     return 0;
793 }
794 
795 /**
796  * xasprintf - Format a string and place it in a buffer
797  * @bufp: Pointer to a pointer to receive the allocated buffer
798  * @fmt: The format string to use
799  * @...: Arguments for the format string
800  *
801  * -ENOMEM is returned on failure and @bufp is not touched.
802  * On success, 0 is returned. The buffer passed back is
803  * guaranteed to be null terminated. The memory is allocated
804  * from xenheap, so the buffer should be freed with xfree().
805  */
xasprintf(char ** bufp,const char * fmt,...)806 int xasprintf(char **bufp, const char *fmt, ...)
807 {
808     va_list args;
809     int i;
810 
811     va_start(args, fmt);
812     i = xvasprintf(bufp, fmt, args);
813     va_end(args);
814 
815     return i;
816 }
817 
818 /*
819  * Local variables:
820  * mode: C
821  * c-file-style: "BSD"
822  * c-basic-offset: 4
823  * tab-width: 4
824  * indent-tabs-mode: nil
825  * End:
826  */
827