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
[a_aux_rand
->a
._dat
[1] ^
161 a_aux_rand
->a
._dat
[84]];
162 a_aux_rand
->a
._j
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._dat
[65] ^
163 a_aux_rand
->a
._dat
[42]];
164 /* ..but be on the safe side */
165 if(UICMP(z
, gr
, ==, sizeof(a_aux_rand
->a
._dat
)))
171 if((u
.fd
= open("/dev/urandom", O_RDONLY
)) != -1){
174 ok
= (sizeof(a_aux_rand
->a
._dat
) == (size_t)read(u
.fd
, a_aux_rand
->a
._dat
,
175 sizeof(a_aux_rand
->a
._dat
)));
178 a_aux_rand
->a
._i
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._dat
[1] ^
179 a_aux_rand
->a
._dat
[84]];
180 a_aux_rand
->a
._j
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._dat
[65] ^
181 a_aux_rand
->a
._dat
[42]];
186 for(seed
= (uintptr_t)a_aux_rand
& UI32_MAX
, rnd
= 21; rnd
!= 0; --rnd
){
187 for(u
.i
= n_NELEM(a_aux_rand
->b32
); u
.i
-- != 0;){
190 # ifdef HAVE_CLOCK_GETTIME
191 clock_gettime(CLOCK_REALTIME
, &ts
);
192 t
= (ui32_t
)ts
.tv_nsec
;
194 gettimeofday(&ts
, NULL
);
195 t
= (ui32_t
)ts
.tv_usec
;
198 t
= (t
>> 16) | (t
<< 16);
199 a_aux_rand
->b32
[u
.i
] ^= a_aux_rand_weak(seed
^ t
);
200 a_aux_rand
->b32
[t
% n_NELEM(a_aux_rand
->b32
)] ^= seed
;
201 if(rnd
== 7 || rnd
== 17)
202 a_aux_rand
->b32
[u
.i
] ^= a_aux_rand_weak(seed
^ (ui32_t
)ts
.tv_sec
);
203 k
= a_aux_rand
->b32
[u
.i
] % n_NELEM(a_aux_rand
->b32
);
204 a_aux_rand
->b32
[k
] ^= a_aux_rand
->b32
[u
.i
];
205 seed
^= a_aux_rand_weak(a_aux_rand
->b32
[k
]);
207 seed
^= nextprime(seed
);
211 for(u
.i
= 5 * sizeof(a_aux_rand
->b8
); u
.i
!= 0; --u
.i
)
214 # endif /* !HAVE_GETRANDOM */
219 a_aux_rand_get8(void){
222 si
= a_aux_rand
->a
._dat
[++a_aux_rand
->a
._i
];
223 sj
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._j
+= si
];
224 a_aux_rand
->a
._dat
[a_aux_rand
->a
._i
] = sj
;
225 a_aux_rand
->a
._dat
[a_aux_rand
->a
._j
] = si
;
226 return a_aux_rand
->a
._dat
[(ui8_t
)(si
+ sj
)];
229 # ifndef HAVE_GETRANDOM
231 a_aux_rand_weak(ui32_t seed
){
232 /* From "Random number generators: good ones are hard to find",
233 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
234 * October 1988, p. 1195.
235 * (In fact: FreeBSD 4.7, /usr/src/lib/libc/stdlib/random.c.) */
242 seed
= (seed
* 16807) - (hi
* 2836);
247 # endif /* HAVE_GETRANDOM */
248 #endif /* !HAVE_POSIX_RANDOM */
256 if((cp
= ok_vlook(screen
)) != NULL
){
257 n_idec_uiz_cp(&rv
, cp
, 0, NULL
);
270 n_pager_get(char const **env_addon
){
274 rv
= ok_vlook(PAGER
);
276 if(env_addon
!= NULL
){
278 /* Update the manual upon any changes:
279 * *colour-pager*, $PAGER */
280 if(strstr(rv
, "less") != NULL
){
281 if(getenv("LESS") == NULL
)
284 (n_psonce
& n_PSO_TERMCAP_CA_MODE
) ? "LESS=Ri"
285 : !(n_psonce
& n_PSO_TERMCAP_DISABLE
) ? "LESS=FRi" :
288 }else if(strstr(rv
, "lv") != NULL
){
289 if(getenv("LV") == NULL
)
290 *env_addon
= "LV=-c";
298 page_or_print(FILE *fp
, size_t lines
)
306 if (n_source_may_yield_control() && (cp
= ok_vlook(crt
)) != NULL
) {
310 rows
= (size_t)n_scrnheight
;
312 n_idec_uiz_cp(&rows
, cp
, 0, NULL
);
314 if (rows
> 0 && lines
== 0) {
315 while ((c
= getc(fp
)) != EOF
)
316 if (c
== '\n' && ++lines
>= rows
)
322 char const *env_add
[2], *pager
;
324 pager
= n_pager_get(&env_add
[0]);
326 run_command(pager
, NULL
, fileno(fp
), COMMAND_FD_PASS
, NULL
,NULL
,NULL
,
332 while ((c
= getc(fp
)) != EOF
)
339 which_protocol(char const *name
) /* XXX (->URL (yet auxlily.c)) */
345 enum protocol rv
= PROTO_UNKNOWN
;
348 temporary_protocol_ext
= NULL
;
350 if (name
[0] == '%' && name
[1] == ':')
352 for (cp
= name
; *cp
&& *cp
!= ':'; cp
++)
356 if (cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/') {
357 if (!strncmp(name
, "pop3://", 7)) {
361 n_err(_("No POP3 support compiled in\n"));
363 } else if (!strncmp(name
, "pop3s://", 8)) {
364 #if defined HAVE_POP3 && defined HAVE_SSL
368 n_err(_("No POP3 support compiled in\n"));
371 n_err(_("No SSL support compiled in\n"));
378 /* TODO This is the de facto maildir code and thus belongs into there!
379 * TODO and: we should have maildir:// and mbox:// pseudo-protos, instead of
380 * TODO or (more likely) in addition to *newfolders*) */
383 np
= ac_alloc((sz
= strlen(name
)) + 4 +1);
384 memcpy(np
, name
, sz
+ 1);
385 if (!stat(name
, &st
)) {
386 if (S_ISDIR(st
.st_mode
) &&
387 (memcpy(np
+sz
, "/tmp", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)) &&
388 (memcpy(np
+sz
, "/new", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)) &&
389 (memcpy(np
+sz
, "/cur", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)))
392 if ((memcpy(np
+sz
, cp
=".gz", 4), !stat(np
, &st
) && S_ISREG(st
.st_mode
)) ||
393 (memcpy(np
+sz
, cp
=".xz",4), !stat(np
,&st
) && S_ISREG(st
.st_mode
)) ||
394 (memcpy(np
+sz
, cp
=".bz2",5), !stat(np
, &st
) && S_ISREG(st
.st_mode
)))
395 temporary_protocol_ext
= cp
;
396 else if ((cp
= ok_vlook(newfolders
)) != NULL
&&
397 !asccasecmp(cp
, "maildir"))
407 n_c_to_hex_base16(char store
[3], char c
){
408 static char const itoa16
[] = "0123456789ABCDEF";
412 store
[1] = itoa16
[(ui8_t
)c
& 0x0F];
413 c
= ((ui8_t
)c
>> 4) & 0x0F;
414 store
[0] = itoa16
[(ui8_t
)c
];
420 n_c_from_hex_base16(char const hex
[2]){
421 static ui8_t
const atoi16
[] = {
422 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x30-0x37 */
423 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x38-0x3F */
424 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, /* 0x40-0x47 */
425 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x48-0x4f */
426 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x50-0x57 */
427 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x58-0x5f */
428 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF /* 0x60-0x67 */
434 if ((i1
= (ui8_t
)hex
[0] - '0') >= n_NELEM(atoi16
) ||
435 (i2
= (ui8_t
)hex
[1] - '0') >= n_NELEM(atoi16
))
439 if ((i1
| i2
) & 0xF0u
)
453 n_idec_buf(void *resp
, char const *cbuf
, uiz_t clen
, ui8_t base
,
454 enum n_idec_mode idm
, char const **endptr_or_null
){
455 /* XXX Brute simple and */
458 enum n_idec_state rv
;
461 idm
&= n__IDEC_MODE_MASK
;
462 rv
= n_IDEC_STATE_NONE
| idm
;
472 while(spacechar(*cbuf
))
473 if(*++cbuf
== '\0' || --clen
== 0)
479 rv
|= n_IDEC_STATE_SEEN_MINUS
;
482 if(*++cbuf
== '\0' || --clen
== 0)
487 /* Base detection/skip */
491 /* Character must be valid for base */
492 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
496 /* 0 always valid as is, fallback base 10 */
497 if(*++cbuf
== '\0' || --clen
== 0)
500 /* Base "detection" */
501 if(base
== 0 || base
== 2 || base
== 16){
512 if((base
& 16) == 0){
514 /* Char after prefix must be valid */
516 if(*++cbuf
== '\0' || --clen
== 0)
519 /* Character must be valid for base, invalid otherwise */
520 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
532 /* Character must be valid for base, EBASE otherwise */
533 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
538 for(cut
= a_aux_idec_cutlimit
[base
- 2];;){
542 if(res
> UI64_MAX
- currc
)
552 if(*++cbuf
== '\0' || --clen
== 0)
555 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
564 switch(rv
& n__IDEC_MODE_LIMIT_MASK
){
565 case n_IDEC_MODE_LIMIT_8BIT
: uimask
= UI8_MAX
; break;
566 case n_IDEC_MODE_LIMIT_16BIT
: uimask
= UI16_MAX
; break;
567 case n_IDEC_MODE_LIMIT_32BIT
: uimask
= UI32_MAX
; break;
568 default: uimask
= UI64_MAX
; break;
570 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
574 if((rv
& (n_IDEC_MODE_SIGNED_TYPE
| n_IDEC_STATE_SEEN_MINUS
)
575 ) == (n_IDEC_MODE_SIGNED_TYPE
| n_IDEC_STATE_SEEN_MINUS
)){
576 if(res
> uimask
+ 1){
585 if(!(rv
& n_IDEC_MODE_LIMIT_NOERROR
))
586 rv
|= n_IDEC_STATE_EOVERFLOW
;
587 }else if(rv
& n_IDEC_STATE_SEEN_MINUS
)
591 switch(rv
& n__IDEC_MODE_LIMIT_MASK
){
592 case n_IDEC_MODE_LIMIT_8BIT
:
593 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
594 *(si8_t
*)resp
= (si8_t
)res
;
596 *(ui8_t
*)resp
= (ui8_t
)res
;
598 case n_IDEC_MODE_LIMIT_16BIT
:
599 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
600 *(si16_t
*)resp
= (si16_t
)res
;
602 *(ui16_t
*)resp
= (ui16_t
)res
;
604 case n_IDEC_MODE_LIMIT_32BIT
:
605 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
606 *(si32_t
*)resp
= (si32_t
)res
;
608 *(ui32_t
*)resp
= (ui32_t
)res
;
611 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
612 *(si64_t
*)resp
= (si64_t
)res
;
614 *(ui64_t
*)resp
= (ui64_t
)res
;
618 if(endptr_or_null
!= NULL
)
619 *endptr_or_null
= cbuf
;
620 if(*cbuf
== '\0' || clen
== 0)
621 rv
|= n_IDEC_STATE_CONSUMED
;
626 rv
|= n_IDEC_STATE_EINVAL
;
629 /* Not a base error for terminator and whitespace! */
630 if(*cbuf
!= '\0' && !spacechar(*cbuf
))
631 rv
|= n_IDEC_STATE_EBASE
;
635 /* Overflow error: consume input until bad character or length out */
637 if(*++cbuf
== '\0' || --clen
== 0)
639 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
644 rv
|= n_IDEC_STATE_EOVERFLOW
;
646 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
647 res
= (rv
& n_IDEC_STATE_SEEN_MINUS
) ? (ui64_t
)SI64_MIN
651 rv
&= ~n_IDEC_STATE_SEEN_MINUS
;
656 torek_hash(char const *name
)
658 /* Chris Torek's hash.
659 * NOTE: need to change *at least* mk-okey-map.pl when changing the
664 while (*name
!= '\0') {
673 torek_ihashn(char const *dat
, size_t len
){
674 /* See torek_hash() */
679 for(h
= 0; len
> 0 && (c
= *dat
++) != '\0'; --len
)
680 h
= (h
* 33) + lowerconv(c
);
688 static ui32_t
const primes
[] = {
689 5, 11, 23, 47, 97, 157, 283,
690 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
691 131071, 262139, 524287, 1048573, 2097143, 4194301,
692 8388593, 16777213, 33554393, 67108859, 134217689,
693 268435399, 536870909, 1073741789, 2147483647
699 i
= (n
< primes
[n_NELEM(primes
) / 4] ? 0
700 : (n
< primes
[n_NELEM(primes
) / 2] ? n_NELEM(primes
) / 4
701 : n_NELEM(primes
) / 2));
703 if ((mprime
= primes
[i
]) > n
)
705 while (++i
< n_NELEM(primes
));
706 if (i
== n_NELEM(primes
) && mprime
< n
)
713 n_getdeadletter(void){
714 char const *cp_base
, *cp
;
719 cp
= fexpand(ok_vlook(DEAD
), FEXP_LOCAL
| FEXP_NSHELL
);
720 if(cp
== NULL
|| strlen(cp
) >= PATH_MAX
){
722 n_err(_("Failed to expand *DEAD*, setting default (%s): %s\n"),
723 VAL_DEAD
, n_shexp_quote_cp(cp
, FAL0
));
727 cp
= savecatsep(ok_vlook(TMPDIR
), '/', VAL_DEAD_BASENAME
);
728 n_err(_("Cannot expand *DEAD*, using: %s\n"), cp
);
736 nodename(int mayoverride
)
738 static char *sys_hostname
, *hostname
; /* XXX free-at-exit */
743 # ifdef HAVE_GETADDRINFO
744 struct addrinfo hints
, *res
;
746 struct hostent
*hent
;
751 if (mayoverride
&& (hn
= ok_vlook(hostname
)) != NULL
&& *hn
!= '\0') {
753 } else if ((hn
= sys_hostname
) == NULL
) {
757 # ifdef HAVE_GETADDRINFO
758 memset(&hints
, 0, sizeof hints
);
759 hints
.ai_family
= AF_UNSPEC
;
760 hints
.ai_flags
= AI_CANONNAME
;
761 if (getaddrinfo(hn
, NULL
, &hints
, &res
) == 0) {
762 if (res
->ai_canonname
!= NULL
) {
763 size_t l
= strlen(res
->ai_canonname
) +1;
766 memcpy(hn
, res
->ai_canonname
, l
);
771 hent
= gethostbyname(hn
);
776 sys_hostname
= sstrdup(hn
);
777 #if defined HAVE_SOCKETS && defined HAVE_GETADDRINFO
778 if (hn
!= ut
.nodename
)
784 if (hostname
!= NULL
&& hostname
!= sys_hostname
)
786 hostname
= sstrdup(hn
);
792 getrandstring(size_t length
){
798 #ifndef HAVE_POSIX_RANDOM
799 if(a_aux_rand
== NULL
)
803 /* We use our base64 encoder with _NOPAD set, so ensure the encoded result
804 * with PAD stripped is still longer than what the user requests, easy way */
805 data
= n_lofi_alloc(i
= length
+ 3);
807 #ifndef HAVE_POSIX_RANDOM
809 data
[i
] = (char)a_aux_rand_get8();
813 for(cp
= data
; i
> 0;){
814 union {ui32_t i4
; char c
[4];} r
;
817 r
.i4
= (ui32_t
)arc4random();
819 case 0: cp
[3] = r
.c
[3]; j
= 4;
820 case 3: cp
[2] = r
.c
[2];
821 case 2: cp
[1] = r
.c
[1];
822 default: cp
[0] = r
.c
[0]; break;
830 assert(length
+ 3 < UIZ_MAX
/ 4);
831 b64_encode_buf(&b64
, data
, length
+ 3,
832 B64_SALLOC
| B64_RFC4648URL
| B64_NOPAD
);
835 assert(b64
.l
>= length
);
836 b64
.s
[length
] = '\0';
842 boolify(char const *inbuf
, uiz_t inlen
, si8_t emptyrv
)
847 assert(inlen
== 0 || inbuf
!= NULL
);
849 if (inlen
== UIZ_MAX
)
850 inlen
= strlen(inbuf
);
853 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
855 if ((inlen
== 1 && (*inbuf
== '1' || *inbuf
== 'y' || *inbuf
== 'Y')) ||
856 !ascncasecmp(inbuf
, "true", inlen
) ||
857 !ascncasecmp(inbuf
, "yes", inlen
) ||
858 !ascncasecmp(inbuf
, "on", inlen
))
860 else if ((inlen
== 1 &&
861 (*inbuf
== '0' || *inbuf
== 'n' || *inbuf
== 'N')) ||
862 !ascncasecmp(inbuf
, "false", inlen
) ||
863 !ascncasecmp(inbuf
, "no", inlen
) ||
864 !ascncasecmp(inbuf
, "off", inlen
))
869 if((n_idec_buf(&ib
, inbuf
, inlen
, 0, 0, NULL
870 ) & (n_IDEC_STATE_EMASK
| n_IDEC_STATE_CONSUMED
)
871 ) != n_IDEC_STATE_CONSUMED
)
882 quadify(char const *inbuf
, uiz_t inlen
, char const *prompt
, si8_t emptyrv
)
887 assert(inlen
== 0 || inbuf
!= NULL
);
889 if (inlen
== UIZ_MAX
)
890 inlen
= strlen(inbuf
);
893 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
894 else if ((rv
= boolify(inbuf
, inlen
, -1)) < 0 &&
895 !ascncasecmp(inbuf
, "ask-", 4) &&
896 (rv
= boolify(inbuf
+ 4, inlen
- 4, -1)) >= 0 &&
897 (n_psonce
& n_PSO_INTERACTIVE
))
898 rv
= getapproval(prompt
, rv
);
904 n_is_all_or_aster(char const *name
){
908 rv
= ((name
[0] == '*' && name
[1] == '\0') || !asccasecmp(name
, "all"));
916 #ifdef HAVE_CLOCK_GETTIME
918 #elif defined HAVE_GETTIMEOFDAY
925 if((cp
= ok_vlook(SOURCE_DATE_EPOCH
)) != NULL
){
928 (void)/* XXX ?? posnum= */n_idec_ui64_cp(&tib
, cp
, 0, NULL
);
933 #ifdef HAVE_CLOCK_GETTIME
934 clock_gettime(CLOCK_REALTIME
, &ts
);
935 rv
= (time_t)ts
.tv_sec
;
936 #elif defined HAVE_GETTIMEOFDAY
937 gettimeofday(&ts
, NULL
);
938 rv
= (time_t)ts
.tv_sec
;
948 time_current_update(struct time_current
*tc
, bool_t full_update
)
951 tc
->tc_time
= n_time_epoch();
953 memcpy(&tc
->tc_gm
, gmtime(&tc
->tc_time
), sizeof tc
->tc_gm
);
954 memcpy(&tc
->tc_local
, localtime(&tc
->tc_time
), sizeof tc
->tc_local
);
955 sstpcpy(tc
->tc_ctime
, ctime(&tc
->tc_time
));
961 n_msleep(uiz_t millis
, bool_t ignint
){
965 #ifdef HAVE_NANOSLEEP
967 struct timespec ts
, trem
;
970 ts
.tv_sec
= millis
/ 1000;
971 ts
.tv_nsec
= (millis
%= 1000) * 1000 * 1000;
973 while((i
= nanosleep(&ts
, &trem
)) != 0 && ignint
)
975 rv
= (i
== 0) ? 0 : (trem
.tv_sec
* 1000) + (trem
.tv_nsec
/ (1000 * 1000));
978 #elif defined HAVE_SLEEP
979 if((millis
/= 1000) == 0)
981 while((rv
= sleep((unsigned int)millis
)) != 0 && ignint
)
984 # error Configuration should have detected a function for sleeping.
992 n_err(char const *format
, ...){
996 va_start(ap
, format
);
998 if(n_psonce
& n_PSO_INTERACTIVE
)
1004 bool_t doname
, doflush
;
1007 while(*format
== '\n'){
1009 putc('\n', n_stderr
);
1013 if((doname
= doflush
))
1014 a_aux_err_linelen
= 0;
1016 if((len
= strlen(format
)) > 0){
1017 if(doname
|| a_aux_err_linelen
== 0)
1018 fputs(VAL_UAGENT
": ", n_stderr
);
1019 vfprintf(n_stderr
, format
, ap
);
1024 if(format
[--len
] == '\n'){
1025 a_aux_err_linelen
= (i
-= ++len
);
1028 ++a_aux_err_linelen
;
1041 n_verr(char const *format
, va_list ap
){
1043 struct a_aux_err_node
*enp
;
1051 while(*format
== '\n'){
1052 putc('\n', n_stderr
);
1058 a_aux_err_linelen
= 0;
1060 if(n_psonce
& n_PSO_INTERACTIVE
){
1061 if((enp
= a_aux_err_tail
) != NULL
&&
1062 (enp
->ae_str
.s_len
> 0 &&
1063 enp
->ae_str
.s_dat
[enp
->ae_str
.s_len
- 1] != '\n'))
1064 n_string_push_c(&enp
->ae_str
, '\n');
1069 if((len
= strlen(format
)) == 0)
1072 n_pstate
|= n_PS_ERRORS_PROMPT
;
1075 if(doname
|| a_aux_err_linelen
== 0)
1076 fputs(VAL_UAGENT
": ", n_stderr
);
1081 if(format
[--len
] == '\n'){
1082 a_aux_err_linelen
= (i
-= ++len
);
1085 ++a_aux_err_linelen
;
1090 if(!(n_psonce
& n_PSO_INTERACTIVE
))
1092 vfprintf(n_stderr
, format
, ap
);
1096 n_LCTAV(ERRORS_MAX
> 3);
1098 /* Link it into the `errors' message ring */
1099 if((enp
= a_aux_err_tail
) == NULL
){
1101 enp
= smalloc(sizeof *enp
);
1102 enp
->ae_next
= NULL
;
1103 n_string_creat(&enp
->ae_str
);
1104 if(a_aux_err_tail
!= NULL
)
1105 a_aux_err_tail
->ae_next
= enp
;
1107 a_aux_err_head
= enp
;
1108 a_aux_err_tail
= enp
;
1111 (enp
->ae_str
.s_len
> 0 &&
1112 enp
->ae_str
.s_dat
[enp
->ae_str
.s_len
- 1] == '\n')){
1113 if(a_aux_err_cnt
< ERRORS_MAX
)
1116 a_aux_err_head
= (enp
= a_aux_err_head
)->ae_next
;
1117 a_aux_err_tail
->ae_next
= enp
;
1118 a_aux_err_tail
= enp
;
1119 enp
->ae_next
= NULL
;
1120 n_string_trunc(&enp
->ae_str
, 0);
1123 # ifdef HAVE_N_VA_COPY
1126 imax
= n_MIN(LINESIZE
, 1024);
1128 for(i
= imax
;; imax
= ++i
/* xxx could wrap, maybe */){
1129 # ifdef HAVE_N_VA_COPY
1137 n_string_resize(&enp
->ae_str
, (len
= enp
->ae_str
.s_len
) + (size_t)i
);
1138 i
= vsnprintf(&enp
->ae_str
.s_dat
[len
], (size_t)i
, format
, vac
);
1139 # ifdef HAVE_N_VA_COPY
1146 if(UICMP(z
, i
, >=, imax
)){
1147 # ifdef HAVE_N_VA_COPY
1148 /* XXX Check overflow for upcoming LEN+++i! */
1149 n_string_trunc(&enp
->ae_str
, len
);
1152 i
= (int)strlen(&enp
->ae_str
.s_dat
[len
]);
1157 n_string_trunc(&enp
->ae_str
, len
+ (size_t)i
);
1159 fwrite(&enp
->ae_str
.s_dat
[len
], 1, (size_t)i
, n_stderr
);
1161 #endif /* HAVE_ERRORS */
1169 n_err_sighdl(char const *format
, ...){ /* TODO sigsafe; obsolete! */
1173 va_start(ap
, format
);
1174 vfprintf(n_stderr
, format
, ap
);
1180 n_perr(char const *msg
, int errval
){
1191 e
= (errval
== 0) ? errno
: errval
;
1192 n_err(fmt
, msg
, strerror(e
));
1199 n_alert(char const *format
, ...){
1203 n_err(a_aux_err_linelen
> 0 ? _("\nAlert: ") : _("Alert: "));
1205 va_start(ap
, format
);
1214 n_panic(char const *format
, ...){
1218 if(a_aux_err_linelen
> 0){
1219 putc('\n', n_stderr
);
1220 a_aux_err_linelen
= 0;
1222 fprintf(n_stderr
, VAL_UAGENT
": Panic: ");
1224 va_start(ap
, format
);
1225 vfprintf(n_stderr
, format
, ap
);
1228 putc('\n', n_stderr
);
1231 abort(); /* Was exit(n_EXIT_ERR); for a while, but no */
1238 struct a_aux_err_node
*enp
;
1245 if(!asccasecmp(*argv
, "show"))
1247 if(!asccasecmp(*argv
, "clear"))
1251 _("Synopsis: errors: (<show> or) <clear> the error ring\n"));
1255 return (v
== NULL
) ? !STOP
: !OKAY
; /* xxx 1:bad 0:good -- do some */
1261 if(a_aux_err_head
== NULL
){
1262 fprintf(n_stderr
, _("The error ring is empty\n"));
1266 if((fp
= Ftmp(NULL
, "errors", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) ==
1268 fprintf(n_stderr
, _("tmpfile"));
1273 for(i
= 0, enp
= a_aux_err_head
; enp
!= NULL
; enp
= enp
->ae_next
)
1274 fprintf(fp
, "%4" PRIuZ
". %s", ++i
, n_string_cp(&enp
->ae_str
));
1275 /* We don't know whether last string ended with NL; be simple XXX */
1278 page_or_print(fp
, 0);
1284 a_aux_err_tail
= NULL
;
1285 a_aux_err_cnt
= a_aux_err_cnt_noted
= 0;
1286 a_aux_err_linelen
= 0;
1287 while((enp
= a_aux_err_head
) != NULL
){
1288 a_aux_err_head
= enp
->ae_next
;
1289 n_string_gut(&enp
->ae_str
);
1294 #endif /* HAVE_ERRORS */
1298 n_regex_err_to_str(const regex_t
*rep
, int e
){
1303 i
= regerror(e
, rep
, NULL
, 0) +1;
1305 regerror(e
, rep
, cp
, i
);