1/*	$NetBSD: sys_exits.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
2
3/*++
4/* NAME
5/*	sys_exits 3
6/* SUMMARY
7/*	sendmail-compatible exit status handling
8/* SYNOPSIS
9/*	#include <sys_exits.h>
10/*
11/*	typedef struct {
12/* .in +4
13/*	    int   status;	/* exit status */
14/*	    const char *dsn;	/* RFC 3463 */
15/*	    const char *text;	/* free text */
16/* .in -4
17/*	} SYS_EXITS_DETAIL;
18/*
19/*	int	SYS_EXITS_CODE(code)
20/*	int	code;
21/*
22/*	const char *sys_exits_strerror(code)
23/*	int	code;
24/*
25/*	const SYS_EXITS_DETAIL *sys_exits_detail(code)
26/*	int	code;
27/*
28/*	int	sys_exits_softerror(code)
29/*	int	code;
30/* DESCRIPTION
31/*	This module interprets sendmail-compatible process exit status
32/*	codes.
33/*
34/*	SYS_EXITS_CODE() returns non-zero when the specified code
35/*	is a sendmail-compatible process exit status code.
36/*
37/*	sys_exits_strerror() returns a descriptive text for the
38/*	specified sendmail-compatible status code, or a generic
39/*	text for an unknown status code.
40/*
41/*	sys_exits_detail() returns a table entry with assorted
42/*	information about the specified sendmail-compatible status
43/*	code, or a generic entry for an unknown status code.
44/*	The generic entry may be overwritten with each sys_exits_detail()
45/*	call.
46/*
47/*	sys_exits_softerror() returns non-zero when the specified
48/*	sendmail-compatible status code corresponds to a recoverable error.
49/*	An unknown status code is always unrecoverable.
50/* DIAGNOSTICS
51/*	Fatal: out of memory.
52/* LICENSE
53/* .ad
54/* .fi
55/*	The Secure Mailer license must be distributed with this software.
56/* AUTHOR(S)
57/*	Wietse Venema
58/*	IBM T.J. Watson Research
59/*	P.O. Box 704
60/*	Yorktown Heights, NY 10598, USA
61/*--*/
62
63/* System library. */
64
65#include <sys_defs.h>
66
67/* Utility library. */
68
69#include <msg.h>
70#include <vstring.h>
71
72/* Global library. */
73
74#include <sys_exits.h>
75
76/* Application-specific. */
77
78static const SYS_EXITS_DETAIL sys_exits_table[] = {
79    EX_USAGE, "5.3.0", "command line usage error",
80    EX_DATAERR, "5.6.0", "data format error",
81    EX_NOINPUT, "5.3.0", "cannot open input",
82    EX_NOUSER, "5.1.1", "user unknown",
83    EX_NOHOST, "5.1.2", "host name unknown",
84    EX_UNAVAILABLE, "5.3.0", "service unavailable",
85    EX_SOFTWARE, "5.3.0", "internal software error",
86    EX_OSERR, "4.3.0", "system resource problem",
87    EX_OSFILE, "5.3.0", "critical OS file missing",
88    EX_CANTCREAT, "5.2.0", "can't create user output file",
89    EX_IOERR, "5.3.0", "input/output error",
90    EX_TEMPFAIL, "4.3.0", "temporary failure",
91    EX_PROTOCOL, "5.5.0", "remote error in protocol",
92    EX_NOPERM, "5.7.0", "permission denied",
93    EX_CONFIG, "5.3.5", "local configuration error",
94};
95
96static VSTRING *sys_exits_def_text = 0;
97
98static SYS_EXITS_DETAIL sys_exits_default[] = {
99    0, "5.3.0", 0,
100};
101
102/* sys_exits_fake - fake an entry for an unknown code */
103
104static SYS_EXITS_DETAIL *sys_exits_fake(int code)
105{
106    if (sys_exits_def_text == 0)
107	sys_exits_def_text = vstring_alloc(30);
108
109    vstring_sprintf(sys_exits_def_text, "unknown mail system error %d", code);
110    sys_exits_default->text = vstring_str(sys_exits_def_text);
111    return (sys_exits_default);
112}
113
114/* sys_exits_strerror - map exit status to error string */
115
116const char *sys_exits_strerror(int code)
117{
118    if (!SYS_EXITS_CODE(code)) {
119	return (sys_exits_fake(code)->text);
120    } else {
121	return (sys_exits_table[code - EX__BASE].text);
122    }
123}
124
125/* sys_exits_detail - map exit status info table entry */
126
127const SYS_EXITS_DETAIL *sys_exits_detail(int code)
128{
129    if (!SYS_EXITS_CODE(code)) {
130	return (sys_exits_fake(code));
131    } else {
132	return (sys_exits_table + code - EX__BASE);
133    }
134}
135
136/* sys_exits_softerror  - determine if error is transient */
137
138int     sys_exits_softerror(int code)
139{
140    if (!SYS_EXITS_CODE(code)) {
141	return (sys_exits_default->dsn[0] == '4');
142    } else {
143	return (sys_exits_table[code - EX__BASE].dsn[0] == '4');
144    }
145}
146