3 * Copyright (C) 2000, Lineo (www.lineo.com)
4 * Copyright (C) 1999-2000, Greg Ungerer (gerg@snapgear.com)
6 * Copied and hacked from rootloader.c which was:
8 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
17 /****************************************************************************/
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
33 #include <sys/mount.h>
36 #include <linux/autoconf.h>
37 #include <config/autoconf.h>
40 #include "fileblock.h"
41 #include "versioning.h"
44 #define VENDOR "Vendor"
47 #define PRODUCT "Product"
50 #define VERSION "1.0.0"
53 #define MAX_DOT_NUMS 3 /* N.N.N */
54 #define TOTAL_VER_NUMS (MAX_DOT_NUMS + 2) /* pN, bN, uN */
56 /****************************************************************************/
58 char imageVendorName[MAX_VENDOR_SIZE];
59 char imageProductName[MAX_PRODUCT_SIZE];
60 char imageVersion[MAX_VERSION_SIZE];
62 /****************************************************************************/
64 extern struct blkmem_program_t * prog;
66 static const char our_vendor_name[] = VENDOR;
67 static const char our_product_name[] = PRODUCT;
68 static char our_image_version[] = VERSION;
70 /****************************************************************************/
72 static int get_string(char *str, int len);
73 static int check_version_info(char *version, char *new_version);
74 static int get_version_bits(char *version, int num[TOTAL_VER_NUMS], char *lang);
77 * name is a simple product or vendor name.
78 * namelist is either a comma separated list of names (may just be one)
80 * Returns true if the name exists in the list or false if not.
82 * e.g. check_match("SG550", "SG530,SME530,SG550,SME550") returns true
84 static int check_match(const char *name, const char *namelist)
86 char *checklist = strdup(namelist);
89 const char *token = strtok(checklist, ",");
91 if (strcmp(name, token) == 0) {
95 token = strtok(0, ",");
101 /****************************************************************************/
105 * Code to check that we are putting the correct type of flash into this
107 * This code also removes the versioning information from the end
108 * of the memory buffer.
111 * 0 - everything is correct.
112 * 1 - the product name is incorrect.
113 * 2 - the vendor name is incorrect.
114 * 3 - the version is the same.
115 * 4 - the version is older.
116 * 5 - the version is invalid.
117 * 6 - the version language is different.
121 * The last few bytes of the image look like the following:
123 * \0version\0vendore_name\0product_namechksum
124 * the chksum is 16bits wide, and the version is no more than 20bytes.
126 * version is w.x.y[nz], where n is ubp, and w, x, y and z are 1,2 or 3 digit
129 * vendorName and productName may be a comma separated list of names
130 * which are acceptable
132 int check_vendor(int endOffset, int *versionLength)
137 * Point to what should be the last byte in the product name string.
139 if (fb_seek_end(endOffset + 1) != 0)
144 * Now try to get the vendor/product/version strings, from the end of the
145 * image, and figure out the length of the strings to return as well
147 if (get_string(imageProductName, MAX_PRODUCT_SIZE) != 0)
149 *versionLength += strlen(imageProductName) + 1;
151 if (get_string(imageVendorName, MAX_VENDOR_SIZE) != 0)
153 *versionLength += strlen(imageVendorName) + 1;
155 if (get_string(imageVersion, MAX_VERSION_SIZE) != 0)
157 *versionLength += strlen(imageVersion) + 1;
160 * Check the product name. Our product name may be a comma separated list of names.
162 if (!check_match(imageProductName, our_product_name)) {
167 * Check the vendor name. Our vendor name may be a comma separated list of names.
169 if (!check_match(imageVendorName, our_vendor_name)) {
174 * Check the version number.
176 versionInfo = check_version_info(our_image_version, imageVersion);
184 * This gets a printable string from the memory buffer.
185 * It searchs backwards for a non-printable character or a NULL terminator.
189 * str/len - the buffer to store the string in.
193 * -1 - we couldn't find the string.
196 int get_string(char *str, int len)
201 for (i = 0; i < len; i++) {
203 if (fb_seek_dec(1) != 0)
207 if (!isprint(str[i]))
210 if (i == 0 || i >= len)
213 /* We read string in reverse order, so reverse it again */
214 for (j=0; j<i/2; j++) {
223 #endif /* VERSIONTEST */
224 /****************************************************************************/
225 /* check_version_info
227 * Check with the version number in imageVersion is a valid
228 * upgrade to the current version.
229 * The version is ALWAYS of the form major.minor.minor or it is invalid.
230 * We determine whether something is older (less than) or newer,
231 * by simply using a strcmp. This functionality will change over
232 * time to reflect intuitive notions of what constitutes reasonable versioing.
236 * curr_version - the version of the current flash image.
237 * recv_version - the version of the new flash image we just received.
240 * 0 - it all worked perfectly and the version looks okay.
241 * 3 - the new version is the same.
242 * 4 - the new version is older.
243 * 5 - the new/old version is invalid.
244 * 6 - the version language is different.
246 int check_version_info(char *curr_version, char *recv_version)
248 char old_version[MAX_VERSION_SIZE];
249 char new_version[MAX_VERSION_SIZE];
250 char new_lang[MAX_LANG_SIZE];
251 char old_lang[MAX_LANG_SIZE];
252 int new_ver[TOTAL_VER_NUMS];
253 int old_ver[TOTAL_VER_NUMS];
256 strncpy(old_version, curr_version, sizeof(old_version));
257 old_version[sizeof(old_version)-1] = '\0';
258 strncpy(new_version, recv_version, sizeof(new_version));
259 new_version[sizeof(new_version)-1] = '\0';
261 if (!get_version_bits(new_version, new_ver, new_lang))
264 if (!get_version_bits(old_version, old_ver, old_lang))
267 if (strcmp(old_lang, new_lang) != 0)
270 for (i = 0; i < TOTAL_VER_NUMS; i++) {
271 if (old_ver[i] < new_ver[i])
273 if (old_ver[i] > new_ver[i])
280 * we support up to 3 x 3 digit versions followed by a suffix (letter number)
282 * for example: 1.2.3p5
285 * the letters can only be b=beta, u=update, p=prerelease
288 static int get_version_bits(char *version, int num[TOTAL_VER_NUMS], char *lang)
295 /* set everything to 0 */
296 for (i = 0; i < TOTAL_VER_NUMS; i++)
299 /* Extract the language suffix */
300 eptr = strchr(version, '\0');
301 while (--eptr > version && isupper(*eptr))
306 for (i = 0; (lang[i] = eptr[i]) != '\0'; i++)
310 /* strip any trailing non-version-ending letters or chars, ie., jj */
311 while (eptr > version && strchr("bup0123456789", *eptr) == NULL)
315 while (tmp != NULL && *tmp) {
316 num[nums] = strtol(tmp, &eptr, 10);
318 /* when we come through this loop, we expect a number */
326 } else if (*eptr == '.') {
328 if (nums >= MAX_DOT_NUMS)
329 return 0; /* we have more N.N.N's than we can handle */
331 } else if (strchr("bup", *eptr)) {
332 nums = MAX_DOT_NUMS; /* skip to trailer (ie., p10, u12 bit) */
334 /* set the priority appropriately p < b < release < u */
336 case 'p': num[nums] = -20; break;
337 case 'b': num[nums] = -10; break;
338 /* 0; real releases are implied 0 */
339 case 'u': num[nums] = 10; break;
341 nums++; /* time to read the number after the letter */
344 return 1; /* something we do not understand */
349 /****************************************************************************/
352 int main(int argc, char *argv[])
354 int nums[TOTAL_VER_NUMS];
359 rc = get_version_bits(argv[1], nums, lang);
360 printf("rc: %d\n", rc);
362 printf("lang: %s\n", lang);
363 for (i = 0; i < TOTAL_VER_NUMS; i++)
364 printf("v[%d]: %d\n", i, nums[i]);
368 } else if (argc == 3) {
369 printf("old_ver = %s\n", argv[1]);
370 printf("new_ver = %s\n", argv[2]);
371 rc = check_version_info(argv[1], argv[2]);
372 printf("rc: %d\n", rc);
374 case 0: printf("Ok to upgrade, versions looks okay.\n"); break;
375 case 3: printf("the new version is the same.\n"); break;
376 case 4: printf("the new version is older.\n"); break;
377 case 5: printf("the new/old version is invalid.\n"); break;
378 case 6: printf("the version language is different.\n"); break;
379 default: printf("unknown\n"); break;
383 fprintf(stderr, "usage: versiontest <version>\n");
384 fprintf(stderr, " versiontest <old version> <new version>\n");
387 exit(1); /* not reached */
391 #ifdef CONFIG_PROP_LOGD_LOGD
392 void log_upgrade(void) {
398 av[ac++] = "firmware";
399 av[ac++] = our_image_version;
400 av[ac++] = imageVersion;
405 execv("/bin/logd", av);
409 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR);