10a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen/*
20a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * Revision 12: http://theos.com/~deraadt/snprintf.c
30a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen *
40a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * Copyright (c) 1997 Theo de Raadt
50a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen *
60a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * Redistribution and use in source and binary forms, with or without
70a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * modification, are permitted provided that the following conditions
80a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * are met:
90a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * 1. Redistributions of source code must retain the above copyright
100a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen *    notice, this list of conditions and the following disclaimer.
110a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * 2. Redistributions in binary form must reproduce the above copyright
120a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen *    notice, this list of conditions and the following disclaimer in the
130a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen *    documentation and/or other materials provided with the distribution.
140a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen *
150a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
160a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
170a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
180a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
190a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
200a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
210a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
220a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
230a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
240a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
250a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen */
260a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
277ac913362770b9f15093bd43769068d966bf913fJouk Jansen#ifndef __VMS
287ac913362770b9f15093bd43769068d966bf913fJouk Jansen# include <sys/param.h>
297ac913362770b9f15093bd43769068d966bf913fJouk Jansen#endif
300a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <sys/types.h>
310a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <sys/mman.h>
320a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <signal.h>
330a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <stdio.h>
340a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#if __STDC__
350a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <stdarg.h>
360a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <stdlib.h>
370a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#else
380a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <varargs.h>
390a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#endif
400a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <setjmp.h>
410a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <unistd.h>
420a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#include <string.h>
430a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
440a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#ifndef roundup
450a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
460a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#endif
470a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
480a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#ifdef __sgi
490a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#define size_t ssize_t
500a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#endif
510a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
520a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenstatic int pgsize;
530a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenstatic char *curobj;
540a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenstatic int caught;
550a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenstatic sigjmp_buf bail;
560a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
570a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#define EXTRABYTES	2	/* XXX: why 2? you don't want to know */
580a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
590a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenstatic char *
600a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenmsetup(str, n)
610a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *str;
620a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	size_t n;
630a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen{
640a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *e;
650a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
660a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	if (n == 0)
670a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		return NULL;
680a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	if (pgsize == 0)
690a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		pgsize = getpagesize();
700a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	curobj = (char *)malloc(n + EXTRABYTES + pgsize * 2);
710a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	if (curobj == NULL)
720a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		return NULL;
730a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	e = curobj + n + EXTRABYTES;
740a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	e = (char *)roundup((unsigned long)e, pgsize);
750a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	if (mprotect(e, pgsize, PROT_NONE) == -1) {
760a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		free(curobj);
770a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		curobj = NULL;
780a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		return NULL;
790a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	}
800a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	e = e - n - EXTRABYTES;
810a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	*e = '\0';
820a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	return (e);
830a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen}
840a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
850a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenstatic void
860a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen  mcatch( int a )
870a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen{
880a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	siglongjmp(bail, 1);
890a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen}
900a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
910a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenstatic void
920a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenmcleanup(str, n, p)
930a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *str;
940a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	size_t n;
950a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *p;
960a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen{
970a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	strncpy(str, p, n-1);
980a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	str[n-1] = '\0';
990a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	if (mprotect((caddr_t)(p + n + EXTRABYTES), pgsize,
1000a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	    PROT_READ|PROT_WRITE|PROT_EXEC) == -1)
1010a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		mprotect((caddr_t)(p + n + EXTRABYTES), pgsize,
1020a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		    PROT_READ|PROT_WRITE);
1030a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	free(curobj);
1040a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen}
1050a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
1060a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenint
1070a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#if __STDC__
1080a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenvsnprintf(char *str, size_t n, char const *fmt, va_list ap)
1090a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#else
1100a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenvsnprintf(str, n, fmt, ap)
1110a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *str;
1120a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	size_t n;
1130a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *fmt;
1140a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *ap;
1150a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#endif
1160a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen{
1170a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	struct sigaction osa, nsa;
1180a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *p;
1190a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	int ret = n + 1;	/* if we bail, indicated we overflowed */
1200a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
1210a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	memset(&nsa, 0, sizeof nsa);
1220a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	nsa.sa_handler = mcatch;
1230a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	sigemptyset(&nsa.sa_mask);
1240a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
1250a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	p = msetup(str, n);
1260a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	if (p == NULL) {
1270a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		*str = '\0';
1280a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		return 0;
1290a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	}
1300a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	if (sigsetjmp(bail, 1) == 0) {
1310a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		if (sigaction(SIGSEGV, &nsa, &osa) == -1) {
1320a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen			mcleanup(str, n, p);
1330a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen			return (0);
1340a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		}
1350a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen		ret = vsprintf(p, fmt, ap);
1360a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	}
1370a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	mcleanup(str, n, p);
1380a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	(void) sigaction(SIGSEGV, &osa, NULL);
1390a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	return (ret);
1400a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen}
1410a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
1420a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansenint
1430a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#if __STDC__
1440a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansensnprintf(char *str, size_t n, char const *fmt, ...)
1450a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#else
1460a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansensnprintf(str, n, fmt, va_alist)
1470a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *str;
1480a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	size_t n;
1490a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	char *fmt;
1500a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	va_dcl
1510a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#endif
1520a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen{
1530a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	va_list ap;
1540a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#if __STDC__
1550a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	va_start(ap, fmt);
1560a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#else
1570a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	va_start(ap);
1580a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen#endif
1590a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
1600a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	return (vsnprintf(str, n, fmt, ap));
1610a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen	va_end(ap);
1620a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen}
1630a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
1640a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
1650a7fc572a7defdb7f7f23d4288bf8bbbc1ca48bdJouk Jansen
166