OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / netflash / versioning.c
1 /* netflash.c:
2  *
3  * Copyright (C) 2000,  Lineo (www.lineo.com)
4  * Copyright (C) 1999-2000,  Greg Ungerer (gerg@snapgear.com)
5  *
6  * Copied and hacked from rootloader.c which was:
7  *
8  * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
9  *
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.
14  *
15  */
16
17 /****************************************************************************/
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <getopt.h>
24 #include <unistd.h>
25 #include <sys/wait.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <errno.h>
30 #include <sys/stat.h>
31 #include <dirent.h>
32 #include <signal.h>
33 #include <sys/mount.h>
34 #include <string.h>
35 #ifndef VERSIONTEST
36 #include <linux/autoconf.h>
37 #include <config/autoconf.h>
38 #endif
39 #include <ctype.h>
40 #include "fileblock.h"
41 #include "versioning.h"
42
43 #ifndef VENDOR
44 #define VENDOR "Vendor"
45 #endif
46 #ifndef PRODUCT
47 #define PRODUCT "Product"
48 #endif
49 #ifndef VERSION
50 #define VERSION "1.0.0"
51 #endif
52
53 #define MAX_DOT_NUMS    3                                       /* N.N.N */
54 #define TOTAL_VER_NUMS  (MAX_DOT_NUMS + 2)      /*  pN, bN, uN */
55
56 /****************************************************************************/
57
58 char imageVendorName[MAX_VENDOR_SIZE];
59 char imageProductName[MAX_PRODUCT_SIZE];
60 char imageVersion[MAX_VERSION_SIZE];
61
62 /****************************************************************************/
63
64 extern struct blkmem_program_t * prog;
65
66 static const char our_vendor_name[] = VENDOR;
67 static const char our_product_name[] = PRODUCT;
68 static char our_image_version[] = VERSION;
69
70 /****************************************************************************/
71
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);
75
76 /**
77  * name is a simple product or vendor name.
78  * namelist is either a comma separated list of names (may just be one)
79  * 
80  * Returns true if the name exists in the list or false if not.
81  *
82  * e.g. check_match("SG550", "SG530,SME530,SG550,SME550") returns true
83  *  */
84 static int check_match(const char *name, const char *namelist)
85 {
86         char *checklist = strdup(namelist);
87         int ret = 0;
88
89         const char *token = strtok(checklist, ",");
90         while (token) {
91                 if (strcmp(name, token) == 0) {
92                         ret = 1;
93                         break;
94                 }
95                 token = strtok(0, ",");
96         }
97         free(checklist);
98         return ret;
99 }
100
101 /****************************************************************************/
102 #ifndef VERSIONTEST
103
104 /*
105  * Code to check that we are putting the correct type of flash into this
106  * unit.
107  * This code also removes the versioning information from the end
108  * of the memory buffer.
109  *
110  * ret:
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.
118  */
119
120 /*
121  * The last few bytes of the image look like the following:
122  *
123  *  \0version\0vendore_name\0product_namechksum
124  *      the chksum is 16bits wide, and the version is no more than 20bytes.
125  *
126  * version is w.x.y[nz], where n is ubp, and w, x, y and z are 1,2 or 3 digit
127  * numbers.
128  *
129  * vendorName and productName may be a comma separated list of names
130  * which are acceptable
131  */
132 int check_vendor(int endOffset, int *versionLength)
133 {
134         int versionInfo;
135
136         /*
137          * Point to what should be the last byte in the product name string.
138          */
139         if (fb_seek_end(endOffset + 1) != 0)
140                 return 5;
141
142         *versionLength = 0;
143         /*
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
146          */
147         if (get_string(imageProductName, MAX_PRODUCT_SIZE) != 0)
148                 return 5;
149         *versionLength += strlen(imageProductName) + 1;
150
151         if (get_string(imageVendorName, MAX_VENDOR_SIZE) != 0)
152                 return 5;
153         *versionLength += strlen(imageVendorName) + 1;
154
155         if (get_string(imageVersion, MAX_VERSION_SIZE) != 0)
156                 return 5;
157         *versionLength += strlen(imageVersion) + 1;
158
159         /*
160          * Check the product name. Our product name may be a comma separated list of names.
161          */
162         if (!check_match(imageProductName, our_product_name)) {
163                 return 1;
164         }
165
166         /*
167          * Check the vendor name. Our vendor name may be a comma separated list of names.
168          */
169         if (!check_match(imageVendorName, our_vendor_name)) {
170                 return 2;
171         }
172
173         /*
174          * Check the version number.
175          */
176         versionInfo = check_version_info(our_image_version, imageVersion);
177
178         return versionInfo;
179 }
180
181
182 /* get_string
183  *
184  * This gets a printable string from the memory buffer.
185  * It searchs backwards for a non-printable character or a NULL terminator.
186  *
187  * inputs:
188  *
189  * str/len - the buffer to store the string in.
190  *
191  * ret:
192  *
193  * -1 - we couldn't find the string.
194  * 0 - success
195  */
196 int get_string(char *str, int len)
197 {
198         int i, j;
199         char c;
200
201         for (i = 0; i < len; i++) {
202                 fb_peek(str + i, 1);
203                 if (fb_seek_dec(1) != 0)
204                         return -1;
205                 if (!str[i])
206                         break;
207                 if (!isprint(str[i]))
208                         return -1;
209         }
210         if (i == 0 || i >= len)
211                 return -1;
212
213         /* We read string in reverse order, so reverse it again */
214         for (j=0; j<i/2; j++) {
215                 c = str[j];
216                 str[j] = str[i-j-1];
217                 str[i-j-1] = c;
218         }
219
220         return 0;
221 }
222
223 #endif /* VERSIONTEST */
224 /****************************************************************************/
225 /* check_version_info
226  *
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.
233  *
234  * inputs:
235  *
236  * curr_version - the version of the current flash image.
237  * recv_version - the version of the new flash image we just received.
238  *
239  * ret:
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.
245  */
246 int check_version_info(char *curr_version, char *recv_version)
247 {
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];
254         int i;
255         
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';
260         
261         if (!get_version_bits(new_version, new_ver, new_lang))
262                 return 5;
263
264         if (!get_version_bits(old_version, old_ver, old_lang))
265                 return 5;
266         
267         if (strcmp(old_lang, new_lang) != 0)
268                 return 6;
269         
270         for (i = 0; i < TOTAL_VER_NUMS; i++) {
271                 if (old_ver[i] < new_ver[i])
272                         return 0;
273                 if (old_ver[i] > new_ver[i])
274                         return 4;
275         }
276         return 3;
277
278
279 /*
280  * we support up to 3 x 3 digit versions followed by a suffix (letter number)
281  *
282  * for example:    1.2.3p5
283  *                 1.2p5
284  *
285  * the letters can only be b=beta, u=update, p=prerelease
286  */
287
288 static int get_version_bits(char *version, int num[TOTAL_VER_NUMS], char *lang)
289 {
290         int i;
291         char *tmp;
292         int nums = 0;
293         char *eptr;
294
295         /* set everything to 0 */
296         for (i = 0; i < TOTAL_VER_NUMS; i++)
297                 num[i] = 0;
298
299         /* Extract the language suffix */
300         eptr = strchr(version, '\0');
301         while (--eptr > version && isupper(*eptr))
302                 ;
303         if (eptr == version)
304                 return 0;
305         eptr++;
306         for (i = 0; (lang[i] = eptr[i]) != '\0'; i++)
307                 ;
308         *eptr-- = '\0';
309
310         /* strip any trailing non-version-ending letters or chars,  ie., jj */
311         while (eptr > version && strchr("bup0123456789", *eptr) == NULL)
312                 *eptr-- = '\0';
313
314         tmp = version;
315         while (tmp != NULL && *tmp) {
316                 num[nums] = strtol(tmp, &eptr, 10);
317
318                 /* when we come through this loop,  we expect a number */
319                 if (eptr == tmp)
320                         return 1;
321
322                 if (*eptr == '\0') {
323                         if (nums == 0)
324                                 return 0;
325                         return 1;
326                 } else if (*eptr == '.') {
327                         nums++;
328                         if (nums >= MAX_DOT_NUMS)
329                                 return 0; /* we have more N.N.N's than we can handle */
330                         tmp = eptr + 1;
331                 } else if (strchr("bup", *eptr)) {
332                         nums = MAX_DOT_NUMS; /* skip to trailer (ie., p10, u12 bit) */
333
334                         /* set the priority appropriately p < b < release < u */
335                         switch (*eptr) {
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;
340                         }
341                         nums++; /* time to read the number after the letter */
342                         tmp = eptr + 1;
343                 } else
344                         return 1;  /* something we do not understand */
345         }
346         return nums ? 1 : 0;
347 }
348
349 /****************************************************************************/
350
351 #ifdef VERSIONTEST
352 int main(int argc, char *argv[])
353 {
354         int nums[TOTAL_VER_NUMS];
355         char lang[10];
356         int i, rc;
357
358         if (argc == 2) {
359                 rc = get_version_bits(argv[1], nums, lang);
360                 printf("rc:   %d\n", rc);
361                 if (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]);
365                         exit(0);
366                 }
367                 exit(1);
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);
373                 switch (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;
380                 }
381                 exit(rc);
382         } else {
383                 fprintf(stderr, "usage: versiontest <version>\n");
384                 fprintf(stderr, "       versiontest <old version> <new version>\n");
385                 exit(1);
386         }
387         exit(1); /* not reached */
388 }
389 #endif
390
391 #ifdef CONFIG_PROP_LOGD_LOGD
392 void log_upgrade(void) {
393         char *av[20];
394         int ac = 0;
395         pid_t pid;
396
397         av[ac++] = "logd";
398         av[ac++] = "firmware";
399         av[ac++] = our_image_version;
400         av[ac++] = imageVersion;
401         av[ac++] = NULL;
402
403         pid = vfork();
404         if (pid == 0) {
405                 execv("/bin/logd", av);
406                 _exit(1);
407         }
408         if (pid != -1)
409                 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR);
410 }
411 #endif