Postfix3.3.1
mail_version.c
[詳解]
1 /*++
2 /* NAME
3 /* mail_version 3
4 /* SUMMARY
5 /* time-dependent probe sender addresses
6 /* SYNOPSIS
7 /* #include <mail_version.h>
8 /*
9 /* typedef struct {
10 /* char *program; /* postfix */
11 /* int major; /* 2 */
12 /* int minor; /* 9 */
13 /* int patch; /* patchlevel or -1 */
14 /* char *snapshot; /* null or snapshot info */
15 /* } MAIL_VERSION;
16 /*
17 /* MAIL_VERSION *mail_version_parse(version_string, why)
18 /* const char *version_string;
19 /* const char **why;
20 /*
21 /* void mail_version_free(mp)
22 /* MAIL_VERSION *mp;
23 /*
24 /* const char *get_mail_version()
25 /*
26 /* int check_mail_version(version_string)
27 /* const char *version_string;
28 /* DESCRIPTION
29 /* This module understands the format of Postfix version strings
30 /* (for example the default value of "mail_version"), and
31 /* provides support to compare the compile-time version of a
32 /* Postfix program with the run-time version of a Postfix
33 /* library. Apparently, some distributions don't use proper
34 /* so-number versioning, causing programs to fail erratically
35 /* after an update replaces the library but not the program.
36 /*
37 /* A Postfix version string consists of two or three parts
38 /* separated by a single "-" character:
39 /* .IP \(bu
40 /* The first part is a string with the program name.
41 /* .IP \(bu
42 /* The second part is the program version: either two or three
43 /* non-negative integer numbers separated by single "."
44 /* character. Stable releases have a major version, minor
45 /* version and patchlevel; experimental releases (snapshots)
46 /* have only major and minor version numbers.
47 /* .IP \(bu
48 /* The third part is ignored with a stable release, otherwise
49 /* it is a string with the snapshot release date plus some
50 /* optional information.
51 /*
52 /* mail_version_parse() parses a version string.
53 /*
54 /* get_mail_version() returns the version string (the value
55 /* of DEF_MAIL_VERSION) that is compiled into the library.
56 /*
57 /* check_mail_version() compares the caller's version string
58 /* (usually the value of DEF_MAIL_VERSION) that is compiled
59 /* into the caller, and logs a warning when the strings differ.
60 /* DIAGNOSTICS
61 /* In the case of a parsing error, mail_version_parse() returns
62 /* a null pointer, and sets the why argument to a string with
63 /* problem details.
64 /* LICENSE
65 /* .ad
66 /* .fi
67 /* The Secure Mailer license must be distributed with this software.
68 /* AUTHOR(S)
69 /* Wietse Venema
70 /* IBM T.J. Watson Research
71 /* P.O. Box 704
72 /* Yorktown Heights, NY 10598, USA
73 /*--*/
74 
75 /* System library. */
76 
77 #include <sys_defs.h>
78 #include <stdlib.h>
79 #include <errno.h>
80 
81 /* Utility library. */
82 
83 #include <msg.h>
84 #include <mymalloc.h>
85 #include <stringops.h>
86 #include <split_at.h>
87 
88 /* Global library. */
89 
90 #include <mail_version.h>
91 
92 /* mail_version_int - convert integer */
93 
94 static int mail_version_int(const char *strval)
95 {
96  char *end;
97  int intval;
98  long longval;
99 
100  errno = 0;
101  intval = longval = strtol(strval, &end, 10);
102  if (*strval == 0 || *end != 0 || errno == ERANGE || longval != intval)
103  intval = (-1);
104  return (intval);
105 }
106 
107 /* mail_version_worker - do the parsing work */
108 
109 static const char *mail_version_worker(MAIL_VERSION *mp, char *cp)
110 {
111  char *major_field;
112  char *minor_field;
113  char *patch_field;
114 
115  /*
116  * Program name.
117  */
118  if ((mp->program = mystrtok(&cp, "-")) == 0)
119  return ("no program name");
120 
121  /*
122  * Major, minor, patchlevel. If this is a stable release, then we ignore
123  * text after the patchlevel, in case there are vendor extensions.
124  */
125  if ((major_field = mystrtok(&cp, "-")) == 0)
126  return ("missing major version");
127 
128  if ((minor_field = split_at(major_field, '.')) == 0)
129  return ("missing minor version");
130  if ((mp->major = mail_version_int(major_field)) < 0)
131  return ("bad major version");
132  patch_field = split_at(minor_field, '.');
133  if ((mp->minor = mail_version_int(minor_field)) < 0)
134  return ("bad minor version");
135 
136  if (patch_field == 0)
137  mp->patch = -1;
138  else if ((mp->patch = mail_version_int(patch_field)) < 0)
139  return ("bad patchlevel");
140 
141  /*
142  * Experimental release. If this is not a stable release, we take
143  * everything to the end of the string.
144  */
145  if (patch_field != 0)
146  mp->snapshot = 0;
147  else if ((mp->snapshot = mystrtok(&cp, "")) == 0)
148  return ("missing snapshot field");
149 
150  return (0);
151 }
152 
153 /* mail_version_parse - driver */
154 
155 MAIL_VERSION *mail_version_parse(const char *string, const char **why)
156 {
157  MAIL_VERSION *mp;
158  char *saved_string;
159  const char *err;
160 
161  mp = (MAIL_VERSION *) mymalloc(sizeof(*mp));
162  saved_string = mystrdup(string);
163  if ((err = mail_version_worker(mp, saved_string)) != 0) {
164  *why = err;
165  myfree(saved_string);
166  myfree((void *) mp);
167  return (0);
168  } else {
169  return (mp);
170  }
171 }
172 
173 /* mail_version_free - destroy version information */
174 
176 {
177  myfree(mp->program);
178  myfree((void *) mp);
179 }
180 
181 /* get_mail_version - return parsed mail version string */
182 
183 const char *get_mail_version(void)
184 {
185  return (DEF_MAIL_VERSION);
186 }
187 
188 /* check_mail_version - compare caller version with library version */
189 
190 void check_mail_version(const char *version_string)
191 {
192  if (strcmp(version_string, DEF_MAIL_VERSION) != 0)
193  msg_warn("Postfix library version mis-match: wanted %s, found %s",
194  version_string, DEF_MAIL_VERSION);
195 }
196 
197 #ifdef TEST
198 
199 #include <unistd.h>
200 #include <vstring.h>
201 #include <vstream.h>
202 #include <vstring_vstream.h>
203 
204 #define STR(x) vstring_str(x)
205 
206 /* parse_sample - parse a sample string from argv or stdin */
207 
208 static void parse_sample(const char *sample)
209 {
210  MAIL_VERSION *mp;
211  const char *why;
212 
213  mp = mail_version_parse(sample, &why);
214  if (mp == 0) {
215  vstream_printf("ERROR: %s: %s\n", sample, why);
216  } else {
217  vstream_printf("program: %s\t", mp->program);
218  vstream_printf("major: %d\t", mp->major);
219  vstream_printf("minor: %d\t", mp->minor);
220  if (mp->patch < 0)
221  vstream_printf("snapshot: %s\n", mp->snapshot);
222  else
223  vstream_printf("patch: %d\n", mp->patch);
224  mail_version_free(mp);
225  }
227 }
228 
229 /* main - the main program */
230 
231 int main(int argc, char **argv)
232 {
233  VSTRING *inbuf = vstring_alloc(1);
234  int have_tty = isatty(0);
235 
236  if (argc > 1) {
237  while (--argc > 0 && *++argv)
238  parse_sample(*argv);
239  } else {
240  for (;;) {
241  if (have_tty) {
242  vstream_printf("> ");
244  }
245  if (vstring_fgets_nonl(inbuf, VSTREAM_IN) <= 0)
246  break;
247  if (have_tty == 0)
248  vstream_printf("> %s\n", STR(inbuf));
249  if (*STR(inbuf) == 0 || *STR(inbuf) == '#')
250  continue;
251  parse_sample(STR(inbuf));
252  }
253  }
254  vstring_free(inbuf);
255  return (0);
256 }
257 
258 #endif
#define vstring_fgets_nonl(s, p)
void myfree(void *ptr)
Definition: mymalloc.c:207
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define VSTREAM_OUT
Definition: vstream.h:67
char * snapshot
Definition: mail_version.h:82
int main(int argc, char **argv)
Definition: anvil.c:1010
char * program
Definition: mail_version.h:78
#define VSTREAM_IN
Definition: vstream.h:66
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
MAIL_VERSION * mail_version_parse(const char *string, const char **why)
Definition: mail_version.c:155
void mail_version_free(MAIL_VERSION *mp)
Definition: mail_version.c:175
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define STR(x)
Definition: anvil.c:518
#define DEF_MAIL_VERSION
Definition: mail_version.h:39
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
char * split_at(char *string, int delimiter)
Definition: split_at.c:53
void check_mail_version(const char *version_string)
Definition: mail_version.c:190
const char * get_mail_version(void)
Definition: mail_version.c:183
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150