Esempio n. 1
0
/* return a heap allocated string formed from fmt and ap arglist
 * returned string is allocated with xmalloc, so must free with xfree.
 *
 * args are like printf, with the addition of the following format chars:
 * - %m expands to strerror(errno)
 * - %t expands to strftime("%x %X") [ locally preferred short date/time ]
 * - %T expands to rfc2822 date time  [ "dd, Mon yyyy hh:mm:ss GMT offset" ]
 *
 * simple format specifiers are handled explicitly to avoid calls to
 * vsnprintf and allow dynamic sizing of the message buffer. If a call
 * is made to vsnprintf, however, the message will be limited to 1024 bytes.
 * (inc. newline)
 *
 */
static char *vxstrfmt(const char *fmt, va_list ap)
{
	char        *buf = NULL;
	char        *p   = NULL;
	size_t      len = (size_t) 0;
	char        tmp[LINEBUFSIZE];
	int         unprocessed = 0;
	int         long_long = 0;

	while (*fmt != '\0') {

		if ((p = (char *)strchr(fmt, '%')) == NULL) {
			/* no more format chars */
			xstrcat(buf, fmt);
			break;

		} else {        /* *p == '%' */
			/* take difference from fmt to just before `%' */
			len = (size_t) ((long)(p) - (long)fmt);
			/* append from fmt to p into buf if there's
			 * anythere there
			 */
			if (len > 0)
				xstrncat(buf, fmt, len);

			switch (*(++p)) {
		        case '%':	/* "%%" => "%" */
				xstrcatchar(buf, '%');
				break;

			case 'm':	/* "%m" => strerror(errno) */
				xslurm_strerrorcat(buf);
				break;

			case 't': 	/* "%t" => locally preferred date/time*/
				xstrftimecat(buf, "%x %X");
				break;
			case 'T': 	/* "%T" => "dd, Mon yyyy hh:mm:ss off" */
				xstrftimecat(buf, "%a, %d %b %Y %H:%M:%S %z");
				break;
			case 'M':
				if (!log)
					xiso8601timecat(buf, true);
				else {
					switch (log->fmt) {
					case LOG_FMT_ISO8601_MS: /* "%M" => "yyyy-mm-ddThh:mm:ss.fff"  */
						xiso8601timecat(buf, true);
						break;
					case LOG_FMT_ISO8601: /* "%M" => "yyyy-mm-ddThh:mm:ss.fff"  */
						xiso8601timecat(buf, false);
						break;
					case LOG_FMT_RFC5424_MS: /* "%M" => "yyyy-mm-ddThh:mm:ss.fff(+/-)hh:mm" */
						xrfc5424timecat(buf, true);
						break;
					case LOG_FMT_RFC5424:  /* "%M" => "yyyy-mm-ddThh:mm:ss.fff(+/-)hh:mm" */
						xrfc5424timecat(buf, false);
						break;
					case LOG_FMT_CLOCK:
						/* "%M" => "usec" */
#if defined(__FreeBSD__)
						snprintf(tmp, sizeof(tmp), "%d", clock());
#else
						snprintf(tmp, sizeof(tmp), "%ld", clock());
#endif
						xstrcat(buf, tmp);
						break;
					case LOG_FMT_SHORT: /* "%M" => "Mon DD hh:mm:ss"         */
						xstrftimecat(buf, "%b %d %T");
						break;
					case LOG_FMT_THREAD_ID:
						set_idbuf(tmp);
						xstrcat(buf, tmp);
						break;
					}
				}
				break;
			case 's':	/* "%s" => append string */
				/* we deal with this case for efficiency */
				if (unprocessed == 0)
					xstrcat(buf, va_arg(ap, char *));
				else
					xstrcat(buf, "%s");
				break;
			case 'f': 	/* "%f" => append double */
				/* again, we only handle this for efficiency */
				if (unprocessed == 0) {
					snprintf(tmp, sizeof(tmp), "%f",
						 va_arg(ap, double));
					xstrcat(buf, tmp);
				} else
					xstrcat(buf, "%f");
				break;
			case 'd':
				if (unprocessed == 0) {
					snprintf(tmp, sizeof(tmp), "%d",
						 va_arg(ap, int));
					xstrcat(buf, tmp);
				} else
Esempio n. 2
0
File: log.c Progetto: cread/slurm
/*
 * return a heap allocated string formed from fmt and ap arglist
 * returned string is allocated with xmalloc, so must free with xfree.
 *
 * args are like printf, with the addition of the following format chars:
 * - %m expands to strerror(errno)
 * - %M expand to time stamp, format is configuration dependent
 * - %t expands to strftime("%x %X") [ locally preferred short date/time ]
 * - %T expands to rfc2822 date time  [ "dd, Mon yyyy hh:mm:ss GMT offset" ]
 *
 * these formats are expanded first, leaving all others to be passed to
 * vsnprintf() to complete the expansion using the ap arglist.
 */
static char *vxstrfmt(const char *fmt, va_list ap)
{
	char	*intermediate_fmt = NULL;
	char	*out_string = NULL;
	char	*p;
	int	found_other_formats = 0;

	while (*fmt != '\0') {
		int is_our_format = 0;
		p = (char *)strchr(fmt, '%');
		if (p == NULL) {
			/*
			 * no more format sequences, append the rest of
			 * fmt and exit the loop:
			 */
			xstrcat(intermediate_fmt, fmt);
			break;
		}

		/*
		 * make sure it's one of our format specifiers, skipping
		 * any that aren't:
		 */
		do {
			switch (*(p + 1)) {
				case 'm':
				case 't':
				case 'T':
				case 'M':
					is_our_format = 1;
					break;
				default:
					found_other_formats = 1;
					break;
			}
		} while (!is_our_format &&
			 (p = (char *)strchr(p + 1, '%')));

		if (is_our_format) {
			char	*substitute = NULL;
			char	substitute_on_stack[256];
			int	should_xfree = 1;

			/*
			 * p points to the leading % of one of our formats;
			 * append anything from fmt up to p to the intermediate
			 * format string:
			 */
			xstrncat(intermediate_fmt, fmt, p - fmt);
			fmt = p + 1;

			/*
			 * fill the substitute buffer with whatever text we want
			 * to substitute for the format sequence in question:
			 */
			switch (*fmt) {
			case 'm':	/* "%m" => strerror(errno) */
				substitute = slurm_strerror(errno);
				should_xfree = 0;
				break;
			case 't': 	/* "%t" => locally preferred date/time*/
				xstrftimecat(substitute,
					     "%x %X");
				break;
			case 'T': 	/* "%T" => "dd, Mon yyyy hh:mm:ss off" */
				xstrftimecat(substitute,
					     "%a, %d %b %Y %H:%M:%S %z");
				break;
			case 'M':
				if (!log) {
					xiso8601timecat(substitute, true);
					break;
				}
				switch (log->fmt) {
				case LOG_FMT_ISO8601_MS:
					/* "%M" => "yyyy-mm-ddThh:mm:ss.fff"  */
					xiso8601timecat(substitute, true);
					break;
				case LOG_FMT_ISO8601:
					/* "%M" => "yyyy-mm-ddThh:mm:ss.fff"  */
					xiso8601timecat(substitute, false);
					break;
				case LOG_FMT_RFC5424_MS:
					/* "%M" => "yyyy-mm-ddThh:mm:ss.fff(+/-)hh:mm" */
					xrfc5424timecat(substitute, true);
					break;
				case LOG_FMT_RFC5424:
					/* "%M" => "yyyy-mm-ddThh:mm:ss.fff(+/-)hh:mm" */
					xrfc5424timecat(substitute, false);
					break;
				case LOG_FMT_CLOCK:
					/* "%M" => "usec" */
#if defined(__FreeBSD__)
					snprintf(substitute_on_stack,
						 sizeof(substitute_on_stack),
						 "%d", clock());
#else
					snprintf(substitute_on_stack,
						 sizeof(substitute_on_stack),
						 "%ld", clock());
#endif
					substitute = substitute_on_stack;
					should_xfree = 0;
					break;
				case LOG_FMT_SHORT:
					/* "%M" => "Mon DD hh:mm:ss" */
					xstrftimecat(substitute, "%b %d %T");
					break;
				case LOG_FMT_THREAD_ID:
					set_idbuf(substitute_on_stack);
					substitute = substitute_on_stack;
					should_xfree = 0;
					break;
				}
				break;
			}
			fmt++;

			if (substitute) {
				char *s = substitute;

				while (*s && (p = (char *)strchr(s, '%'))) {
					/* append up through the '%' */
					xstrncat(intermediate_fmt, s, p - s);
					xstrcat(intermediate_fmt, "%%");
					s = p + 1;
				}
				if (*s) {
					/* append whatever's left of the substitution: */
					xstrcat(intermediate_fmt, s);
				}

				/* deallocate substitute if necessary: */
				if (should_xfree) {
					xfree(substitute);
				}
			}
		} else {
			/*
			 * no more format sequences for us, append the rest of
			 * fmt and exit the loop:
			 */
			xstrcat(intermediate_fmt, fmt);
			break;
		}
	}

	if (intermediate_fmt && found_other_formats) {
		char	tmp[LINEBUFSIZE];
		int	actual_len;
		va_list	ap_copy;

		va_copy(ap_copy, ap);
		actual_len = vsnprintf(tmp, sizeof(tmp),
				       intermediate_fmt, ap_copy);
		va_end(ap_copy);

		if (actual_len >= 0) {
			if (actual_len < sizeof(tmp)) {
				out_string = xstrdup(tmp);
			} else {
				/*
				 * our C library's vsnprintf() was nice enough
				 * to return the necessary size of the buffer!
				 */
				out_string = xmalloc(actual_len + 1);
				if (out_string) {
					va_copy(ap_copy, ap);
					vsnprintf(out_string, actual_len + 1,
						  intermediate_fmt, ap_copy);
					va_end(ap_copy);
				}
			}
		} else {
			size_t	growable_tmp_size = LINEBUFSIZE;
			char	*growable_tmp = NULL;

			/*
			 * our C library's vsnprintf() doesn't return the
			 * necessary buffer size on overflow, it considers that
			 * an error condition.  So we need to iteratively grow
			 * a buffer until it accommodates the vsnprintf() call
			 */
			do {
				growable_tmp_size += LINEBUFSIZE;
				growable_tmp = xrealloc(growable_tmp,
							growable_tmp_size);
				if (!growable_tmp)
					break;
				va_copy(ap_copy, ap);
				actual_len = vsnprintf(growable_tmp,
						       growable_tmp_size,
						       intermediate_fmt,
						       ap_copy);
				va_end(ap_copy);
			} while (actual_len < 0);
			out_string = growable_tmp;
		}
		xfree(intermediate_fmt);
	} else if (intermediate_fmt) {
		/*
		 * no additional format sequences, so we can just return the
		 * intermediate_fmt string
		 */
		out_string = intermediate_fmt;
	}

	return out_string;
}