1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Auxiliary functions that don't fit anywhere else.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
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. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #define n_FILE auxlily
38 #ifndef HAVE_AMALGAMATION
42 #include <sys/utsname.h>
45 # include HAVE_GETRANDOM_HEADER
49 # ifdef HAVE_GETADDRINFO
50 # include <sys/socket.h>
56 #ifndef HAVE_POSIX_RANDOM
64 ui8_t b8
[sizeof(struct rand_arc4
)];
65 ui32_t b32
[sizeof(struct rand_arc4
) / sizeof(ui32_t
)];
70 struct a_aux_err_node
{
71 struct a_aux_err_node
*ae_next
;
72 struct n_string ae_str
;
76 static ui8_t a_aux_idec_atoi
[256] = {
77 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
78 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
79 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
80 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
81 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x01,
82 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,
83 0xFF,0xFF,0xFF,0xFF,0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,
84 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
85 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
86 0x23,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0A,0x0B,0x0C,
87 0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
88 0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,
89 0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
90 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
91 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
92 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
93 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
94 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
95 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
96 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
97 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
98 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
99 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
100 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
101 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
102 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
105 #define a_X(X) ((ui64_t)-1 / (X))
106 static ui64_t
const a_aux_idec_cutlimit
[35] = {
107 a_X( 2), a_X( 3), a_X( 4), a_X( 5), a_X( 6), a_X( 7), a_X( 8),
108 a_X( 9), a_X(10), a_X(11), a_X(12), a_X(13), a_X(14), a_X(15),
109 a_X(16), a_X(17), a_X(18), a_X(19), a_X(20), a_X(21), a_X(22),
110 a_X(23), a_X(24), a_X(25), a_X(26), a_X(27), a_X(28), a_X(29),
111 a_X(30), a_X(31), a_X(32), a_X(33), a_X(34), a_X(35), a_X(36)
115 #ifndef HAVE_POSIX_RANDOM
116 static union rand_state
*a_aux_rand
;
119 /* Error ring, for `errors' */
121 static struct a_aux_err_node
*a_aux_err_head
, *a_aux_err_tail
;
122 static size_t a_aux_err_cnt
, a_aux_err_cnt_noted
;
124 static size_t a_aux_err_linelen
;
126 /* Our ARC4 random generator with its completely unacademical pseudo
127 * initialization (shall /dev/urandom fail) */
128 #ifndef HAVE_POSIX_RANDOM
129 static void a_aux_rand_init(void);
130 SINLINE ui8_t
a_aux_rand_get8(void);
131 # ifndef HAVE_GETRANDOM
132 static ui32_t
a_aux_rand_weak(ui32_t seed
);
136 #ifndef HAVE_POSIX_RANDOM
138 a_aux_rand_init(void){
139 # ifndef HAVE_GETRANDOM
140 # ifdef HAVE_CLOCK_GETTIME
145 union {int fd
; size_t i
;} u
;
150 a_aux_rand
= smalloc(sizeof *a_aux_rand
);
152 # ifdef HAVE_GETRANDOM
153 /* getrandom(2) guarantees 256 without EINTR.. */
154 n_LCTA(sizeof(a_aux_rand
->a
._dat
) <= 256,
155 "Buffer to large to be served without EINTR error");
159 gr
= HAVE_GETRANDOM(a_aux_rand
->a
._dat
, sizeof a_aux_rand
->a
._dat
);
160 a_aux_rand
->a
._i
= a_aux_rand
->a
._dat
[42];
161 a_aux_rand
->a
._j
= a_aux_rand
->a
._dat
[84];
162 /* ..but be on the safe side */
163 if(UICMP(z
, gr
, ==, sizeof(a_aux_rand
->a
._dat
)))
169 if((u
.fd
= open("/dev/urandom", O_RDONLY
)) != -1){
172 ok
= (sizeof(a_aux_rand
->a
._dat
) == (size_t)read(u
.fd
, a_aux_rand
->a
._dat
,
173 sizeof(a_aux_rand
->a
._dat
)));
176 a_aux_rand
->a
._i
= a_aux_rand
->a
._dat
[42];
177 a_aux_rand
->a
._j
= a_aux_rand
->a
._dat
[84];
182 for(seed
= (uintptr_t)a_aux_rand
& UI32_MAX
, rnd
= 21; rnd
!= 0; --rnd
){
183 for(u
.i
= n_NELEM(a_aux_rand
->b32
); u
.i
-- != 0;){
186 # ifdef HAVE_CLOCK_GETTIME
187 clock_gettime(CLOCK_REALTIME
, &ts
);
188 t
= (ui32_t
)ts
.tv_nsec
;
190 gettimeofday(&ts
, NULL
);
191 t
= (ui32_t
)ts
.tv_usec
;
194 t
= (t
>> 16) | (t
<< 16);
195 a_aux_rand
->b32
[u
.i
] ^= a_aux_rand_weak(seed
^ t
);
196 a_aux_rand
->b32
[t
% n_NELEM(a_aux_rand
->b32
)] ^= seed
;
197 if(rnd
== 7 || rnd
== 17)
198 a_aux_rand
->b32
[u
.i
] ^= a_aux_rand_weak(seed
^ (ui32_t
)ts
.tv_sec
);
199 k
= a_aux_rand
->b32
[u
.i
] % n_NELEM(a_aux_rand
->b32
);
200 a_aux_rand
->b32
[k
] ^= a_aux_rand
->b32
[u
.i
];
201 seed
^= a_aux_rand_weak(a_aux_rand
->b32
[k
]);
203 seed
^= nextprime(seed
);
207 for(u
.i
= 5 * sizeof(a_aux_rand
->b8
); u
.i
!= 0; --u
.i
)
210 # endif /* !HAVE_GETRANDOM */
215 a_aux_rand_get8(void){
218 si
= a_aux_rand
->a
._dat
[++a_aux_rand
->a
._i
];
219 sj
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._j
+= si
];
220 a_aux_rand
->a
._dat
[a_aux_rand
->a
._i
] = sj
;
221 a_aux_rand
->a
._dat
[a_aux_rand
->a
._j
] = si
;
222 return a_aux_rand
->a
._dat
[(ui8_t
)(si
+ sj
)];
225 # ifndef HAVE_GETRANDOM
227 a_aux_rand_weak(ui32_t seed
){
228 /* From "Random number generators: good ones are hard to find",
229 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
230 * October 1988, p. 1195.
231 * (In fact: FreeBSD 4.7, /usr/src/lib/libc/stdlib/random.c.) */
238 seed
= (seed
* 16807) - (hi
* 2836);
243 # endif /* HAVE_GETRANDOM */
244 #endif /* !HAVE_POSIX_RANDOM */
252 if((cp
= ok_vlook(screen
)) != NULL
){
253 n_idec_uiz_cp(&rv
, cp
, 0, NULL
);
266 n_pager_get(char const **env_addon
){
270 rv
= ok_vlook(PAGER
);
272 if(env_addon
!= NULL
){
274 /* Update the manual upon any changes:
275 * *colour-pager*, $PAGER */
276 if(strstr(rv
, "less") != NULL
){
277 if(getenv("LESS") == NULL
)
280 (n_psonce
& n_PSO_TERMCAP_CA_MODE
) ? "LESS=Ri"
281 : !(n_psonce
& n_PSO_TERMCAP_DISABLE
) ? "LESS=FRi" :
284 }else if(strstr(rv
, "lv") != NULL
){
285 if(getenv("LV") == NULL
)
286 *env_addon
= "LV=-c";
294 page_or_print(FILE *fp
, size_t lines
)
302 if (n_source_may_yield_control() && (cp
= ok_vlook(crt
)) != NULL
) {
306 rows
= (size_t)n_scrnheight
;
308 n_idec_uiz_cp(&rows
, cp
, 0, NULL
);
310 if (rows
> 0 && lines
== 0) {
311 while ((c
= getc(fp
)) != EOF
)
312 if (c
== '\n' && ++lines
>= rows
)
318 char const *env_add
[2], *pager
;
320 pager
= n_pager_get(&env_add
[0]);
322 run_command(pager
, NULL
, fileno(fp
), COMMAND_FD_PASS
, NULL
,NULL
,NULL
,
328 while ((c
= getc(fp
)) != EOF
)
335 which_protocol(char const *name
) /* XXX (->URL (yet auxlily.c)) */
341 enum protocol rv
= PROTO_UNKNOWN
;
344 temporary_protocol_ext
= NULL
;
346 if (name
[0] == '%' && name
[1] == ':')
348 for (cp
= name
; *cp
&& *cp
!= ':'; cp
++)
352 if (cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/') {
353 if (!strncmp(name
, "pop3://", 7)) {
357 n_err(_("No POP3 support compiled in\n"));
359 } else if (!strncmp(name
, "pop3s://", 8)) {
360 #if defined HAVE_POP3 && defined HAVE_SSL
364 n_err(_("No POP3 support compiled in\n"));
367 n_err(_("No SSL support compiled in\n"));
374 /* TODO This is the de facto maildir code and thus belongs into there!
375 * TODO and: we should have maildir:// and mbox:// pseudo-protos, instead of
376 * TODO or (more likely) in addition to *newfolders*) */
379 np
= ac_alloc((sz
= strlen(name
)) + 4 +1);
380 memcpy(np
, name
, sz
+ 1);
381 if (!stat(name
, &st
)) {
382 if (S_ISDIR(st
.st_mode
) &&
383 (memcpy(np
+sz
, "/tmp", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)) &&
384 (memcpy(np
+sz
, "/new", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)) &&
385 (memcpy(np
+sz
, "/cur", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)))
388 if ((memcpy(np
+sz
, cp
=".gz", 4), !stat(np
, &st
) && S_ISREG(st
.st_mode
)) ||
389 (memcpy(np
+sz
, cp
=".xz",4), !stat(np
,&st
) && S_ISREG(st
.st_mode
)) ||
390 (memcpy(np
+sz
, cp
=".bz2",5), !stat(np
, &st
) && S_ISREG(st
.st_mode
)))
391 temporary_protocol_ext
= cp
;
392 else if ((cp
= ok_vlook(newfolders
)) != NULL
&&
393 !asccasecmp(cp
, "maildir"))
403 n_c_to_hex_base16(char store
[3], char c
){
404 static char const itoa16
[] = "0123456789ABCDEF";
408 store
[1] = itoa16
[(ui8_t
)c
& 0x0F];
409 c
= ((ui8_t
)c
>> 4) & 0x0F;
410 store
[0] = itoa16
[(ui8_t
)c
];
416 n_c_from_hex_base16(char const hex
[2]){
417 static ui8_t
const atoi16
[] = {
418 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x30-0x37 */
419 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x38-0x3F */
420 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, /* 0x40-0x47 */
421 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x48-0x4f */
422 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x50-0x57 */
423 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x58-0x5f */
424 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF /* 0x60-0x67 */
430 if ((i1
= (ui8_t
)hex
[0] - '0') >= n_NELEM(atoi16
) ||
431 (i2
= (ui8_t
)hex
[1] - '0') >= n_NELEM(atoi16
))
435 if ((i1
| i2
) & 0xF0u
)
449 n_idec_buf(void *resp
, char const *cbuf
, uiz_t clen
, ui8_t base
,
450 enum n_idec_mode idm
, char const **endptr_or_null
){
451 /* XXX Brute simple and */
454 enum n_idec_state rv
;
457 idm
&= n__IDEC_MODE_MASK
;
458 rv
= n_IDEC_STATE_NONE
| idm
;
468 while(spacechar(*cbuf
))
469 if(*++cbuf
== '\0' || --clen
== 0)
475 rv
|= n_IDEC_STATE_SEEN_MINUS
;
478 if(*++cbuf
== '\0' || --clen
== 0)
483 /* Base detection/skip */
487 /* Character must be valid for base */
488 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
492 /* 0 always valid as is, fallback base 10 */
493 if(*++cbuf
== '\0' || --clen
== 0)
496 /* Base "detection" */
497 if(base
== 0 || base
== 2 || base
== 16){
508 if((base
& 16) == 0){
510 /* Char after prefix must be valid */
512 if(*++cbuf
== '\0' || --clen
== 0)
515 /* Character must be valid for base, invalid otherwise */
516 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
528 /* Character must be valid for base, EBASE otherwise */
529 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
534 for(cut
= a_aux_idec_cutlimit
[base
- 2];;){
538 if(res
> UI64_MAX
- currc
)
548 if(*++cbuf
== '\0' || --clen
== 0)
551 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
560 switch(rv
& n__IDEC_MODE_LIMIT_MASK
){
561 case n_IDEC_MODE_LIMIT_8BIT
: uimask
= UI8_MAX
; break;
562 case n_IDEC_MODE_LIMIT_16BIT
: uimask
= UI16_MAX
; break;
563 case n_IDEC_MODE_LIMIT_32BIT
: uimask
= UI32_MAX
; break;
564 default: uimask
= UI64_MAX
; break;
566 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
570 if((rv
& (n_IDEC_MODE_SIGNED_TYPE
| n_IDEC_STATE_SEEN_MINUS
)
571 ) == (n_IDEC_MODE_SIGNED_TYPE
| n_IDEC_STATE_SEEN_MINUS
)){
572 if(res
> uimask
+ 1){
581 if(!(rv
& n_IDEC_MODE_LIMIT_NOERROR
))
582 rv
|= n_IDEC_STATE_EOVERFLOW
;
583 }else if(rv
& n_IDEC_STATE_SEEN_MINUS
)
587 switch(rv
& n__IDEC_MODE_LIMIT_MASK
){
588 case n_IDEC_MODE_LIMIT_8BIT
:
589 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
590 *(si8_t
*)resp
= (si8_t
)res
;
592 *(ui8_t
*)resp
= (ui8_t
)res
;
594 case n_IDEC_MODE_LIMIT_16BIT
:
595 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
596 *(si16_t
*)resp
= (si16_t
)res
;
598 *(ui16_t
*)resp
= (ui16_t
)res
;
600 case n_IDEC_MODE_LIMIT_32BIT
:
601 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
602 *(si32_t
*)resp
= (si32_t
)res
;
604 *(ui32_t
*)resp
= (ui32_t
)res
;
607 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
608 *(si64_t
*)resp
= (si64_t
)res
;
610 *(ui64_t
*)resp
= (ui64_t
)res
;
614 if(endptr_or_null
!= NULL
)
615 *endptr_or_null
= cbuf
;
616 if(*cbuf
== '\0' || clen
== 0)
617 rv
|= n_IDEC_STATE_CONSUMED
;
622 rv
|= n_IDEC_STATE_EINVAL
;
625 /* Not a base error for terminator and whitespace! */
626 if(*cbuf
!= '\0' && !spacechar(*cbuf
))
627 rv
|= n_IDEC_STATE_EBASE
;
631 /* Overflow error: consume input until bad character or length out */
633 if(*++cbuf
== '\0' || --clen
== 0)
635 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
640 rv
|= n_IDEC_STATE_EOVERFLOW
;
642 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
643 res
= (rv
& n_IDEC_STATE_SEEN_MINUS
) ? (ui64_t
)SI64_MIN
647 rv
&= ~n_IDEC_STATE_SEEN_MINUS
;
652 torek_hash(char const *name
)
654 /* Chris Torek's hash.
655 * NOTE: need to change *at least* mk-okey-map.pl when changing the
660 while (*name
!= '\0') {
669 torek_ihashn(char const *dat
, size_t len
){
670 /* See torek_hash() */
675 for(h
= 0; len
> 0 && (c
= *dat
++) != '\0'; --len
)
676 h
= (h
* 33) + lowerconv(c
);
684 static ui32_t
const primes
[] = {
685 5, 11, 23, 47, 97, 157, 283,
686 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
687 131071, 262139, 524287, 1048573, 2097143, 4194301,
688 8388593, 16777213, 33554393, 67108859, 134217689,
689 268435399, 536870909, 1073741789, 2147483647
695 i
= (n
< primes
[n_NELEM(primes
) / 4] ? 0
696 : (n
< primes
[n_NELEM(primes
) / 2] ? n_NELEM(primes
) / 4
697 : n_NELEM(primes
) / 2));
699 if ((mprime
= primes
[i
]) > n
)
701 while (++i
< n_NELEM(primes
));
702 if (i
== n_NELEM(primes
) && mprime
< n
)
709 n_getdeadletter(void){
710 char const *cp_base
, *cp
;
715 cp
= fexpand(ok_vlook(DEAD
), FEXP_LOCAL
| FEXP_NSHELL
);
716 if(cp
== NULL
|| strlen(cp
) >= PATH_MAX
){
718 n_err(_("Failed to expand *DEAD*, setting default (%s): %s\n"),
719 VAL_DEAD
, n_shexp_quote_cp(cp
, FAL0
));
723 cp
= savecatsep(ok_vlook(TMPDIR
), '/', VAL_DEAD_BASENAME
);
724 n_err(_("Cannot expand *DEAD*, using: %s\n"), cp
);
732 nodename(int mayoverride
)
734 static char *sys_hostname
, *hostname
; /* XXX free-at-exit */
739 # ifdef HAVE_GETADDRINFO
740 struct addrinfo hints
, *res
;
742 struct hostent
*hent
;
747 if (mayoverride
&& (hn
= ok_vlook(hostname
)) != NULL
&& *hn
!= '\0') {
749 } else if ((hn
= sys_hostname
) == NULL
) {
753 # ifdef HAVE_GETADDRINFO
754 memset(&hints
, 0, sizeof hints
);
755 hints
.ai_family
= AF_UNSPEC
;
756 hints
.ai_flags
= AI_CANONNAME
;
757 if (getaddrinfo(hn
, NULL
, &hints
, &res
) == 0) {
758 if (res
->ai_canonname
!= NULL
) {
759 size_t l
= strlen(res
->ai_canonname
) +1;
762 memcpy(hn
, res
->ai_canonname
, l
);
767 hent
= gethostbyname(hn
);
772 sys_hostname
= sstrdup(hn
);
773 #if defined HAVE_SOCKETS && defined HAVE_GETADDRINFO
774 if (hn
!= ut
.nodename
)
780 if (hostname
!= NULL
&& hostname
!= sys_hostname
)
782 hostname
= sstrdup(hn
);
788 getrandstring(size_t length
){
794 #ifndef HAVE_POSIX_RANDOM
795 if(a_aux_rand
== NULL
)
799 /* We use our base64 encoder with _NOPAD set, so ensure the encoded result
800 * with PAD stripped is still longer than what the user requests, easy way */
801 data
= n_lofi_alloc(i
= length
+ 3);
803 #ifndef HAVE_POSIX_RANDOM
805 data
[i
] = (char)a_aux_rand_get8();
809 for(cp
= data
; i
> 0;){
810 union {ui32_t i4
; char c
[4];} r
;
813 r
.i4
= (ui32_t
)arc4random();
815 case 0: cp
[3] = r
.c
[3]; j
= 4;
816 case 3: cp
[2] = r
.c
[2];
817 case 2: cp
[1] = r
.c
[1];
818 default: cp
[0] = r
.c
[0]; break;
826 assert(length
+ 3 < UIZ_MAX
/ 4);
827 b64_encode_buf(&b64
, data
, length
+ 3,
828 B64_SALLOC
| B64_RFC4648URL
| B64_NOPAD
);
831 assert(b64
.l
>= length
);
832 b64
.s
[length
] = '\0';
838 boolify(char const *inbuf
, uiz_t inlen
, si8_t emptyrv
)
843 assert(inlen
== 0 || inbuf
!= NULL
);
845 if (inlen
== UIZ_MAX
)
846 inlen
= strlen(inbuf
);
849 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
851 if ((inlen
== 1 && (*inbuf
== '1' || *inbuf
== 'y' || *inbuf
== 'Y')) ||
852 !ascncasecmp(inbuf
, "true", inlen
) ||
853 !ascncasecmp(inbuf
, "yes", inlen
) ||
854 !ascncasecmp(inbuf
, "on", inlen
))
856 else if ((inlen
== 1 &&
857 (*inbuf
== '0' || *inbuf
== 'n' || *inbuf
== 'N')) ||
858 !ascncasecmp(inbuf
, "false", inlen
) ||
859 !ascncasecmp(inbuf
, "no", inlen
) ||
860 !ascncasecmp(inbuf
, "off", inlen
))
865 if((n_idec_buf(&ib
, inbuf
, inlen
, 0, 0, NULL
866 ) & (n_IDEC_STATE_EMASK
| n_IDEC_STATE_CONSUMED
)
867 ) != n_IDEC_STATE_CONSUMED
)
878 quadify(char const *inbuf
, uiz_t inlen
, char const *prompt
, si8_t emptyrv
)
883 assert(inlen
== 0 || inbuf
!= NULL
);
885 if (inlen
== UIZ_MAX
)
886 inlen
= strlen(inbuf
);
889 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
890 else if ((rv
= boolify(inbuf
, inlen
, -1)) < 0 &&
891 !ascncasecmp(inbuf
, "ask-", 4) &&
892 (rv
= boolify(inbuf
+ 4, inlen
- 4, -1)) >= 0 &&
893 (n_psonce
& n_PSO_INTERACTIVE
))
894 rv
= getapproval(prompt
, rv
);
900 n_is_all_or_aster(char const *name
){
904 rv
= ((name
[0] == '*' && name
[1] == '\0') || !asccasecmp(name
, "all"));
912 #ifdef HAVE_CLOCK_GETTIME
914 #elif defined HAVE_GETTIMEOFDAY
921 if((cp
= ok_vlook(SOURCE_DATE_EPOCH
)) != NULL
){
924 (void)/* XXX ?? posnum= */n_idec_ui64_cp(&tib
, cp
, 0, NULL
);
929 #ifdef HAVE_CLOCK_GETTIME
930 clock_gettime(CLOCK_REALTIME
, &ts
);
931 rv
= (time_t)ts
.tv_sec
;
932 #elif defined HAVE_GETTIMEOFDAY
933 gettimeofday(&ts
, NULL
);
934 rv
= (time_t)ts
.tv_sec
;
944 time_current_update(struct time_current
*tc
, bool_t full_update
)
947 tc
->tc_time
= n_time_epoch();
949 memcpy(&tc
->tc_gm
, gmtime(&tc
->tc_time
), sizeof tc
->tc_gm
);
950 memcpy(&tc
->tc_local
, localtime(&tc
->tc_time
), sizeof tc
->tc_local
);
951 sstpcpy(tc
->tc_ctime
, ctime(&tc
->tc_time
));
957 n_msleep(uiz_t millis
, bool_t ignint
){
961 #ifdef HAVE_NANOSLEEP
963 struct timespec ts
, trem
;
966 ts
.tv_sec
= millis
/ 1000;
967 ts
.tv_nsec
= (millis
%= 1000) * 1000 * 1000;
969 while((i
= nanosleep(&ts
, &trem
)) != 0 && ignint
)
971 rv
= (i
== 0) ? 0 : (trem
.tv_sec
* 1000) + (trem
.tv_nsec
/ (1000 * 1000));
974 #elif defined HAVE_SLEEP
975 if((millis
/= 1000) == 0)
977 while((rv
= sleep((unsigned int)millis
)) != 0 && ignint
)
980 # error Configuration should have detected a function for sleeping.
988 n_err(char const *format
, ...){
992 va_start(ap
, format
);
994 if(n_psonce
& n_PSO_INTERACTIVE
)
1000 bool_t doname
, doflush
;
1003 while(*format
== '\n'){
1005 putc('\n', n_stderr
);
1009 if((doname
= doflush
))
1010 a_aux_err_linelen
= 0;
1012 if((len
= strlen(format
)) > 0){
1013 if(doname
|| a_aux_err_linelen
== 0)
1014 fputs(VAL_UAGENT
": ", n_stderr
);
1015 vfprintf(n_stderr
, format
, ap
);
1020 if(format
[--len
] == '\n'){
1021 a_aux_err_linelen
= (i
-= ++len
);
1024 ++a_aux_err_linelen
;
1037 n_verr(char const *format
, va_list ap
){
1039 struct a_aux_err_node
*enp
;
1041 bool_t doname
, doflush
;
1046 while(*format
== '\n'){
1048 putc('\n', n_stderr
);
1052 if((doname
= doflush
)){
1053 a_aux_err_linelen
= 0;
1055 if(n_psonce
& n_PSO_INTERACTIVE
){
1056 if((enp
= a_aux_err_tail
) != NULL
&&
1057 (enp
->ae_str
.s_len
> 0 &&
1058 enp
->ae_str
.s_dat
[enp
->ae_str
.s_len
- 1] != '\n'))
1059 n_string_push_c(&enp
->ae_str
, '\n');
1064 if((len
= strlen(format
)) == 0)
1067 n_pstate
|= n_PS_ERRORS_PROMPT
;
1070 if(doname
|| a_aux_err_linelen
== 0)
1071 fputs(VAL_UAGENT
": ", n_stderr
);
1076 if(format
[--len
] == '\n'){
1077 a_aux_err_linelen
= (i
-= ++len
);
1080 ++a_aux_err_linelen
;
1085 if(!(n_psonce
& n_PSO_INTERACTIVE
))
1087 vfprintf(n_stderr
, format
, ap
);
1091 n_LCTAV(ERRORS_MAX
> 3);
1093 /* Link it into the `errors' message ring */
1094 if((enp
= a_aux_err_tail
) == NULL
){
1096 enp
= smalloc(sizeof *enp
);
1097 enp
->ae_next
= NULL
;
1098 n_string_creat(&enp
->ae_str
);
1099 if(a_aux_err_tail
!= NULL
)
1100 a_aux_err_tail
->ae_next
= enp
;
1102 a_aux_err_head
= enp
;
1103 a_aux_err_tail
= enp
;
1106 (enp
->ae_str
.s_len
> 0 &&
1107 enp
->ae_str
.s_dat
[enp
->ae_str
.s_len
- 1] == '\n')){
1108 if(a_aux_err_cnt
< ERRORS_MAX
)
1111 a_aux_err_head
= (enp
= a_aux_err_head
)->ae_next
;
1112 a_aux_err_tail
->ae_next
= enp
;
1113 a_aux_err_tail
= enp
;
1114 enp
->ae_next
= NULL
;
1115 n_string_trunc(&enp
->ae_str
, 0);
1118 # ifdef HAVE_N_VA_COPY
1121 imax
= n_MIN(LINESIZE
, 1024);
1123 for(i
= imax
;; imax
= ++i
/* xxx could wrap, maybe */){
1124 # ifdef HAVE_N_VA_COPY
1132 n_string_resize(&enp
->ae_str
, (len
= enp
->ae_str
.s_len
) + (size_t)i
);
1133 i
= vsnprintf(&enp
->ae_str
.s_dat
[len
], (size_t)i
, format
, vac
);
1134 # ifdef HAVE_N_VA_COPY
1141 if(UICMP(z
, i
, >=, imax
)){
1142 # ifdef HAVE_N_VA_COPY
1143 /* XXX Check overflow for upcoming LEN+++i! */
1144 n_string_trunc(&enp
->ae_str
, len
);
1147 i
= (int)strlen(&enp
->ae_str
.s_dat
[len
]);
1152 n_string_trunc(&enp
->ae_str
, len
+ (size_t)i
);
1154 fwrite(&enp
->ae_str
.s_dat
[len
], 1, (size_t)i
, n_stderr
);
1156 #endif /* HAVE_ERRORS */
1165 n_err_sighdl(char const *format
, ...){ /* TODO sigsafe; obsolete! */
1169 va_start(ap
, format
);
1170 vfprintf(n_stderr
, format
, ap
);
1176 n_perr(char const *msg
, int errval
){
1189 n_err(fmt
, msg
, strerror(errval
));
1194 n_alert(char const *format
, ...){
1198 n_err(a_aux_err_linelen
> 0 ? _("\nAlert: ") : _("Alert: "));
1200 va_start(ap
, format
);
1209 n_panic(char const *format
, ...){
1213 if(a_aux_err_linelen
> 0){
1214 putc('\n', n_stderr
);
1215 a_aux_err_linelen
= 0;
1217 fprintf(n_stderr
, VAL_UAGENT
": Panic: ");
1219 va_start(ap
, format
);
1220 vfprintf(n_stderr
, format
, ap
);
1223 putc('\n', n_stderr
);
1226 abort(); /* Was exit(n_EXIT_ERR); for a while, but no */
1233 struct a_aux_err_node
*enp
;
1240 if(!asccasecmp(*argv
, "show"))
1242 if(!asccasecmp(*argv
, "clear"))
1246 _("Synopsis: errors: (<show> or) <clear> the error ring\n"));
1250 return (v
== NULL
) ? !STOP
: !OKAY
; /* xxx 1:bad 0:good -- do some */
1256 if(a_aux_err_head
== NULL
){
1257 fprintf(n_stderr
, _("The error ring is empty\n"));
1261 if((fp
= Ftmp(NULL
, "errors", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) ==
1263 fprintf(n_stderr
, _("tmpfile"));
1268 for(i
= 0, enp
= a_aux_err_head
; enp
!= NULL
; enp
= enp
->ae_next
)
1269 fprintf(fp
, "%4" PRIuZ
". %s", ++i
, n_string_cp(&enp
->ae_str
));
1270 /* We don't know whether last string ended with NL; be simple XXX */
1273 page_or_print(fp
, 0);
1279 a_aux_err_tail
= NULL
;
1280 a_aux_err_cnt
= a_aux_err_cnt_noted
= 0;
1281 a_aux_err_linelen
= 0;
1282 while((enp
= a_aux_err_head
) != NULL
){
1283 a_aux_err_head
= enp
->ae_next
;
1284 n_string_gut(&enp
->ae_str
);
1289 #endif /* HAVE_ERRORS */
1293 n_regex_err_to_str(const regex_t
*rep
, int e
){
1298 i
= regerror(e
, rep
, NULL
, 0) +1;
1300 regerror(e
, rep
, cp
, i
);