/* $Id$ */
/*
* Copyright (c) 2006 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef FDM_H
#define FDM_H
#include <sys/param.h>
#include <sys/stat.h>
#ifdef HAVE_QUEUE_H
#include <sys/queue.h>
#else
#include "compat/queue.h"
#endif
#ifdef HAVE_TREE_H
#include <sys/tree.h>
#else
#include "compat/tree.h"
#endif
#include <dirent.h>
#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#ifndef _PUBLIC_
#define _PUBLIC_
#endif
#include <tdb.h>
#include <regex.h>
#ifdef PCRE
#include <pcre.h>
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
#define CHILDUSER "_fdm"
#define CONFFILE ".fdm.conf"
#define LOCKFILE ".fdm.lock"
#define DEFLOCKTIMEOUT 10
#define MAXQUEUEVALUE 50
#define DEFMAILQUEUE 2
#define DEFMAILSIZE (32 * 1024 * 1024) /* 32 MB */
#define MAXMAILSIZE (1 * 1024 * 1024 * 1024) /* 1 GB */
#define DEFSTRIPCHARS "\\<>$%^&*|{}[]\"'`;"
#define MAXACTIONCHAIN 5
#define DEFTIMEOUT (900 * 1000)
#define LOCKSLEEPTIME 10000 /* 0.1 seconds */
#define MAXNAMESIZE 64
#define DEFUMASK (S_IRWXG|S_IRWXO)
#define FILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
#define DIRMODE (S_IRWXU|S_IRWXG|S_IRWXO)
#define MAXUSERLEN 256
extern char *__progname;
/* Various compatibility stuff. */
#ifndef UID_MAX
#define UID_MAX UINT_MAX
#endif
#ifndef GID_MAX
#define GID_MAX UINT_MAX
#endif
#ifndef INFTIM
#define INFTIM -1
#endif
#ifndef WAIT_ANY
#define WAIT_ANY -1
#endif
#ifndef GLOB_BRACE
#define GLOB_BRACE 0
#endif
#ifndef ACCESSPERMS
#define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO)
#endif
#ifndef MAXNAMLEN
#define MAXNAMLEN 255
#endif
#ifndef __dead
#define __dead __attribute__ ((__noreturn__))
#endif
#ifndef __packed
#define __packed __attribute__ ((__packed__))
#endif
/* Databases are not portable between endiness on OSs without these. */
#ifndef htole64
#define htole64
#endif
#ifndef letoh64
#define letoh64
#endif
/* Fatal errors. */
#define fatal(msg) log_fatal("%s: %s", __func__, msg);
#define fatalx(msg) log_fatalx("%s: %s", __func__, msg);
/* Apply umask. */
#define UMASK(mask) ((mask) & ~conf.file_umask)
/* Convert a file mode for %o%o%o printf. */
#define MODE(m) \
(m & S_IRUSR ? 4 : 0) + (m & S_IWUSR ? 2 : 0) + (m & S_IXUSR ? 1 : 0), \
(m & S_IRGRP ? 4 : 0) + (m & S_IWGRP ? 2 : 0) + (m & S_IXGRP ? 1 : 0), \
(m & S_IROTH ? 4 : 0) + (m & S_IWOTH ? 2 : 0) + (m & S_IXOTH ? 1 : 0)
/* Definition to shut gcc up about unused arguments. */
#define unused __attribute__ ((unused))
/* Attribute to make gcc check printf-like arguments. */
#define printflike1 __attribute__ ((format (printf, 1, 2)))
#define printflike2 __attribute__ ((format (printf, 2, 3)))
#define printflike3 __attribute__ ((format (printf, 3, 4)))
#define printflike4 __attribute__ ((format (printf, 4, 5)))
#define printflike5 __attribute__ ((format (printf, 5, 6)))
#define printflike6 __attribute__ ((format (printf, 6, 7)))
/* Ensure buffer size. */
#define ENSURE_SIZE(buf, len, size) do { \
(buf) = ensure_size(buf, &(len), 1, size); \
} while (0)
#define ENSURE_FOR(buf, len, size, adj) do { \
(buf) = ensure_for(buf, &(len), size, adj); \
} while (0)
/* Description buffer size. */
#define DESCBUFSIZE 512
/* Replace buffer size. */
#define REPLBUFSIZE 64
/* Lengths of time. */
#define TIME_MINUTE 60LL
#define TIME_HOUR 3600LL
#define TIME_DAY 86400LL
#define TIME_WEEK 604800LL
#define TIME_MONTH 2419200LL
#define TIME_YEAR 29030400LL
/* Number of matches to use. */
#define NPMATCH 10
/* Account and action name match. */
#define account_match(p, n) (fnmatch(p, n, 0) == 0)
#define action_match(p, n) (fnmatch(p, n, 0) == 0)
#include "array.h"
#include "io.h"
/* Macros in configuration file. */
struct macro {
char name[MAXNAMESIZE];
union {
long long num;
char *str;
} value;
enum {
MACRO_NUMBER,
MACRO_STRING
} type;
TAILQ_ENTRY(macro) entry;
};
TAILQ_HEAD(macros, macro);
/* Command-line commands. */
enum fdmop {
FDMOP_NONE = 0,
FDMOP_POLL,
FDMOP_FETCH,
FDMOP_CACHE
};
/*
* Wrapper struct for a string that needs tag replacement before it is used.
* This is used for anything that needs to be replaced after account and mail
* data are available, everything else is replaced at parse time.
*/
struct replstr {
char *str;
} __packed;
ARRAY_DECL(replstrs, struct replstr);
/* Similar to replstr but needs expand_path too. */
struct replpath {
char *str;
} __packed;
/* Server description. */
struct server {
char *host;
char *port;
struct addrinfo *ai;
int ssl;
int verify;
int insecure;
};
/* Proxy type. */
enum proxytype {
PROXY_HTTP,
PROXY_HTTPS,
PROXY_SOCKS5
};
/* Proxy definition. */
struct proxy {
enum proxytype type;
char *user;
char *pass;
struct server server;
};
/* Shared memory. */
struct shm {
char name[MAXNAMLEN];
int fd;
#define SHM_REGISTER(shm) cleanup_register(shm_path(shm))
#define SHM_DEREGISTER(shm) cleanup_deregister(shm_path(shm))
void *data;
size_t size;
};
/* Generic array of strings. */
ARRAY_DECL(strings, char *);
/* Options for final mail handling. */
enum decision {
DECISION_NONE,
DECISION_DROP,
DECISION_KEEP
};
/* String block entry. */
struct strbent {
size_t key;
size_t value;
};
/* String block header. */
struct strb {
u_int ent_used;
u_int ent_max;
size_t str_used;
size_t str_size;
};
/* Initial string block slots and block size. */
#define STRBOFFSET (((sizeof (struct strb)) + 0x3f) & ~0x3f)
#define STRBENTRIES 64
#define STRBBLOCK 1024
/* String block access macros. */
#define STRB_BASE(sb) (((char *) (sb)) + STRBOFFSET)
#define STRB_KEY(sb, sbe) (STRB_BASE(sb) + (sbe)->key)
#define STRB_VALUE(sb, sbe) (STRB_BASE(sb) + (sbe)->value)
#define STRB_ENTBASE(sb) (STRB_BASE(sb) + (sb)->str_size)
#define STRB_ENTOFF(sb, n) ((n) * (sizeof (struct strbent)))
#define STRB_ENTSIZE(sb) STRB_ENTOFF(sb, (sb)->ent_max)
#define STRB_ENTRY(sb, n) ((void *) (STRB_ENTBASE(sb) + STRB_ENTOFF(sb, n)))
#define STRB_SIZE(sb) (STRBOFFSET + (sb)->str_size + STRB_ENTSIZE((sb)))
/* Regexp wrapper structs. */
struct re {
char *str;
#ifndef PCRE
regex_t re;
#else
pcre *pcre;
#endif
int flags;
};
struct rm {
int valid;
size_t so;
size_t eo;
};
struct rmlist {
int valid;
struct rm list[NPMATCH];
};
/* Regexp flags. */
#define RE_IGNCASE 0x1
#define RE_NOSUBST 0x2
/* Cache data. */
struct cache {
TDB_CONTEXT *db;
char *path;
uint64_t expire;
TAILQ_ENTRY(cache) entry;
};
struct cacheitem {
uint64_t tim;
uint32_t pad[4];
} __packed;
/* A single mail. */
struct mail {
u_int idx;
double tim;
struct strb *tags;
struct shm shm;
struct attach *attach;
int attach_built;
char *base;
char *data;
size_t off;
size_t size; /* size of mail */
size_t space; /* size of allocated area */
size_t body; /* offset of body */
ARRAY_DECL(, size_t) wrapped; /* list of wrapped lines */
char wrapchar; /* wrapped character */
/* XXX move below into special struct and just cp it in mail_*? */
struct rmlist rml; /* regexp matches */
enum decision decision; /* final deliver decision */
void (*auxfree)(void *);
void *auxdata;
};
/* Mail match/delivery return codes. */
#define MAIL_CONTINUE 0
#define MAIL_DELIVER 1
#define MAIL_MATCH 2
#define MAIL_ERROR 3
#define MAIL_BLOCKED 4
#define MAIL_DONE 5
/* Mail match/delivery context. */
struct mail_ctx {
int done;
u_int msgid;
struct account *account;
struct io *io;
struct mail *mail;
u_int ruleidx;
struct rule *rule;
ARRAY_DECL(, struct rule *) stack;
struct expritem *expritem;
int result;
int matched;
TAILQ_HEAD(, deliver_ctx) dqueue;
TAILQ_ENTRY(mail_ctx) entry;
};
TAILQ_HEAD(mail_queue, mail_ctx);
/* An attachment. */
struct attach {
u_int idx;
size_t data;
size_t body;
size_t size;
char *type;
char *name;
struct attach *parent;
TAILQ_HEAD(, attach) children;
TAILQ_ENTRY(attach) entry;
};
/* Privsep message types. */
enum msgtype {
MSG_ACTION,
MSG_EXIT,
MSG_DONE,
MSG_COMMAND
};
/* Privsep message data. */
struct msgdata {
int error;
struct mail mail;
/* These only work so long as they aren't moved in either process. */
struct account *account;
struct actitem *actitem;
struct match_command_data *cmddata;
uid_t uid;
gid_t gid;
};
/* Privsep message buffer. */
struct msgbuf {
void *buf;
size_t len;
};
/* Privsep message. */
struct msg {
u_int id;
enum msgtype type;
size_t size;
struct msgdata data;
};
/* A single child. */
struct child {
pid_t pid;
struct child *parent;
struct io *io;
void *data;
int (*msg)(struct child *, struct msg *, struct msgbuf *);
void *buf;
size_t len;
int exit_req;
};
/* List of children. */
ARRAY_DECL(children, struct child *);
/* Fetch child data. */
struct child_fetch_data {
struct account *account;
enum fdmop op;
struct children *children;
};
/* Deliver child data. */
struct child_deliver_data {
void (*hook)(int, struct account *, struct msg *,
struct child_deliver_data *, int *);
struct child *child; /* the source of the request */
uid_t uid;
gid_t gid;
u_int msgid;
const char *name;
struct account *account;
struct mail *mail;
struct actitem *actitem;
struct deliver_ctx *dctx;
struct mail_ctx *mctx;
struct match_command_data *cmddata;
};
/* Account entry. */
struct account {
u_int idx;
char name[MAXNAMESIZE];
struct replstrs *users;
int disabled;
int keep;
struct fetch *fetch;
void *data;
TAILQ_ENTRY(account) entry;
TAILQ_ENTRY(account) active_entry;
};
/* Action item. */
struct actitem {
u_int idx;
struct deliver *deliver;
void *data;
TAILQ_ENTRY(actitem) entry;
};
/* Action list. */
TAILQ_HEAD(actlist, actitem);
/* Action definition. */
struct action {
char name[MAXNAMESIZE];
struct replstrs *users;
struct actlist *list;
TAILQ_ENTRY(action) entry;
};
/* Actions arrays. */
ARRAY_DECL(actions, struct action *);
/* Match areas. */
enum area {
AREA_BODY,
AREA_HEADERS,
AREA_ANY
};
/* Expression operators. */
enum exprop {
OP_NONE,
OP_AND,
OP_OR
};
/* Expression item. */
struct expritem {
struct match *match;
void *data;
enum exprop op;
int inverted;
TAILQ_ENTRY(expritem) entry;
};
/* Expression struct. */
TAILQ_HEAD(expr, expritem);
/* Rule list. */
TAILQ_HEAD(rules, rule);
/* Rule entry. */
struct rule {
u_int idx;
struct expr *expr;
struct replstrs *users;
int stop; /* stop matching at this rule */
struct rules rules;
struct action *lambda;
struct replstrs *actions;
TAILQ_ENTRY(rule) entry;
};
/* Lock types. */
#define LOCK_FCNTL 0x1
#define LOCK_FLOCK 0x2
#define LOCK_DOTLOCK 0x4
/* User info settings. */
struct userdata {
char *name;
char *home;
uid_t uid;
gid_t gid;
};
/* User lookup order. */
typedef struct userdata *(*userfunction)(const char *);
ARRAY_DECL(userfunctions, userfunction);
/* Configuration settings. */
struct conf {
int debug;
int syslog;
uid_t child_uid;
gid_t child_gid;
char *tmp_dir;
struct strings incl;
struct strings excl;
struct proxy *proxy;
char *user_home;
struct userfunctions *user_order;
char *host_name;
char *host_fqdn;
char *host_address;
char *conf_file;
char *strip_chars;
int check_only;
int allow_many;
int keep_all;
int no_received;
int no_create;
int verify_certs;
u_int purge_after;
enum decision impl_act;
int max_accts;
char *lock_file;
int lock_wait;
int lock_timeout;
int queue_high;
int queue_low;
mode_t file_umask;
gid_t file_group;
size_t max_size;
int timeout;
int del_big;
int ignore_errors;
u_int lock_types;
char *def_user;
char *cmd_user;
TAILQ_HEAD(, cache) caches;
TAILQ_HEAD(, account) accounts;
TAILQ_HEAD(, action) actions;
struct rules rules;
};
extern struct conf conf;
/* Command flags. */
#define CMD_IN 0x1
#define CMD_OUT 0x2
#define CMD_ONCE 0x4
/* Command data. */
struct cmd {
pid_t pid;
int status;
int flags;
const char *buf;
size_t len;
struct io *io_in;
struct io *io_out;
struct io *io_err;
};
/* Comparison operators. */
enum cmp {
CMP_EQ,
CMP_NE,
CMP_LT,
CMP_GT
};
/* Configuration file (used by parser). */
struct file {
FILE *f;
int line;
const char *path;
};
ARRAY_DECL(files, struct file *);
#ifndef HAVE_SETRESUID
#define setresuid(r, e, s) setreuid(r, e)
#endif
#ifndef HAVE_SETRESGID
#define setresgid(r, e, s) setregid(r, e)
#endif
#ifndef HAVE_STRTONUM
/* strtonum.c */
long long strtonum(const char *, long long, long long, const char **);
#endif
#ifndef HAVE_STRLCPY
/* strlcpy.c */
size_t strlcpy(char *, const char *, size_t);
#endif
#ifndef HAVE_STRLCAT
/* strlcat.c */
size_t strlcat(char *, const char *, size_t);
#endif
#ifndef HAVE_B64_NTOP
/* base64.c */
int b64_ntop(u_char const *, size_t, char *, size_t);
int b64_pton(char const *, u_char *, size_t);
#endif
/* shm.c */
char *shm_path(struct shm *);
void *shm_create(struct shm *, size_t);
int shm_owner(struct shm *, uid_t, gid_t);
void shm_destroy(struct shm *);
void shm_close(struct shm *);
void *shm_reopen(struct shm *);
void *shm_resize(struct shm *, size_t, size_t);
/* lex.c */
int yylex(void);
/* parse.y */
extern struct macros parse_macros;
extern struct files parse_filestack;
extern struct file *parse_file;
extern struct strb *parse_tags;
int parse_conf(const char *, struct strings *);
__dead printflike1 void yyerror(const char *, ...);
/* parse-fn.c */
char *expand_path(const char *, const char *);
char *run_command(const char *, const char *);
char *fmt_replstrs(const char *, struct replstrs *);
char *fmt_strings(const char *, struct strings *);
int have_accounts(char *);
struct account *find_account(char *);
struct action *find_action(char *);
struct actions *match_actions(const char *);
struct macro *extract_macro(char *);
struct macro *find_macro(const char *);
void find_netrc(const char *, char **, char **);
int find_netrc1(const char *, char **, char **, char **);
void free_account(struct account *);
void free_action(struct action *);
void free_actitem(struct actitem *);
void free_cache(struct cache *);
void free_replstrs(struct replstrs *);
void free_rule(struct rule *);
void free_strings(struct strings *);
void make_actlist(struct actlist *, char *, size_t);
void print_action(struct action *);
void print_rule(struct rule *);
/* netrc.c */
FILE *netrc_open(const char *, char **);
void netrc_close(FILE *);
int netrc_lookup(FILE *, const char *, char **, char **);
/* fdm.c */
extern volatile sig_atomic_t sigusr1;
extern volatile sig_atomic_t sigint;
extern volatile sig_atomic_t sigterm;
double get_time(void);
void dropto(uid_t, gid_t);
int check_incl(const char *);
int check_excl(const char *);
int use_account(struct account *, char **);
void fill_host(void);
__dead void usage(void);
/* cache-op.c */
__dead void cache_op(int, char **);
/* re.c */
int re_compile(struct re *, const char *, int, char **);
int re_string(struct re *, const char *, struct rmlist *, char **);
int re_block(struct re *, const void *, size_t, struct rmlist *,
char **);
void re_free(struct re *);
/* attach.c */
struct attach *attach_visit(struct attach *, u_int *);
void printflike2 attach_log(struct attach *, const char *, ...);
struct attach *attach_build(struct mail *);
void attach_free(struct attach *);
/* lookup.c */
struct userdata *user_lookup(const char *, struct userfunctions *);
void user_free(struct userdata *);
struct userdata *user_copy(struct userdata *);
/* lookup-passwd.c */
struct userdata *passwd_lookup(const char *);
/* privsep.c */
int privsep_send(struct io *, struct msg *, struct msgbuf *);
int privsep_check(struct io *);
int privsep_recv(struct io *, struct msg *, struct msgbuf *);
/* command.c */
struct cmd *cmd_start(const char *, int, const char *, size_t, char **);
int cmd_poll(struct cmd *, char **, char **, char **, size_t *,
int, char **);
void cmd_free(struct cmd *);
/* child.c */
int child_fork(void);
__dead void child_exit(int);
struct child *child_start(struct children *, uid_t, gid_t,
int (*)(struct child *, struct io *),
int (*)(struct child *, struct msg *, struct msgbuf *),
void *, struct child *);
/* child-fetch.c */
int open_cache(struct account *, struct cache *);
int child_fetch(struct child *, struct io *);
/* child-deliver.c */
int child_deliver(struct child *, struct io *);
void child_deliver_action_hook(int, struct account *, struct msg *,
struct child_deliver_data *, int *);
void child_deliver_cmd_hook(int, struct account *, struct msg *,
struct child_deliver_data *, int *);
/* parent-fetch.c */
int parent_fetch(struct child *, struct msg *, struct msgbuf *);
/* parent-deliver.c */
int parent_deliver(struct child *, struct msg *, struct msgbuf *);
/* timer.c */
int timer_expired(void);
void timer_set(int);
void timer_cancel(void);
/* connect.c */
char *sslerror(const char *);
char *sslerror2(int, const char *);
SSL *makessl(struct server *, int, int, int, char **);
void getaddrs(const char *, char **, char **);
struct proxy *getproxy(const char *);
struct io *connectproxy(struct server *, int, struct proxy *,
const char *, int, char **);
struct io *connectio(struct server *, int, const char *, int, char **);
struct io *connectunix(const char *, char **);
/* file.c */
int printflike3 ppath(char *, size_t, const char *, ...);
int vppath(char *, size_t, const char *, va_list);
int openlock(const char *, int, u_int);
int createlock(const char *, int, uid_t, gid_t, mode_t, u_int);
void closelock(int, const char *, u_int);
int locksleep(const char *, const char *, long long *);
int xcreate(const char *, int, uid_t, gid_t, mode_t);
int xmkdir(const char *, uid_t, gid_t, mode_t);
int xmkpath(const char *, uid_t, gid_t, mode_t);
const char *checkmode(struct stat *, mode_t);
const char *checkowner(struct stat *, uid_t);
const char *checkgroup(struct stat *, gid_t);
int safemove(const char *, const char *);
/* mail.c */
int mail_open(struct mail *, size_t);
void mail_send(struct mail *, struct msg *);
int mail_receive(struct mail *, struct msg *, int);
void mail_close(struct mail *);
void mail_destroy(struct mail *);
int mail_resize(struct mail *, size_t);
void line_init(struct mail *, char **, size_t *);
void line_next(struct mail *, char **, size_t *);
int printflike3 insert_header(struct mail *, const char *, const char *, ...);
int remove_header(struct mail *, const char *);
char *find_header(struct mail *, const char *, size_t *, int);
char *match_header(struct mail *, const char *, size_t *, int);
size_t find_body(struct mail *);
void count_lines(struct mail *, u_int *, u_int *);
int append_line(struct mail *, const char *, size_t);
char *find_address(char *, size_t, size_t *);
void trim_from(struct mail *);
char *make_from(struct mail *, char *);
u_int fill_wrapped(struct mail *);
void set_wrapped(struct mail *, char);
/* mail-time.c */
char *rfc822time(time_t, char *, size_t);
int mailtime(struct mail *, time_t *);
/* mail-state.c */
int mail_match(struct mail_ctx *, struct msg *, struct msgbuf *);
int mail_deliver(struct mail_ctx *, struct msg *, struct msgbuf *);
/* db-tdb.c */
TDB_CONTEXT *db_open(char *);
void db_close(TDB_CONTEXT *);
int db_add(TDB_CONTEXT *, char *);
int db_remove(TDB_CONTEXT *, char *);
int db_contains(TDB_CONTEXT *, char *);
int db_size(TDB_CONTEXT *);
int db_print(TDB_CONTEXT *, void (*)(const char *, ...));
int db_expire(TDB_CONTEXT *, uint64_t);
int db_clear(TDB_CONTEXT *);
/* cleanup.c */
void cleanup_check(void);
void cleanup_flush(void);
void cleanup_purge(void);
void cleanup_register(const char *);
void cleanup_deregister(const char *);
/* strb.c */
void strb_create(struct strb **);
void strb_clear(struct strb **);
void strb_destroy(struct strb **);
void strb_dump(struct strb *, const char *,
void (*)(const char *, ...));
void printflike3 strb_add(struct strb **, const char *, const char *, ...);
void strb_vadd(struct strb **, const char *, const char *, va_list);
struct strbent *strb_find(struct strb *, const char *);
struct strbent *strb_match(struct strb *, const char *);
/* replace.c */
void printflike3 add_tag(struct strb **, const char *, const char *, ...);
const char *find_tag(struct strb *, const char *);
const char *match_tag(struct strb *, const char *);
void default_tags(struct strb **, const char *);
void update_tags(struct strb **, struct userdata *);
void reset_tags(struct strb **);
char *replacestr(struct replstr *, struct strb *, struct mail *,
struct rmlist *);
char *replacepath(struct replpath *, struct strb *, struct mail *,
struct rmlist *, const char *);
/* log.c */
#define LOG_FACILITY LOG_MAIL
void log_open_syslog(int);
void log_open_tty(int);
void log_open_file(int, const char *);
void log_close(void);
void log_vwrite(int, const char *, va_list);
void log_write(int, const char *, ...);
void printflike1 log_warn(const char *, ...);
void printflike1 log_warnx(const char *, ...);
void printflike1 log_info(const char *, ...);
void printflike1 log_debug(const char *, ...);
void printflike1 log_debug2(const char *, ...);
void printflike1 log_debug3(const char *, ...);
__dead void log_vfatal(const char *, va_list);
__dead void log_fatal(const char *, ...);
__dead void log_fatalx(const char *, ...);
/* xmalloc.c */
void *ensure_size(void *, size_t *, size_t, size_t);
void *ensure_for(void *, size_t *, size_t, size_t);
char *xstrdup(const char *);
void *xcalloc(size_t, size_t);
void *xmalloc(size_t);
void *xrealloc(void *, size_t, size_t);
void xfree(void *);
int printflike2 xasprintf(char **, const char *, ...);
int xvasprintf(char **, const char *, va_list);
int printflike3 xsnprintf(char *, size_t, const char *, ...);
int xvsnprintf(char *, size_t, const char *, va_list);
int printflike3 printpath(char *, size_t, const char *, ...);
char *xdirname(const char *);
char *xbasename(const char *);
#endif /* FDM_H */