1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Auxiliary functions.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2013 Steffen "Daode" Nurpmeso <sdaoden@users.sf.net>.
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #ifndef HAVE_AMALGAMATION
44 #include <sys/utsname.h>
52 # include <sys/socket.h>
62 /* {hold,rele}_all_sigs() */
63 static size_t _alls_depth
;
64 static sigset_t _alls_nset
, _alls_oset
;
66 /* {hold,rele}_sigs() */
67 static size_t _hold_sigdepth
;
68 static sigset_t _hold_nset
, _hold_oset
;
71 panic(char const *format
, ...)
75 fprintf(stderr
, tr(1, "Panic: "));
78 vfprintf(stderr
, format
, ap
);
88 warn(char const *format
, ...)
92 fprintf(stderr
, tr(1, "Panic: "));
95 vfprintf(stderr
, format
, ap
);
104 safe_signal(int signum
, sighandler_type handler
)
106 struct sigaction nact
, oact
;
108 nact
.sa_handler
= handler
;
109 sigemptyset(&nact
.sa_mask
);
112 nact
.sa_flags
|= SA_RESTART
;
114 return ((sigaction(signum
, &nact
, &oact
) != 0) ? SIG_ERR
: oact
.sa_handler
);
120 if (_alls_depth
++ == 0) {
121 sigfillset(&_alls_nset
);
122 sigdelset(&_alls_nset
, SIGKILL
);
123 sigdelset(&_alls_nset
, SIGSTOP
);
124 sigdelset(&_alls_nset
, SIGCHLD
);
125 sigprocmask(SIG_BLOCK
, &_alls_nset
, &_alls_oset
);
132 if (--_alls_depth
== 0)
133 sigprocmask(SIG_SETMASK
, &_alls_oset
, (sigset_t
*)NULL
);
139 if (_hold_sigdepth
++ == 0) {
140 sigemptyset(&_hold_nset
);
141 sigaddset(&_hold_nset
, SIGHUP
);
142 sigaddset(&_hold_nset
, SIGINT
);
143 sigaddset(&_hold_nset
, SIGQUIT
);
144 sigprocmask(SIG_BLOCK
, &_hold_nset
, &_hold_oset
);
151 if (--_hold_sigdepth
== 0)
152 sigprocmask(SIG_SETMASK
, &_hold_oset
, NULL
);
156 * Touch the named message by setting its MTOUCH flag.
157 * Touched messages have the effect of not being sent
158 * back to the system mailbox on exit.
161 touch(struct message
*mp
)
164 mp
->m_flag
|= MTOUCH
;
165 if ((mp
->m_flag
& MREAD
) == 0)
166 mp
->m_flag
|= MREAD
|MSTATUS
;
170 * Test to see if the passed file name is a directory.
171 * Return true if it is.
174 is_dir(char const *name
)
178 if (stat(name
, &sbuf
) < 0)
180 return(S_ISDIR(sbuf
.st_mode
));
184 * Count the number of arguments in the given string raw list.
187 argcount(char **argv
)
191 for (ap
= argv
; *ap
++ != NULL
;)
193 return ap
- argv
- 1;
197 colalign(const char *cp
, int col
, int fill
, int *cols_decr_used_or_null
)
199 int col_orig
= col
, n
, sz
;
202 np
= nb
= salloc(mb_cur_max
* strlen(cp
) + col
+ 1);
205 if (mb_cur_max
> 1) {
208 if ((sz
= mbtowc(&wc
, cp
, mb_cur_max
)) < 0) {
211 if ((n
= wcwidth(wc
)) < 0)
222 if (sz
== 1 && spacechar(*cp
)) {
230 if (fill
&& col
!= 0) {
232 memmove(nb
+ col
, nb
, (size_t)(np
- nb
));
233 memset(nb
, ' ', col
);
235 memset(np
, ' ', col
);
241 if (cols_decr_used_or_null
!= NULL
)
242 *cols_decr_used_or_null
-= col_orig
- col
;
251 cp
= ok_vlook(PAGER
);
252 if (cp
== NULL
|| *cp
== '\0')
258 paging_seems_sensible(void)
263 if (IS_TTY_SESSION() && (cp
= ok_vlook(crt
)) != NULL
)
264 ret
= (*cp
!= '\0') ? (size_t)atol(cp
) : (size_t)scrnheight
;
269 page_or_print(FILE *fp
, size_t lines
)
276 if ((rows
= paging_seems_sensible()) != 0 && lines
== 0) {
277 while ((c
= getc(fp
)) != EOF
)
278 if (c
== '\n' && ++lines
> rows
)
283 if (rows
!= 0 && lines
>= rows
)
284 run_command(get_pager(), 0, fileno(fp
), -1, NULL
, NULL
, NULL
);
286 while ((c
= getc(fp
)) != EOF
)
291 which_protocol(const char *name
)
293 register const char *cp
;
299 if (name
[0] == '%' && name
[1] == ':')
301 for (cp
= name
; *cp
&& *cp
!= ':'; cp
++)
302 if (!alnumchar(*cp
&0377))
304 if (cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/') {
305 if (strncmp(name
, "pop3://", 7) == 0)
310 tr(216, "No POP3 support compiled in.\n"));
312 if (strncmp(name
, "pop3s://", 8) == 0)
317 tr(225, "No SSL support compiled in.\n"));
319 if (strncmp(name
, "imap://", 7) == 0)
324 tr(269, "No IMAP support compiled in.\n"));
326 if (strncmp(name
, "imaps://", 8) == 0)
331 tr(225, "No SSL support compiled in.\n"));
333 return PROTO_UNKNOWN
;
335 /* TODO This is the de facto maildir code and thus belongs
336 * TODO into maildir! */
337 file
: p
= PROTO_FILE
;
338 np
= ac_alloc((sz
= strlen(name
)) + 5);
339 memcpy(np
, name
, sz
+ 1);
340 if (stat(name
, &st
) == 0) {
341 if (S_ISDIR(st
.st_mode
)) {
342 strcpy(&np
[sz
], "/tmp");
343 if (stat(np
, &st
) == 0 && S_ISDIR(st
.st_mode
)) {
344 strcpy(&np
[sz
], "/new");
345 if (stat(np
, &st
) == 0 &&
346 S_ISDIR(st
.st_mode
)) {
347 strcpy(&np
[sz
], "/cur");
348 if (stat(np
, &st
) == 0 &&
355 strcpy(&np
[sz
], ".gz");
356 if (stat(np
, &st
) < 0) {
357 strcpy(&np
[sz
], ".bz2");
358 if (stat(np
, &st
) < 0) {
359 if ((cp
= ok_vlook(newfolders
)) != NULL
&&
360 strcmp(cp
, "maildir") == 0)
371 torek_hash(char const *name
)
373 /* Chris Torek's hash.
374 * NOTE: need to change *at least* create-okey-map.pl when changing the
378 while (*name
!= '\0') {
392 h
= (h
<< 4 & 0xffffffff) + (*cp
&0377);
393 if ((g
= h
& 0xf0000000) != 0) {
404 const long primes
[] = {
405 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
406 131071, 262139, 524287, 1048573, 2097143, 4194301,
407 8388593, 16777213, 33554393, 67108859, 134217689,
408 268435399, 536870909, 1073741789, 2147483647
413 for (i
= 0; i
< sizeof primes
/ sizeof *primes
; i
++)
414 if ((mprime
= primes
[i
]) >= (n
< 65536 ? n
*4 :
415 n
< 262144 ? n
*2 : n
))
417 if (i
== sizeof primes
/ sizeof *primes
)
418 mprime
= n
; /* not so prime, but better than failure */
423 expand_shell_escape(char const **s
, bool_t use_nail_extensions
)
428 if ((c
= *xs
& 0xFF) == '\0')
434 switch ((c
= *xs
& 0xFF)) {
436 case 'a': c
= '\a'; break;
437 case 'b': c
= '\b'; break;
438 case 'c': c
= PROMPT_STOP
; break;
439 case 'f': c
= '\f'; break;
440 case 'n': c
= '\n'; break;
441 case 'r': c
= '\r'; break;
442 case 't': c
= '\t'; break;
443 case 'v': c
= '\v'; break;
445 for (++xs
, c
= 0, n
= 4; --n
> 0 && octalchar(*xs
); ++xs
) {
450 /* S-nail extension for nice (get)prompt(()) support */
455 if (use_nail_extensions
) {
457 case '&': c
= ok_blook(bsdcompat
) ? '&' : '?'; break;
458 case '?': c
= exec_last_comm_error
? '1' : '0'; break;
459 case '$': c
= PROMPT_DOLLAR
; break;
460 case '@': c
= PROMPT_AT
; break;
466 /* A sole <backslash> at EOS is treated as-is! */
481 static char buf
[PROMPT_BUFFER_SIZE
];
486 if ((ccp
= ok_vlook(prompt
)) == NULL
|| *ccp
== '\0')
489 for (; PTRCMP(cp
, <, buf
+ sizeof(buf
) - 1); ++cp
) {
492 int c
= expand_shell_escape(&ccp
, TRU1
);
498 if (c
== 0 || c
== PROMPT_STOP
)
501 a
= (c
== PROMPT_DOLLAR
) ? account_name
: displayname
;
505 if (PTRCMP(cp
+ l
, >=, buf
+ sizeof(buf
) - 1))
518 nodename(int mayoverride
)
520 static char *hostname
;
525 struct addrinfo hints
, *res
;
527 struct hostent
*hent
;
531 if (mayoverride
&& (hn
= ok_vlook(hostname
)) != NULL
&& *hn
!= '\0') {
532 if (hostname
!= NULL
)
534 hostname
= sstrdup(hn
);
535 } else if (hostname
== NULL
) {
540 memset(&hints
, 0, sizeof hints
);
541 hints
.ai_family
= AF_UNSPEC
;
542 hints
.ai_socktype
= SOCK_DGRAM
; /* dummy */
543 hints
.ai_flags
= AI_CANONNAME
;
544 if (getaddrinfo(hn
, "0", &hints
, &res
) == 0) {
545 if (res
->ai_canonname
!= NULL
) {
546 size_t l
= strlen(res
->ai_canonname
);
547 hn
= ac_alloc(l
+ 1);
548 memcpy(hn
, res
->ai_canonname
, l
+ 1);
553 hent
= gethostbyname(hn
);
559 hostname
= sstrdup(hn
);
560 #if defined HAVE_SOCKETS && defined HAVE_IPV6
561 if (hn
!= ut
.nodename
)
569 lookup_password_for_token(char const *token
)
575 var
= ac_alloc(tl
+ 10);
577 memcpy(var
, "password-", 9);
578 memcpy(var
+ 9, token
, tl
);
581 if ((cp
= vok_vlook(var
)) != NULL
)
588 getrandstring(size_t length
)
590 static unsigned char nodedigest
[16];
602 data
= ac_alloc(length
);
603 if ((fd
= open("/dev/urandom", O_RDONLY
)) < 0 ||
604 length
!= (size_t)read(fd
, data
, length
)) {
611 md5_update(&ctx
, (unsigned char*)cp
, strlen(cp
));
612 md5_final(nodedigest
, &ctx
);
614 /* In that case it's only used for boundaries and
615 * Message-Id:s so that srand(3) should suffice */
617 for (i
= 0; i
< sizeof(nodedigest
); ++i
)
618 nodedigest
[i
] = (unsigned char)(
622 for (i
= 0; i
< length
; i
++)
624 (int)(255 * (rand() / (RAND_MAX
+ 1.0))) ^
625 nodedigest
[i
% sizeof nodedigest
]);
630 (void)b64_encode_buf(&b64
, data
, length
, B64_SALLOC
);
632 assert(length
< b64
.l
);
633 b64
.s
[length
] = '\0';
639 md5tohex(char hex
[MD5TOHEX_SIZE
], void const *vp
)
644 for (i
= 0; i
< MD5TOHEX_SIZE
/ 2; i
++) {
646 hex
[j
] = hexchar((cp
[i
] & 0xf0) >> 4);
647 hex
[++j
] = hexchar(cp
[i
] & 0x0f);
653 cram_md5_string(char const *user
, char const *pass
, char const *b64
)
656 char digest
[16], *cp
;
662 (void)b64_decode(&out
, &in
, NULL
);
663 assert(out
.s
!= NULL
);
665 hmac_md5((unsigned char*)out
.s
, out
.l
, UNCONST(pass
), strlen(pass
),
668 cp
= md5tohex(salloc(MD5TOHEX_SIZE
+ 1), digest
);
671 in
.l
= lu
+ MD5TOHEX_SIZE
+1;
672 in
.s
= ac_alloc(lu
+ 1 + MD5TOHEX_SIZE
+1);
673 memcpy(in
.s
, user
, lu
);
675 memcpy(in
.s
+ lu
+ 1, cp
, MD5TOHEX_SIZE
);
676 (void)b64_encode(&out
, &in
, B64_SALLOC
|B64_CRLF
);
680 #endif /* HAVE_MD5 */
683 makedir(const char *name
)
688 if (mkdir(name
, 0700) < 0) {
690 if ((e
== EEXIST
|| e
== ENOSYS
) &&
691 stat(name
, &st
) == 0 &&
692 (st
.st_mode
&S_IFMT
) == S_IFDIR
)
703 if ((cw
->cw_fd
= open(".", O_RDONLY
)) < 0)
705 if (fchdir(cw
->cw_fd
) < 0) {
715 if (fchdir(cw
->cw_fd
) < 0)
721 cwrelse(struct cw
*cw
)
725 #else /* !HAVE_FCHDIR */
729 if (getcwd(cw
->cw_wd
, sizeof cw
->cw_wd
) == NULL
|| chdir(cw
->cw_wd
) < 0)
737 if (chdir(cw
->cw_wd
) < 0)
744 cwrelse(struct cw
*cw
)
748 #endif /* !HAVE_FCHDIR */
751 makeprint(struct str
const *in
, struct str
*out
)
753 static int print_all_chars
= -1;
754 char const *inp
, *maxp
;
758 if (print_all_chars
== -1)
759 print_all_chars
= ok_blook(print_all_chars
);
762 out
->s
= outp
= smalloc(msz
);
766 if (print_all_chars
) {
768 memcpy(outp
, inp
, out
->l
);
772 #ifdef HAVE_C90AMEND1
773 if (mb_cur_max
> 1) {
774 char mbb
[MB_LEN_MAX
+ 1];
782 n
= mbtowc(&wc
, inp
, maxp
- inp
);
788 /* FIXME Why mbtowc() resetting here?
789 * FIXME what about ISO 2022-JP plus -- those
790 * FIXME will loose shifts, then!
791 * FIXME THUS - we'd need special "known points"
792 * FIXME to do so - say, after a newline!!
793 * FIXME WE NEED TO CHANGE ALL USES +MBLEN! */
794 (void)mbtowc(&wc
, NULL
, mb_cur_max
);
795 wc
= utf8
? 0xFFFD : '?';
800 if (!iswprint(wc
) && wc
!= '\n' && wc
!= '\r' &&
801 wc
!= '\b' && wc
!= '\t') {
802 if ((wc
& ~(wchar_t)037) == 0)
803 wc
= utf8
? 0x2400 | wc
: '?';
805 wc
= utf8
? 0x2421 : '?';
807 wc
= utf8
? 0x2426 : '?';
809 if ((n
= wctomb(mbb
, wc
)) <= 0)
812 if (out
->l
>= msz
- 1) {
813 dist
= outp
- out
->s
;
814 out
->s
= srealloc(out
->s
, msz
+= 32);
815 outp
= &out
->s
[dist
];
817 for (i
= 0; i
< n
; i
++)
821 #endif /* C90AMEND1 */
826 if (!isprint(c
) && c
!= '\n' && c
!= '\r' &&
827 c
!= '\b' && c
!= '\t')
834 out
->s
[out
->l
] = '\0';
845 makeprint(&in
, &out
);
846 rp
= salloc(out
.l
+ 1);
847 memcpy(rp
, out
.s
, out
.l
);
854 prout(const char *s
, size_t sz
, FILE *fp
)
861 makeprint(&in
, &out
);
862 n
= fwrite(out
.s
, 1, out
.l
, fp
);
868 putuc(int u
, int c
, FILE *fp
)
873 #ifdef HAVE_C90AMEND1
874 if (utf8
&& (u
& ~(wchar_t)0177)) {
875 char mbb
[MB_LEN_MAX
];
877 if ((n
= wctomb(mbb
, u
)) > 0) {
879 for (i
= 0; i
< n
; ++i
)
880 if (putc(mbb
[i
] & 0377, fp
) == EOF
) {
885 rv
= (putc('\0', fp
) != EOF
);
890 rv
= (putc(c
, fp
) != EOF
);
895 time_current_update(struct time_current
*tc
, bool_t full_update
)
897 tc
->tc_time
= time(NULL
);
899 memcpy(&tc
->tc_gm
, gmtime(&tc
->tc_time
), sizeof tc
->tc_gm
);
900 memcpy(&tc
->tc_local
, localtime(&tc
->tc_time
),
901 sizeof tc
->tc_local
);
902 sstpcpy(tc
->tc_ctime
, ctime(&tc
->tc_time
));
913 (smalloc_safe
)(size_t s SMALLOC_DEBUG_ARGS
)
918 rv
= (smalloc
)(s SMALLOC_DEBUG_ARGSCALL
);
924 (srealloc_safe
)(void *v
, size_t s SMALLOC_DEBUG_ARGS
)
929 rv
= (srealloc
)(v
, s SMALLOC_DEBUG_ARGSCALL
);
936 (scalloc_safe
)(size_t nmemb
, size_t size SMALLOC_DEBUG_ARGS
)
941 rv
= (scalloc
)(nmemb
, size SMALLOC_DEBUG_ARGSCALL
);
949 smalloc(size_t s SMALLOC_DEBUG_ARGS
)
955 if ((rv
= malloc(s
)) == NULL
)
961 srealloc(void *v
, size_t s SMALLOC_DEBUG_ARGS
)
969 else if ((rv
= realloc(v
, s
)) == NULL
)
975 scalloc(size_t nmemb
, size_t size SMALLOC_DEBUG_ARGS
)
981 if ((rv
= calloc(nmemb
, size
)) == NULL
)
986 #else /* !HAVE_DEBUG */
987 CTA(sizeof(char) == sizeof(ui8_t
));
989 # define _HOPE_SIZE (2 * 8 * sizeof(char))
990 # define _HOPE_SET(C) \
992 union ptr __xl, __xu;\
998 __xl.ui8p[0]=0xDE; __xl.ui8p[1]=0xAA; __xl.ui8p[2]=0x55; __xl.ui8p[3]=0xAD;\
999 __xl.ui8p[4]=0xBE; __xl.ui8p[5]=0x55; __xl.ui8p[6]=0xAA; __xl.ui8p[7]=0xEF;\
1000 __xu.ui8p += __xc->size - 8;\
1001 __xu.ui8p[0]=0xDE; __xu.ui8p[1]=0xAA; __xu.ui8p[2]=0x55; __xu.ui8p[3]=0xAD;\
1002 __xu.ui8p[4]=0xBE; __xu.ui8p[5]=0x55; __xu.ui8p[6]=0xAA; __xu.ui8p[7]=0xEF;\
1004 # define _HOPE_GET_TRACE(C,BAD) do {(C).cp += 8; _HOPE_GET(C, BAD);} while(0)
1005 # define _HOPE_GET(C,BAD) \
1007 union ptr __xl, __xu;\
1008 struct chunk *__xc;\
1016 if (__xl.ui8p[0] != 0xDE) __i |= 1<<0;\
1017 if (__xl.ui8p[1] != 0xAA) __i |= 1<<1;\
1018 if (__xl.ui8p[2] != 0x55) __i |= 1<<2;\
1019 if (__xl.ui8p[3] != 0xAD) __i |= 1<<3;\
1020 if (__xl.ui8p[4] != 0xBE) __i |= 1<<4;\
1021 if (__xl.ui8p[5] != 0x55) __i |= 1<<5;\
1022 if (__xl.ui8p[6] != 0xAA) __i |= 1<<6;\
1023 if (__xl.ui8p[7] != 0xEF) __i |= 1<<7;\
1026 warn("%p: corrupted lower canary: 0x%02X: %s, line %u",\
1027 __xl.p, __i, mdbg_file, mdbg_line);\
1030 __xu.ui8p += __xc->size - 8;\
1032 if (__xu.ui8p[0] != 0xDE) __i |= 1<<0;\
1033 if (__xu.ui8p[1] != 0xAA) __i |= 1<<1;\
1034 if (__xu.ui8p[2] != 0x55) __i |= 1<<2;\
1035 if (__xu.ui8p[3] != 0xAD) __i |= 1<<3;\
1036 if (__xu.ui8p[4] != 0xBE) __i |= 1<<4;\
1037 if (__xu.ui8p[5] != 0x55) __i |= 1<<5;\
1038 if (__xu.ui8p[6] != 0xAA) __i |= 1<<6;\
1039 if (__xu.ui8p[7] != 0xEF) __i |= 1<<7;\
1042 warn("%p: corrupted upper canary: 0x%02X: %s, line %u",\
1043 __xl.p, __i, mdbg_file, mdbg_line);\
1046 warn(" ..canary last seen: %s, line %u", __xc->file, __xc->line);\
1066 struct chunk
*_mlist
, *_mfree
;
1069 (smalloc
)(size_t s SMALLOC_DEBUG_ARGS
)
1075 s
+= sizeof(struct chunk
) + _HOPE_SIZE
;
1077 if ((p
.p
= (malloc
)(s
)) == NULL
)
1080 if ((p
.c
->next
= _mlist
) != NULL
)
1082 p
.c
->file
= mdbg_file
;
1083 p
.c
->line
= (ui16_t
)mdbg_line
;
1085 p
.c
->size
= (ui32_t
)s
;
1092 (srealloc
)(void *v
, size_t s SMALLOC_DEBUG_ARGS
)
1097 if ((p
.p
= v
) == NULL
) {
1098 p
.p
= (smalloc
)(s
, mdbg_file
, mdbg_line
);
1102 _HOPE_GET(p
, isbad
);
1105 fprintf(stderr
, "srealloc(): region freed! At %s, line %d\n"
1106 "\tLast seen: %s, line %d\n",
1107 mdbg_file
, mdbg_line
, p
.c
->file
, p
.c
->line
);
1114 p
.c
->prev
->next
= p
.c
->next
;
1115 if (p
.c
->next
!= NULL
)
1116 p
.c
->next
->prev
= p
.c
->prev
;
1121 s
+= sizeof(struct chunk
) + _HOPE_SIZE
;
1123 if ((p
.p
= (realloc
)(p
.c
, s
)) == NULL
)
1126 if ((p
.c
->next
= _mlist
) != NULL
)
1128 p
.c
->file
= mdbg_file
;
1129 p
.c
->line
= (ui16_t
)mdbg_line
;
1131 p
.c
->size
= (ui32_t
)s
;
1139 (scalloc
)(size_t nmemb
, size_t size SMALLOC_DEBUG_ARGS
)
1148 size
+= sizeof(struct chunk
) + _HOPE_SIZE
;
1150 if ((p
.p
= (malloc
)(size
)) == NULL
)
1152 memset(p
.p
, 0, size
);
1154 if ((p
.c
->next
= _mlist
) != NULL
)
1156 p
.c
->file
= mdbg_file
;
1157 p
.c
->line
= (ui16_t
)mdbg_line
;
1159 p
.c
->size
= (ui32_t
)size
;
1166 (sfree
)(void *v SMALLOC_DEBUG_ARGS
)
1171 if ((p
.p
= v
) == NULL
) {
1172 fprintf(stderr
, "sfree(NULL) from %s, line %d\n", mdbg_file
, mdbg_line
);
1176 _HOPE_GET(p
, isbad
);
1179 fprintf(stderr
, "sfree(): double-free avoided at %s, line %d\n"
1180 "\tLast seen: %s, line %d\n",
1181 mdbg_file
, mdbg_line
, p
.c
->file
, p
.c
->line
);
1188 p
.c
->prev
->next
= p
.c
->next
;
1189 if (p
.c
->next
!= NULL
)
1190 p
.c
->next
->prev
= p
.c
->prev
;
1193 if (options
& OPT_DEBUG
) {
1206 size_t c
= 0, s
= 0;
1208 for (p
.c
= _mfree
; p
.c
!= NULL
;) {
1217 if (options
& OPT_DEBUG
)
1218 fprintf(stderr
, "smemreset(): freed %" ZFMT
" chunks/%" ZFMT
" bytes\n",
1225 /* For _HOPE_GET() */
1226 char const * const mdbg_file
= "smemtrace()";
1227 int const mdbg_line
= -1;
1236 if ((fp
= Ftemp(&cp
, "Ra", "w+", 0600, 1)) == NULL
) {
1243 fprintf(fp
, "Currently allocated memory chunks:\n");
1244 for (lines
= 0, p
.c
= _mlist
; p
.c
!= NULL
; ++lines
, p
.c
= p
.c
->next
) {
1247 _HOPE_GET_TRACE(xp
, isbad
);
1248 fprintf(fp
, "%s%p (%5" ZFMT
" bytes): %s, line %u\n",
1249 (isbad
? "! CANARY ERROR: " : ""), xp
.p
,
1250 (size_t)(p
.c
->size
- sizeof(struct chunk
)), p
.c
->file
, p
.c
->line
);
1253 if (options
& OPT_DEBUG
) {
1254 fprintf(fp
, "sfree()d memory chunks awaiting free():\n");
1255 for (p
.c
= _mfree
; p
.c
!= NULL
; ++lines
, p
.c
= p
.c
->next
) {
1258 _HOPE_GET_TRACE(xp
, isbad
);
1259 fprintf(fp
, "%s%p (%5" ZFMT
" bytes): %s, line %u\n",
1260 (isbad
? "! CANARY ERROR: " : ""), xp
.p
,
1261 (size_t)(p
.c
->size
- sizeof(struct chunk
)), p
.c
->file
, p
.c
->line
);
1265 page_or_print(fp
, lines
);
1274 _smemcheck(char const *mdbg_file
, int mdbg_line
)
1277 bool_t anybad
= FAL0
, isbad
;
1280 for (lines
= 0, p
.c
= _mlist
; p
.c
!= NULL
; ++lines
, p
.c
= p
.c
->next
) {
1283 _HOPE_GET_TRACE(xp
, isbad
);
1287 "! CANARY ERROR: %p (%5" ZFMT
" bytes): %s, line %u\n",
1288 xp
.p
, (size_t)(p
.c
->size
- sizeof(struct chunk
)),
1289 p
.c
->file
, p
.c
->line
);
1293 if (options
& OPT_DEBUG
) {
1294 for (p
.c
= _mfree
; p
.c
!= NULL
; ++lines
, p
.c
= p
.c
->next
) {
1297 _HOPE_GET_TRACE(xp
, isbad
);
1301 "! CANARY ERROR: %p (%5" ZFMT
" bytes): %s, line %u\n",
1302 xp
.p
, (size_t)(p
.c
->size
- sizeof(struct chunk
)),
1303 p
.c
->file
, p
.c
->line
);
1309 # endif /* MEMCHECK */
1310 #endif /* HAVE_DEBUG */
1312 /* vim:set fenc=utf-8:s-it-mode (TODO only partial true) */