13a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org/*
23a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * Revision 12: http://theos.com/~deraadt/snprintf.c
33a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *
43a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * Copyright (c) 1997 Theo de Raadt
53a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *
63a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * Redistribution and use in source and binary forms, with or without
73a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * modification, are permitted provided that the following conditions
83a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * are met:
93a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * 1. Redistributions of source code must retain the above copyright
103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *    notice, this list of conditions and the following disclaimer.
113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *    notice, this list of conditions and the following disclaimer in the
133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *    documentation and/or other materials provided with the distribution.
143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *
153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org */
263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#ifndef __VMS
283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org# include <sys/param.h>
293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <sys/types.h>
313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <sys/mman.h>
323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <signal.h>
333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <stdio.h>
343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if __STDC__
353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <stdarg.h>
363a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <stdlib.h>
373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#else
383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <varargs.h>
393a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <setjmp.h>
413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <unistd.h>
423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include <string.h>
433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#ifndef roundup
453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#ifdef __sgi
493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#define size_t ssize_t
503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic int pgsize;
533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic char *curobj;
543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic int caught;
553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic sigjmp_buf bail;
563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#define EXTRABYTES	2	/* XXX: why 2? you don't want to know */
583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic char *
603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgmsetup(str, n)
613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *str;
623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	size_t n;
633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *e;
653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
663a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	if (n == 0)
673a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		return NULL;
683a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	if (pgsize == 0)
693a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		pgsize = getpagesize();
703a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	curobj = (char *)malloc(n + EXTRABYTES + pgsize * 2);
713a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	if (curobj == NULL)
723a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		return NULL;
733a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	e = curobj + n + EXTRABYTES;
743a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	e = (char *)roundup((unsigned long)e, pgsize);
753a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	if (mprotect(e, pgsize, PROT_NONE) == -1) {
763a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		free(curobj);
773a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		curobj = NULL;
783a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		return NULL;
793a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	}
803a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	e = e - n - EXTRABYTES;
813a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	*e = '\0';
823a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	return (e);
833a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
843a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
853a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void
863a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org  mcatch( int a )
873a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
883a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	siglongjmp(bail, 1);
893a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
903a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
913a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void
923a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgmcleanup(str, n, p)
933a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *str;
943a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	size_t n;
953a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *p;
963a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
973a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	strncpy(str, p, n-1);
983a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	str[n-1] = '\0';
993a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	if (mprotect((caddr_t)(p + n + EXTRABYTES), pgsize,
1003a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	    PROT_READ|PROT_WRITE|PROT_EXEC) == -1)
1013a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		mprotect((caddr_t)(p + n + EXTRABYTES), pgsize,
1023a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		    PROT_READ|PROT_WRITE);
1033a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	free(curobj);
1043a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
1053a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1063a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgint
1073a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if __STDC__
1083a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgvsnprintf(char *str, size_t n, char const *fmt, va_list ap)
1093a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#else
1103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgvsnprintf(str, n, fmt, ap)
1113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *str;
1123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	size_t n;
1133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *fmt;
1143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *ap;
1153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
1163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
1173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	struct sigaction osa, nsa;
1183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *p;
1193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	int ret = n + 1;	/* if we bail, indicated we overflowed */
1203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	memset(&nsa, 0, sizeof nsa);
1223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	nsa.sa_handler = mcatch;
1233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	sigemptyset(&nsa.sa_mask);
1243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	p = msetup(str, n);
1263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	if (p == NULL) {
1273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		*str = '\0';
1283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		return 0;
1293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	}
1303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	if (sigsetjmp(bail, 1) == 0) {
1313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		if (sigaction(SIGSEGV, &nsa, &osa) == -1) {
1323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org			mcleanup(str, n, p);
1333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org			return (0);
1343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		}
1353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org		ret = vsprintf(p, fmt, ap);
1363a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	}
1373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	mcleanup(str, n, p);
1383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	(void) sigaction(SIGSEGV, &osa, NULL);
1393a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	return (ret);
1403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
1413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgint
1433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if __STDC__
1443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgsnprintf(char *str, size_t n, char const *fmt, ...)
1453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#else
1463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgsnprintf(str, n, fmt, va_alist)
1473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *str;
1483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	size_t n;
1493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	char *fmt;
1503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	va_dcl
1513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
1523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
1533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	va_list ap;
1543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if __STDC__
1553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	va_start(ap, fmt);
1563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#else
1573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	va_start(ap);
1583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
1593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	return (vsnprintf(str, n, fmt, ap));
1613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org	va_end(ap);
1623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
1633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
166