#define COMPAT_C_IMPL #include "compat.h" #ifndef __OpenBSD__ #include #include #include #include #include #include #ifndef program_invocation_short_name extern char *__progname; #define program_invocation_short_name (__progname ? __progname : "ftp") #endif long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; int error = 0; char *ep; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "too large", ERANGE }, { "too small", ERANGE }, { "invalid", EINVAL }, }; ev[0].err = errno; errno = 0; if (minval > maxval) { error = 3; ev[error].err = EINVAL; ev[error].errstr = "invalid"; } else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = 3; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = 1; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = 2; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } if (n == 0) { if (siz != 0) *d = '\0'; while (*s++) ; } return(s - src - 1); } void err(int eval, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (fmt != NULL) { fprintf(stderr, "%s: ", program_invocation_short_name); vfprintf(stderr, fmt, ap); va_end(ap); if (errno != 0) fprintf(stderr, ": %s", strerror(errno)); fprintf(stderr, "\n"); } else { if (errno != 0) fprintf(stderr, "%s: %s\n", program_invocation_short_name, strerror(errno)); va_end(ap); } exit(eval); } void errx(int eval, const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s: ", program_invocation_short_name); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); exit(eval); } void warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (fmt != NULL) { fprintf(stderr, "%s: ", program_invocation_short_name); vfprintf(stderr, fmt, ap); va_end(ap); if (errno != 0) fprintf(stderr, ": %s", strerror(errno)); fprintf(stderr, "\n"); } else { if (errno != 0) fprintf(stderr, "%s: %s\n", program_invocation_short_name, strerror(errno)); va_end(ap); } errno = 0; } void warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s: ", program_invocation_short_name); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } #if defined(__linux__) && !defined(HAVE_FUNOPEN) #define _GNU_SOURCE #include struct funopen_cookie { const void *cookie; int (*readfn)(void *, char *, int); int (*writefn)(void *, const char *, int); fpos_t (*seekfn)(void *, fpos_t, int); int (*closefn)(void *); }; static ssize_t funopen_read(void *cookie, char *buf, size_t size) { struct funopen_cookie *c = cookie; if (c->readfn) return c->readfn((void *)c->cookie, buf, (int)size); return -1; } static ssize_t funopen_write(void *cookie, const char *buf, size_t size) { struct funopen_cookie *c = cookie; if (c->writefn) return c->writefn((void *)c->cookie, buf, (int)size); return -1; } static int funopen_seek(void *cookie, off64_t *offset, int whence) { struct funopen_cookie *c = cookie; fpos_t pos = (fpos_t)*offset; int ret; if (c->seekfn) { ret = c->seekfn((void *)c->cookie, pos, whence); if (ret == 0) *offset = (off64_t)pos; return ret; } return -1; } static int funopen_close(void *cookie) { struct funopen_cookie *c = cookie; if (c->closefn) return c->closefn((void *)c->cookie); free(c); return 0; } FILE * funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int), fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *)) { struct funopen_cookie *c = malloc(sizeof(*c)); if (c == NULL) return NULL; c->cookie = cookie; c->readfn = readfn; c->writefn = writefn; c->seekfn = seekfn; c->closefn = closefn; cookie_io_functions_t funcs = { .read = funopen_read, .write = funopen_write, .seek = funopen_seek, .close = funopen_close }; return fopencookie(c, "r+", funcs); } #endif #if defined(__APPLE__) #include int strnvis_openbsd(char *dst, const char *src, size_t dlen, int flags) { return strnvis(dst, dlen, src, flags); } #endif #ifndef __OpenBSD__ #include #ifndef u_char #define u_char unsigned char #endif static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; int b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; u_char input[3]; u_char output[4]; u_int i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } if (srclength != 0) { input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) target[datalength++] = Pad64; else target[datalength++] = Base64[output[2]]; target[datalength++] = Pad64; } if (datalength >= targsize) return (-1); target[datalength] = '\0'; return (datalength); } #endif #if !defined(__OpenBSD__) #include #include int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask) { int timeout_ms; (void)sigmask; /* Ignoring signal mask for simplicity */ if (timeout_ts == NULL) { timeout_ms = -1; } else { /* Convert timespec to milliseconds */ timeout_ms = timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000; } return poll(fds, nfds, timeout_ms); } #endif #endif