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 
78 static 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 
96 static VSTRING *sys_exits_def_text = 0;
97 
98 static 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 
sys_exits_fake(int code)104 static 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 
sys_exits_strerror(int code)116 const 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 
sys_exits_detail(int code)127 const 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 
sys_exits_softerror(int code)138 int     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