1 /*
2 * version.c: library version number and utilities
3 *
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
22 */
23
24
25
26 #include "svn_error.h"
27 #include "svn_version.h"
28
29 #include "sysinfo.h"
30 #include "svn_private_config.h"
31 #include "private/svn_subr_private.h"
32
33 const svn_version_t *
svn_subr_version(void)34 svn_subr_version(void)
35 {
36 SVN_VERSION_BODY;
37 }
38
39
svn_ver_compatible(const svn_version_t * my_version,const svn_version_t * lib_version)40 svn_boolean_t svn_ver_compatible(const svn_version_t *my_version,
41 const svn_version_t *lib_version)
42 {
43 /* With normal development builds the matching rules are strict, to
44 avoid inadvertantly using the wrong libraries. For backward
45 compatibility testing use --disable-full-version-match to
46 configure 1.7 and then the libraries that get built can be used
47 to replace those in 1.6 or earlier builds. */
48
49 #ifndef SVN_DISABLE_FULL_VERSION_MATCH
50 if (lib_version->tag[0] != '\0')
51 /* Development library; require exact match. */
52 return svn_ver_equal(my_version, lib_version);
53 else if (my_version->tag[0] != '\0')
54 /* Development client; must be newer than the library
55 and have the same major and minor version. */
56 return (my_version->major == lib_version->major
57 && my_version->minor == lib_version->minor
58 && my_version->patch > lib_version->patch);
59 #endif
60
61 /* General compatibility rules for released versions. */
62 return (my_version->major == lib_version->major
63 && my_version->minor <= lib_version->minor);
64 }
65
66
svn_ver_equal(const svn_version_t * my_version,const svn_version_t * lib_version)67 svn_boolean_t svn_ver_equal(const svn_version_t *my_version,
68 const svn_version_t *lib_version)
69 {
70 return (my_version->major == lib_version->major
71 && my_version->minor == lib_version->minor
72 && my_version->patch == lib_version->patch
73 && 0 == strcmp(my_version->tag, lib_version->tag));
74 }
75
76
77 svn_error_t *
svn_ver_check_list2(const svn_version_t * my_version,const svn_version_checklist_t * checklist,svn_boolean_t (* comparator)(const svn_version_t *,const svn_version_t *))78 svn_ver_check_list2(const svn_version_t *my_version,
79 const svn_version_checklist_t *checklist,
80 svn_boolean_t (*comparator)(const svn_version_t *,
81 const svn_version_t *))
82 {
83 svn_error_t *err = SVN_NO_ERROR;
84 int i;
85
86 for (i = 0; checklist[i].label != NULL; ++i)
87 {
88 const svn_version_t *lib_version = checklist[i].version_query();
89 if (!comparator(my_version, lib_version))
90 err = svn_error_createf(SVN_ERR_VERSION_MISMATCH, err,
91 _("Version mismatch in '%s'%s:"
92 " found %d.%d.%d%s,"
93 " expected %d.%d.%d%s"),
94 checklist[i].label,
95 comparator == svn_ver_equal
96 ? _(" (expecting equality)")
97 : comparator == svn_ver_compatible
98 ? _(" (expecting compatibility)")
99 : "",
100 lib_version->major, lib_version->minor,
101 lib_version->patch, lib_version->tag,
102 my_version->major, my_version->minor,
103 my_version->patch, my_version->tag);
104 }
105
106 return err;
107 }
108
109
110 struct svn_version_extended_t
111 {
112 const char *build_date; /* Compilation date */
113 const char *build_time; /* Compilation time */
114 const char *build_host; /* Build canonical host name */
115 const char *copyright; /* Copyright notice (localized) */
116 const char *runtime_host; /* Runtime canonical host name */
117 const char *runtime_osname; /* Running OS release name */
118
119 /* Array of svn_version_ext_linked_lib_t describing dependent
120 libraries. */
121 const apr_array_header_t *linked_libs;
122
123 /* Array of svn_version_ext_loaded_lib_t describing loaded shared
124 libraries. */
125 const apr_array_header_t *loaded_libs;
126 };
127
128
129 const svn_version_extended_t *
svn_version_extended(svn_boolean_t verbose,apr_pool_t * pool)130 svn_version_extended(svn_boolean_t verbose,
131 apr_pool_t *pool)
132 {
133 svn_version_extended_t *info = apr_pcalloc(pool, sizeof(*info));
134
135 info->build_date = NULL;
136 info->build_time = NULL;
137 info->build_host = SVN_BUILD_HOST;
138 info->copyright = apr_pstrdup
139 (pool, _("Copyright (C) 2015 The Apache Software Foundation.\n"
140 "This software consists of contributions made by many people;\n"
141 "see the NOTICE file for more information.\n"
142 "Subversion is open source software, see "
143 "http://subversion.apache.org/\n"));
144
145 if (verbose)
146 {
147 info->runtime_host = svn_sysinfo__canonical_host(pool);
148 info->runtime_osname = svn_sysinfo__release_name(pool);
149 info->linked_libs = svn_sysinfo__linked_libs(pool);
150 info->loaded_libs = svn_sysinfo__loaded_libs(pool);
151 }
152
153 return info;
154 }
155
156
157 const char *
svn_version_ext_build_date(const svn_version_extended_t * ext_info)158 svn_version_ext_build_date(const svn_version_extended_t *ext_info)
159 {
160 return ext_info->build_date;
161 }
162
163 const char *
svn_version_ext_build_time(const svn_version_extended_t * ext_info)164 svn_version_ext_build_time(const svn_version_extended_t *ext_info)
165 {
166 return ext_info->build_time;
167 }
168
169 const char *
svn_version_ext_build_host(const svn_version_extended_t * ext_info)170 svn_version_ext_build_host(const svn_version_extended_t *ext_info)
171 {
172 return ext_info->build_host;
173 }
174
175 const char *
svn_version_ext_copyright(const svn_version_extended_t * ext_info)176 svn_version_ext_copyright(const svn_version_extended_t *ext_info)
177 {
178 return ext_info->copyright;
179 }
180
181 const char *
svn_version_ext_runtime_host(const svn_version_extended_t * ext_info)182 svn_version_ext_runtime_host(const svn_version_extended_t *ext_info)
183 {
184 return ext_info->runtime_host;
185 }
186
187 const char *
svn_version_ext_runtime_osname(const svn_version_extended_t * ext_info)188 svn_version_ext_runtime_osname(const svn_version_extended_t *ext_info)
189 {
190 return ext_info->runtime_osname;
191 }
192
193 const apr_array_header_t *
svn_version_ext_linked_libs(const svn_version_extended_t * ext_info)194 svn_version_ext_linked_libs(const svn_version_extended_t *ext_info)
195 {
196 return ext_info->linked_libs;
197 }
198
199 const apr_array_header_t *
svn_version_ext_loaded_libs(const svn_version_extended_t * ext_info)200 svn_version_ext_loaded_libs(const svn_version_extended_t *ext_info)
201 {
202 return ext_info->loaded_libs;
203 }
204
205 svn_error_t *
svn_version__parse_version_string(svn_version_t ** version_p,const char * version_string,apr_pool_t * result_pool)206 svn_version__parse_version_string(svn_version_t **version_p,
207 const char *version_string,
208 apr_pool_t *result_pool)
209 {
210 svn_error_t *err;
211 svn_version_t *version;
212 apr_array_header_t *pieces =
213 svn_cstring_split(version_string, ".", FALSE, result_pool);
214
215 if ((pieces->nelts < 2) || (pieces->nelts > 3))
216 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, NULL,
217 _("Failed to parse version number string '%s'"),
218 version_string);
219
220 version = apr_pcalloc(result_pool, sizeof(*version));
221 version->tag = "";
222
223 /* Parse the major and minor integers strictly. */
224 err = svn_cstring_atoi(&(version->major),
225 APR_ARRAY_IDX(pieces, 0, const char *));
226 if (err)
227 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
228 _("Failed to parse version number string '%s'"),
229 version_string);
230 err = svn_cstring_atoi(&(version->minor),
231 APR_ARRAY_IDX(pieces, 1, const char *));
232 if (err)
233 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
234 _("Failed to parse version number string '%s'"),
235 version_string);
236
237 /* If there's a third component, we'll parse it, too. But we don't
238 require that it be present. */
239 if (pieces->nelts == 3)
240 {
241 const char *piece = APR_ARRAY_IDX(pieces, 2, const char *);
242 char *hyphen = strchr(piece, '-');
243 if (hyphen)
244 {
245 version->tag = apr_pstrdup(result_pool, hyphen + 1);
246 *hyphen = '\0';
247 }
248 err = svn_cstring_atoi(&(version->patch), piece);
249 if (err)
250 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
251 _("Failed to parse version number string '%s'"
252 ),
253 version_string);
254 }
255
256 if (version->major < 0 || version->minor < 0 || version->patch < 0)
257 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
258 _("Failed to parse version number string '%s'"),
259 version_string);
260
261 *version_p = version;
262 return SVN_NO_ERROR;
263 }
264
265
266 svn_boolean_t
svn_version__at_least(svn_version_t * version,int major,int minor,int patch)267 svn_version__at_least(svn_version_t *version,
268 int major,
269 int minor,
270 int patch)
271 {
272 /* Compare major versions. */
273 if (version->major < major)
274 return FALSE;
275 if (version->major > major)
276 return TRUE;
277
278 /* Major versions are the same. Compare minor versions. */
279 if (version->minor < minor)
280 return FALSE;
281 if (version->minor > minor)
282 return TRUE;
283
284 /* Major and minor versions are the same. Compare patch
285 versions. */
286 if (version->patch < patch)
287 return FALSE;
288 if (version->patch > patch)
289 return TRUE;
290
291 /* Major, minor, and patch versions are identical matches. But tags
292 in our schema are always used for versions not yet quite at the
293 given patch level. */
294 if (version->tag && version->tag[0])
295 return FALSE;
296
297 return TRUE;
298 }
299