2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Version CLI command
9 /******************************************************************************
13 Version [<library|device|file>] [<version #>] [<revision #>] [FILE] [FULL] [RES]
17 NAME/M,MD5SUM/S,VERSION/N,REVISION/N,FILE/S,FULL/S,RES/S,ARCH/S
25 Prints or checks the version and revision information of a file, library or device.
29 NAME -- name of file, library or device to check. If not given it
30 prints version and revision of Kickstart.
31 MD5SUM -- #FIXME what is that?
32 VERSION -- checks for version and returns error code 5 (warn) if the
33 version of the file is lower.
34 REVISION -- checks for revision and returns error code 5 (warn) if the
35 revision of the file is lower.
36 FILE -- reads from file and ignores currently loaded libraries and devices
37 FULL -- prints additional information
38 RES -- gets version of resident commands
39 ARCH -- displays architecture information about a file
55 ******************************************************************************/
57 #define ELF_32BIT /* This is needed for correct .ARM.Attributes parsing */
59 #include <aros/arosbase.h>
60 #include <aros/debug.h>
61 #include <aros/inquire.h>
62 #include <proto/aros.h>
70 #include <proto/exec.h>
71 #include <exec/execbase.h>
72 #include <exec/libraries.h>
73 #include <exec/memory.h>
74 #include <exec/resident.h>
75 #include <proto/dos.h>
76 #include <proto/utility.h>
77 #include <proto/alib.h>
78 #include <dos/datetime.h>
80 #include <dos/dosextens.h>
83 /*===[md5.h]==============================================================*/
85 /* Data structure for MD5 (Message-Digest) computation */
87 ULONG buf
[4]; /* scratch buffer */
88 ULONG i
[2]; /* number of _bits_ handled mod 2^64 */
89 unsigned char in
[64]; /* input buffer */
92 void MD5Init(MD5_CTX
*mdContext
);
93 void MD5Update(MD5_CTX
*mdContext
, unsigned char *inBuf
, unsigned int inLen
);
94 void MD5Final(unsigned char digest
[16], MD5_CTX
*mdContext
);
96 /*==[md5.c]===============================================================*/
99 * Used in 'version' as is, just removed the #include "ambient.h"
101 * Harry Sintonen <sintonen@iki.fi>
105 * Ambient - the ultimate desktop
106 * ------------------------------
107 * (c) 2001-2003 by David Gerber <zapek@meanmachine.ch>
108 * All Rights Reserved
113 //#include "ambient.h"
114 //#include <exec/types.h>
117 ***********************************************************************
118 ** md5.c -- the source code for MD5 routines **
119 ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
120 ** Created: 2/17/90 RLR **
121 ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
122 ***********************************************************************
126 * Edited 7 May 93 by CP to change the interface to match that
127 * of the MD5 routines in RSAREF. Due to this alteration, this
128 * code is "derived from the RSA Data Security, Inc. MD5 Message-
129 * Digest Algorithm". (See below.)
133 ***********************************************************************
134 ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
136 ** License to copy and use this software is granted provided that **
137 ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
138 ** Digest Algorithm" in all material mentioning or referencing this **
139 ** software or this function. **
141 ** License is also granted to make and use derivative works **
142 ** provided that such works are identified as "derived from the RSA **
143 ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
144 ** material mentioning or referencing the derived work. **
146 ** RSA Data Security, Inc. makes no representations concerning **
147 ** either the merchantability of this software or the suitability **
148 ** of this software for any particular purpose. It is provided "as **
149 ** is" without express or implied warranty of any kind. **
151 ** These notices must be retained in any copies of any part of this **
152 ** documentation and/or software. **
153 ***********************************************************************
159 ***********************************************************************
160 ** Message-digest routines: **
161 ** To form the message digest for a message M **
162 ** (1) Initialize a context buffer mdContext using MD5Init **
163 ** (2) Call MD5Update on mdContext and M **
164 ** (3) Call MD5Final on mdContext **
165 ** The message digest is now in the bugffer passed to MD5Final **
166 ***********************************************************************
169 static unsigned char PADDING
[64] = {
170 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
180 /* F, G, H and I are basic MD5 functions */
181 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
182 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
183 #define H(x, y, z) ((x) ^ (y) ^ (z))
184 #define I(x, y, z) ((y) ^ ((x) | (~z)))
186 /* ROTATE_LEFT rotates x left n bits */
187 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
189 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
190 /* Rotation is separate from addition to prevent recomputation */
191 #define FF(a, b, c, d, x, s, ac) \
192 {(a) += F ((b), (c), (d)) + (x) + (ULONG)(ac); \
193 (a) = ROTATE_LEFT ((a), (s)); \
196 #define GG(a, b, c, d, x, s, ac) \
197 {(a) += G ((b), (c), (d)) + (x) + (ULONG)(ac); \
198 (a) = ROTATE_LEFT ((a), (s)); \
201 #define HH(a, b, c, d, x, s, ac) \
202 {(a) += H ((b), (c), (d)) + (x) + (ULONG)(ac); \
203 (a) = ROTATE_LEFT ((a), (s)); \
206 #define II(a, b, c, d, x, s, ac) \
207 {(a) += I ((b), (c), (d)) + (x) + (ULONG)(ac); \
208 (a) = ROTATE_LEFT ((a), (s)); \
212 static void Transform(register ULONG
*buf
,register ULONG
*in
);
214 /* The routine MD5Init initializes the message-digest context
215 mdContext. All fields are set to zero.
217 void MD5Init ( MD5_CTX
*mdContext
)
219 mdContext
->i
[0] = mdContext
->i
[1] = (ULONG
)0;
221 /* Load magic initialization constants.
223 mdContext
->buf
[0] = (ULONG
)0x67452301L
;
224 mdContext
->buf
[1] = (ULONG
)0xefcdab89L
;
225 mdContext
->buf
[2] = (ULONG
)0x98badcfeL
;
226 mdContext
->buf
[3] = (ULONG
)0x10325476L
;
229 /* The routine MD5Update updates the message-digest context to
230 account for the presence of each of the characters inBuf[0..inLen-1]
231 in the message whose digest is being computed.
233 void MD5Update (MD5_CTX
*mdContext
, unsigned char *inBuf
,
240 /* compute number of bytes mod 64 */
241 mdi
= (int)((mdContext
->i
[0] >> 3) & 0x3F);
243 /* update number of bits */
244 if ((mdContext
->i
[0] + ((ULONG
)inLen
<< 3)) < mdContext
->i
[0])
246 mdContext
->i
[0] += ((ULONG
)inLen
<< 3);
247 mdContext
->i
[1] += ((ULONG
)inLen
>> 29);
251 /* add new character to buffer, increment mdi */
252 mdContext
->in
[mdi
++] = *inBuf
++;
254 /* transform if necessary */
257 for (i
= 0, ii
= 0; i
< 16; i
++, ii
+= 4)
258 in
[i
] = (((ULONG
)mdContext
->in
[ii
+3]) << 24) |
259 (((ULONG
)mdContext
->in
[ii
+2]) << 16) |
260 (((ULONG
)mdContext
->in
[ii
+1]) << 8) |
261 ((ULONG
)mdContext
->in
[ii
]);
262 Transform (mdContext
->buf
, in
);
268 /* The routine MD5Final terminates the message-digest computation and
269 ends with the desired message digest in mdContext->digest[0...15].
271 void MD5Final (unsigned char digest
[16], MD5_CTX
*mdContext
)
278 /* save number of bits */
279 in
[14] = mdContext
->i
[0];
280 in
[15] = mdContext
->i
[1];
282 /* compute number of bytes mod 64 */
283 mdi
= (int)((mdContext
->i
[0] >> 3) & 0x3F);
285 /* pad out to 56 mod 64 */
286 padLen
= (mdi
< 56) ? (56 - mdi
) : (120 - mdi
);
287 MD5Update (mdContext
, PADDING
, padLen
);
289 /* append length in bits and transform */
290 for (i
= 0, ii
= 0; i
< 14; i
++, ii
+= 4)
291 in
[i
] = (((ULONG
)mdContext
->in
[ii
+3]) << 24) |
292 (((ULONG
)mdContext
->in
[ii
+2]) << 16) |
293 (((ULONG
)mdContext
->in
[ii
+1]) << 8) |
294 ((ULONG
)mdContext
->in
[ii
]);
295 Transform (mdContext
->buf
, in
);
297 /* store buffer in digest */
298 for (i
= 0, ii
= 0; i
< 4; i
++, ii
+= 4)
300 digest
[ii
] = (unsigned char) (mdContext
->buf
[i
] & 0xFF);
301 digest
[ii
+1] = (unsigned char)((mdContext
->buf
[i
] >> 8) & 0xFF);
302 digest
[ii
+2] = (unsigned char)((mdContext
->buf
[i
] >> 16) & 0xFF);
303 digest
[ii
+3] = (unsigned char)((mdContext
->buf
[i
] >> 24) & 0xFF);
307 /* Basic MD5 step. Transforms buf based on in. Note that if the Mysterious
308 Constants are arranged backwards in little-endian order and decrypted with
309 the DES they produce OCCULT MESSAGES!
311 void Transform(register ULONG
*buf
,register ULONG
*in
)
313 register ULONG a
= buf
[0], b
= buf
[1], c
= buf
[2], d
= buf
[3];
320 FF ( a
, b
, c
, d
, in
[ 0], S11
, 0xD76AA478L
); /* 1 */
321 FF ( d
, a
, b
, c
, in
[ 1], S12
, 0xE8C7B756L
); /* 2 */
322 FF ( c
, d
, a
, b
, in
[ 2], S13
, 0x242070DBL
); /* 3 */
323 FF ( b
, c
, d
, a
, in
[ 3], S14
, 0xC1BDCEEEL
); /* 4 */
324 FF ( a
, b
, c
, d
, in
[ 4], S11
, 0xF57C0FAFL
); /* 5 */
325 FF ( d
, a
, b
, c
, in
[ 5], S12
, 0x4787C62AL
); /* 6 */
326 FF ( c
, d
, a
, b
, in
[ 6], S13
, 0xA8304613L
); /* 7 */
327 FF ( b
, c
, d
, a
, in
[ 7], S14
, 0xFD469501L
); /* 8 */
328 FF ( a
, b
, c
, d
, in
[ 8], S11
, 0x698098D8L
); /* 9 */
329 FF ( d
, a
, b
, c
, in
[ 9], S12
, 0x8B44F7AFL
); /* 10 */
330 FF ( c
, d
, a
, b
, in
[10], S13
, 0xFFFF5BB1L
); /* 11 */
331 FF ( b
, c
, d
, a
, in
[11], S14
, 0x895CD7BEL
); /* 12 */
332 FF ( a
, b
, c
, d
, in
[12], S11
, 0x6B901122L
); /* 13 */
333 FF ( d
, a
, b
, c
, in
[13], S12
, 0xFD987193L
); /* 14 */
334 FF ( c
, d
, a
, b
, in
[14], S13
, 0xA679438EL
); /* 15 */
335 FF ( b
, c
, d
, a
, in
[15], S14
, 0x49B40821L
); /* 16 */
342 GG ( a
, b
, c
, d
, in
[ 1], S21
, 0xF61E2562L
); /* 17 */
343 GG ( d
, a
, b
, c
, in
[ 6], S22
, 0xC040B340L
); /* 18 */
344 GG ( c
, d
, a
, b
, in
[11], S23
, 0x265E5A51L
); /* 19 */
345 GG ( b
, c
, d
, a
, in
[ 0], S24
, 0xE9B6C7AAL
); /* 20 */
346 GG ( a
, b
, c
, d
, in
[ 5], S21
, 0xD62F105DL
); /* 21 */
347 GG ( d
, a
, b
, c
, in
[10], S22
, 0x02441453L
); /* 22 */
348 GG ( c
, d
, a
, b
, in
[15], S23
, 0xD8A1E681L
); /* 23 */
349 GG ( b
, c
, d
, a
, in
[ 4], S24
, 0xE7D3FBC8L
); /* 24 */
350 GG ( a
, b
, c
, d
, in
[ 9], S21
, 0x21E1CDE6L
); /* 25 */
351 GG ( d
, a
, b
, c
, in
[14], S22
, 0xC33707D6L
); /* 26 */
352 GG ( c
, d
, a
, b
, in
[ 3], S23
, 0xF4D50D87L
); /* 27 */
353 GG ( b
, c
, d
, a
, in
[ 8], S24
, 0x455A14EDL
); /* 28 */
354 GG ( a
, b
, c
, d
, in
[13], S21
, 0xA9E3E905L
); /* 29 */
355 GG ( d
, a
, b
, c
, in
[ 2], S22
, 0xFCEFA3F8L
); /* 30 */
356 GG ( c
, d
, a
, b
, in
[ 7], S23
, 0x676F02D9L
); /* 31 */
357 GG ( b
, c
, d
, a
, in
[12], S24
, 0x8D2A4C8AL
); /* 32 */
364 HH ( a
, b
, c
, d
, in
[ 5], S31
, 0xFFFA3942L
); /* 33 */
365 HH ( d
, a
, b
, c
, in
[ 8], S32
, 0x8771F681L
); /* 34 */
366 HH ( c
, d
, a
, b
, in
[11], S33
, 0x6D9D6122L
); /* 35 */
367 HH ( b
, c
, d
, a
, in
[14], S34
, 0xFDE5380CL
); /* 36 */
368 HH ( a
, b
, c
, d
, in
[ 1], S31
, 0xA4BEEA44L
); /* 37 */
369 HH ( d
, a
, b
, c
, in
[ 4], S32
, 0x4BDECFA9L
); /* 38 */
370 HH ( c
, d
, a
, b
, in
[ 7], S33
, 0xF6BB4B60L
); /* 39 */
371 HH ( b
, c
, d
, a
, in
[10], S34
, 0xBEBFBC70L
); /* 40 */
372 HH ( a
, b
, c
, d
, in
[13], S31
, 0x289B7EC6L
); /* 41 */
373 HH ( d
, a
, b
, c
, in
[ 0], S32
, 0xEAA127FAL
); /* 42 */
374 HH ( c
, d
, a
, b
, in
[ 3], S33
, 0xD4EF3085L
); /* 43 */
375 HH ( b
, c
, d
, a
, in
[ 6], S34
, 0x04881D05L
); /* 44 */
376 HH ( a
, b
, c
, d
, in
[ 9], S31
, 0xD9D4D039L
); /* 45 */
377 HH ( d
, a
, b
, c
, in
[12], S32
, 0xE6DB99E5L
); /* 46 */
378 HH ( c
, d
, a
, b
, in
[15], S33
, 0x1FA27CF8L
); /* 47 */
379 HH ( b
, c
, d
, a
, in
[ 2], S34
, 0xC4AC5665L
); /* 48 */
386 II ( a
, b
, c
, d
, in
[ 0], S41
, 0xF4292244L
); /* 49 */
387 II ( d
, a
, b
, c
, in
[ 7], S42
, 0x432AFF97L
); /* 50 */
388 II ( c
, d
, a
, b
, in
[14], S43
, 0xAB9423A7L
); /* 51 */
389 II ( b
, c
, d
, a
, in
[ 5], S44
, 0xFC93A039L
); /* 52 */
390 II ( a
, b
, c
, d
, in
[12], S41
, 0x655B59C3L
); /* 53 */
391 II ( d
, a
, b
, c
, in
[ 3], S42
, 0x8F0CCC92L
); /* 54 */
392 II ( c
, d
, a
, b
, in
[10], S43
, 0xFFEFF47DL
); /* 55 */
393 II ( b
, c
, d
, a
, in
[ 1], S44
, 0x85845DD1L
); /* 56 */
394 II ( a
, b
, c
, d
, in
[ 8], S41
, 0x6FA87E4FL
); /* 57 */
395 II ( d
, a
, b
, c
, in
[15], S42
, 0xFE2CE6E0L
); /* 58 */
396 II ( c
, d
, a
, b
, in
[ 6], S43
, 0xA3014314L
); /* 59 */
397 II ( b
, c
, d
, a
, in
[13], S44
, 0x4E0811A1L
); /* 60 */
398 II ( a
, b
, c
, d
, in
[ 4], S41
, 0xF7537E82L
); /* 61 */
399 II ( d
, a
, b
, c
, in
[11], S42
, 0xBD3AF235L
); /* 62 */
400 II ( c
, d
, a
, b
, in
[ 2], S43
, 0x2AD7D2BBL
); /* 63 */
401 II ( b
, c
, d
, a
, in
[ 9], S44
, 0xEB86D391L
); /* 64 */
409 /*==[end md5.c]============================================================*/
412 const TEXT version
[] = "$VER: Version 42.2 (22.05.2011)\n";
414 static const char ERROR_HEADER
[] = "Version";
416 #define TEMPLATE "NAME/M,MD5SUM/S,VERSION/N,REVISION/N,FILE/S,FULL/S,RES/S,ARCH/S"
419 CONST_STRPTR
*arg_name
;
430 LONG mversion
, mrevision
;
449 parsedver
= { NULL
, 0, 0, 0, 0, -1, 0, NULL
, NULL
, NULL
, NULL
, NULL
, {0}};
451 #define PVF_MD5SUM (1 << 0)
452 #define PVF_NOVERSION (1 << 1)
455 int makeverstring(CONST_STRPTR name
);
457 void printverstring(void);
459 void freeverstring(void);
461 int makesysver(void);
463 int cmpargsparsed(void);
466 /**************************** support functions ************************/
468 /* Duplicate string, by given length or -1 for full length
471 STRPTR
dupstr(CONST_STRPTR buffer
, LONG len
)
478 len
= strlen(buffer
);
480 ret
= AllocVec(len
+ 1, MEMF_ANY
);
483 CopyMem((STRPTR
) buffer
, ret
, len
);
493 inline int myisspace(int c
)
495 return (c
== ' ' || c
== '\t');
499 /* Return a pointer to a string, stripped by all leading whitespace characters
503 STRPTR
skipwhites(CONST_STRPTR buffer
)
507 if (buffer
[0] == '\0' || !isspace(buffer
[0]))
509 return (STRPTR
) buffer
;
515 /* Return a pointer to a string, stripped by all leading space characters
519 STRPTR
skipspaces(CONST_STRPTR buffer
)
523 if (buffer
[0] == '\0' || buffer
[0] != ' ')
525 return (STRPTR
) buffer
;
531 /* Strip all whitespace-characters from the end of a string. Note that the
532 * buffer passed in will be modified!
535 void stripwhites(STRPTR buffer
)
537 int len
= strlen(buffer
);
541 if (!isspace(buffer
[len
-1]))
552 /* Searches for a given string in a file and stores up to *lenptr characters
553 * into the buffer beginning with the first character after the given string.
556 int findinfile(BPTR file
, CONST_STRPTR string
, STRPTR buffer
, int *lenptr
, unsigned char digest
[16])
558 int error
= RETURN_OK
;
559 int buflen
= *lenptr
, len
= 0, pos
, stringlen
;
565 tmp
= AllocMem(buflen
, MEMF_PUBLIC
);
571 stringlen
= strlen(string
);
580 while ((len
= Read(file
, &tmp
[len
], buflen
- len
)) > 0)
586 MD5Update(&md5ctx
, bufpos
, len
);
591 /* If we get here we're scanning the rest of the file for md5sum. - Piru */
596 while ((len
- pos
) >= stringlen
)
598 /* Compare the current buffer position with the supplied string. */
599 if (strncmp(&tmp
[pos
], string
, stringlen
) == 0)
601 /* It is equal! Now move the rest of the buffer to the top of
602 * the buffer and fill it up.
604 int findstrlen
= len
- pos
;
606 memcpy(buffer
, &tmp
[pos
+ stringlen
], findstrlen
);
608 len
= Read(file
, &buffer
[findstrlen
], buflen
- findstrlen
);
613 MD5Update(&md5ctx
, &buffer
[findstrlen
], len
);
616 *lenptr
= findstrlen
+ len
;
627 /* Move the rest of the buffer that could not be compared (because it
628 * is smaller than the string to compare) to the top of the buffer.
632 memmove(tmp
, &tmp
[len
- stringlen
], stringlen
);
636 /* If we're not md5summing, stop file scanning now. - Piru */
637 if (!args
.arg_md5sum
)
648 FreeMem(tmp
, buflen
);
657 memset(digest
, 0, 16);
658 MD5Final(digest
, &md5ctx
);
665 /*************************** parsing functions *************************/
667 /* Convert a date in the form DD.MM.YY or DD.MM.YYYY into a numerical
668 * value. Return FALSE, if buffer doesn't contain a valid date.
671 BOOL
makedatefromstring(CONST_STRPTR
*bufptr
)
673 CONST_STRPTR buffer
= *bufptr
;
675 CONST_STRPTR headerstart
, end
;
681 //if (isspace(buffer[0]))
684 headerstart
= buffer
;
686 buffer
= strchr(buffer
, '(');
692 end
= strchr(buffer
, ')');
697 len
= (int)(end
- buffer
);
698 newbuf
= dupstr(buffer
, len
);
703 for (i
= 0; i
< len
; i
++)
707 if (c
== '.' || c
== '/')
709 else if (!isalnum(c
))
717 D(Printf("date: \"%s\"\n", newbuf
));
719 dt
.dat_Format
= FORMAT_CDN
;
721 dt
.dat_StrDay
= NULL
;
722 dt
.dat_StrDate
= newbuf
;
723 dt
.dat_StrTime
= NULL
;
724 res
= StrToDate(&dt
);
727 dt
.dat_Format
= FORMAT_DOS
;
728 res
= StrToDate(&dt
);
731 //Printf("StrToDate failed!\n");
738 //parsedver.pv_days = dt.dat_Stamp.ds_Days;
740 parsedver
.pv_datestr
= AllocVec(buffer
- headerstart
+ LEN_DATSTRING
+ 2, MEMF_ANY
);
741 if (!parsedver
.pv_datestr
)
746 dt
.dat_Stamp
.ds_Minute
= 0;
747 dt
.dat_Stamp
.ds_Tick
= 0;
749 dt
.dat_StrDate
= parsedver
.pv_datestr
+ (buffer
- headerstart
);
750 dt
.dat_Format
= FORMAT_DEF
;
753 //Printf("DateToStr failed!\n");
757 CopyMem((STRPTR
) headerstart
, parsedver
.pv_datestr
, buffer
- headerstart
);
758 res
= strlen(parsedver
.pv_datestr
);
759 parsedver
.pv_datestr
[res
++] = ')';
760 parsedver
.pv_datestr
[res
] = '\0';
768 /* Check whether the given string contains a version in the form
769 * <version>.<revision> . If not return FALSE, otherwise fill in parsedver and
773 BOOL
makeversionfromstring(CONST_STRPTR
*bufptr
)
776 CONST_STRPTR buffer
= *bufptr
;
777 CONST_STRPTR verstart
, revstart
;
779 //Printf("makeversionfromstring: buffer \"%s\"\n", (LONG) buffer);
784 pos
= StrToLong((STRPTR
) buffer
, &ver
);
789 parsedver
.pv_version
= ver
;
790 parsedver
.pv_revision
= -1;
792 parsedver
.pv_vername
= dupstr(verstart
, pos
);
793 if (!parsedver
.pv_vername
)
802 buffer
= skipspaces(buffer
); /* NOTE: skipspaces, not skipwhites! */
810 pos
= StrToLong((STRPTR
) buffer
, &rev
);
817 parsedver
.pv_revision
= rev
;
819 /* calc the revision string len */
820 pos
= buffer
+ pos
- revstart
;
821 parsedver
.pv_revname
= dupstr(revstart
, pos
);
822 if (!parsedver
.pv_revname
)
827 *bufptr
= revstart
+ pos
;
832 static const char *arm_cpus
[] =
850 static const char *arm_fpus
[] =
861 void printverstring(void)
865 if (parsedver
.pv_flags
& PVF_MD5SUM
)
867 /* Endianess safe version */
868 Printf("%02lX%02lX%02lX%02lX"
869 "%02lX%02lX%02lX%02lX"
870 "%02lX%02lX%02lX%02lX"
871 "%02lX%02lX%02lX%02lX ",
872 parsedver
.pv_md5sum
[0],
873 parsedver
.pv_md5sum
[1],
874 parsedver
.pv_md5sum
[2],
875 parsedver
.pv_md5sum
[3],
876 parsedver
.pv_md5sum
[4],
877 parsedver
.pv_md5sum
[5],
878 parsedver
.pv_md5sum
[6],
879 parsedver
.pv_md5sum
[7],
880 parsedver
.pv_md5sum
[8],
881 parsedver
.pv_md5sum
[9],
882 parsedver
.pv_md5sum
[10],
883 parsedver
.pv_md5sum
[11],
884 parsedver
.pv_md5sum
[12],
885 parsedver
.pv_md5sum
[13],
886 parsedver
.pv_md5sum
[14],
887 parsedver
.pv_md5sum
[15]);
891 /* "01234567012345670123456701234567: " */
892 PutStr("<no md5sum available> ");
896 if (parsedver
.pv_flags
& PVF_NOVERSION
)
898 Printf("%s\n", (IPTR
) parsedver
.pv_name
);
904 /* If md5sum output was there, avoid linefeed to allow parsing the output - Piru */
907 parsedver
.pv_extralf
= " ";
910 Printf("%s%s%s%s%s%s%s\n",
911 (IPTR
) parsedver
.pv_name
, (IPTR
) (*parsedver
.pv_name
? " " : ""),
912 (IPTR
) parsedver
.pv_vername
, (IPTR
) parsedver
.pv_revname
,
913 (IPTR
) (parsedver
.pv_datestr
? (IPTR
)parsedver
.pv_datestr
: (IPTR
)""),
914 (IPTR
) (parsedver
.pv_extralf
? (IPTR
)parsedver
.pv_extralf
: (IPTR
)""),
915 (IPTR
) (parsedver
.pv_extrastr
? (IPTR
)parsedver
.pv_extrastr
: (IPTR
)""));
920 (IPTR
) parsedver
.pv_name
, (IPTR
) (*parsedver
.pv_name
? " " : ""),
921 (IPTR
) parsedver
.pv_vername
, (IPTR
) parsedver
.pv_revname
);
928 if (parsedver
.pv_arch
== EM_ARM
)
930 Printf("Architecture: ");
932 if (parsedver
.pv_arm_cpu
== (UBYTE
)-1)
933 Printf("ARM (unspecified)");
934 else if (parsedver
.pv_arm_cpu
<= ELF_CPU_ARMv7EM
)
935 Printf(arm_cpus
[parsedver
.pv_arm_cpu
]);
937 Printf("Unknown ARM (%d)", parsedver
.pv_arm_cpu
);
939 if (parsedver
.pv_arm_fpu
> 6)
940 Printf(" Unknown FPU (%d)", parsedver
.pv_arm_fpu
);
941 else if (parsedver
.pv_arm_fpu
)
942 Printf(" %s", arm_fpus
[parsedver
.pv_arm_fpu
]);
948 switch (parsedver
.pv_arch
)
951 /* No information available */
977 Printf("Architecture: %s\n", arch
);
985 int makedata(CONST_STRPTR buffer
, CONST_STRPTR ptr
, int pos
)
987 D(Printf("makedata: buffer \"%s\" ptr \"%s\"\n", buffer
, ptr
));
989 if (makeversionfromstring(&ptr
))
995 /* Copy the program-name into a buffer. */
996 parsedver
.pv_name
= dupstr(buffer
, pos
);
997 if (!parsedver
.pv_name
)
999 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1003 /* Now find the date */
1004 D(Printf("makedata: ptr #1: \"%s\"\n", ptr
));
1005 doskip
= strchr(ptr
, '(') ? TRUE
: FALSE
;
1006 (void) makedatefromstring(&ptr
);
1008 D(Printf("makedata: ptr #2: \"%s\"\n", ptr
));
1010 ptr
= skipspaces(ptr
); /* NOTE: not skipwhites! */
1011 for (endp
= ptr
; *endp
!= '\0' && *endp
!= '\r' && *endp
!= '\n'; endp
++)
1016 parsedver
.pv_extrastr
= dupstr(ptr
, pos
);
1017 if (!parsedver
.pv_extrastr
)
1019 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1023 D(Printf("makedata: Extra string: %s\n", parsedver
.pv_extrastr
));
1025 parsedver
.pv_extralf
= "\n";
1035 /* Retrieves version information from string. The data is stored in the
1036 * global struct parsedver.pv_
1040 int makedatafromstring(CONST_STRPTR buffer
)
1042 int error
= RETURN_OK
;
1046 while (buffer
[pos
] && buffer
[pos
] != '\r' && buffer
[pos
] != '\n')
1048 /* NOTE: Not isspace()! - Piru */
1049 if (myisspace(buffer
[pos
]) &&
1050 (add
= StrToLong((STRPTR
) buffer
+ pos
+ 1, &dummy
)) != -1)
1054 /* Found something, which looks like a version. Now check, if it
1058 D(Printf("makedatafromstring: buffer + %ld: \"%s\"\n", pos
, buffer
+ pos
));
1060 ptr
= buffer
+ pos
+ 1;
1062 if (makedata(buffer
, ptr
, pos
))
1070 if (!buffer
[pos
] || buffer
[pos
] == '\r' || buffer
[pos
] == '\n')
1074 /* use the whatever is after ver tag as name */
1075 for (endp
= buffer
; *endp
!= '\0' && *endp
!= '\r' && *endp
!= '\n'; endp
++)
1077 pos
= endp
- buffer
;
1079 parsedver
.pv_name
= dupstr(buffer
, pos
);
1080 if (!parsedver
.pv_name
)
1082 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1087 /* Strip any whitespaces from the tail of the program-name.
1089 if (parsedver
.pv_name
)
1091 stripwhites(parsedver
.pv_name
);
1098 /* Case-insensitive FindResident()
1101 struct Resident
*findresident(CONST_STRPTR name
)
1103 struct Resident
**rp
;
1104 struct Resident
*resident
;
1106 rp
= (struct Resident
**) SysBase
->ResModules
;
1108 while ((resident
= *rp
++))
1111 if (((LONG
)resident
) < 0)
1112 rp
= (struct Resident
**)((ULONG
)resident
& 0x7fffffff);
1114 if (((IPTR
)resident
) & 0x01)
1115 rp
= (struct Resident
**)((IPTR
)resident
& ~1);
1118 if (!Stricmp(resident
->rt_Name
, (STRPTR
) name
))
1127 /* Case-insensitive FindName()
1130 struct Node
*findname(struct List
*list
, CONST_STRPTR name
)
1134 ForeachNode(list
, node
)
1136 if (!Stricmp(node
->ln_Name
, (STRPTR
) name
))
1146 /* Retrieve information from resident modules. Returns 0 for success.
1149 int createresidentver(struct Resident
*MyResident
)
1151 STRPTR buffer
= NULL
;
1152 CONST_STRPTR name
= NULL
;
1156 BOOL foundver
= FALSE
;
1159 if (MyResident
->rt_IdString
)
1161 buffer
= skipwhites(MyResident
->rt_IdString
);
1162 D(Printf("createresidentver: buffer \"%s\"\n", buffer
));
1164 /* Locate version part */
1169 /* NOTE: Not isspace()! - Piru */
1170 if (myisspace(buffer
[pos
]) &&
1171 StrToLong(buffer
+ pos
+ 1, &dummy
) != -1)
1179 D(Printf("createresidentver: buffer: \"%s\"\n", buffer
));
1181 name
= MyResident
->rt_IdString
;
1182 len
= buffer
- name
;
1185 /* If could not find any version info, use the resident rt_Name */
1189 D(Printf("createresidentver: buffer: \"%s\"\n", buffer
));
1191 if ((!args
.arg_full
) || (!name
))
1193 name
= MyResident
->rt_Name
;
1194 len
= strlen(MyResident
->rt_Name
);
1197 tmpbuffer
= AllocVec(len
+ strlen(buffer
) + 1, MEMF_ANY
);
1200 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1203 CopyMem(name
, tmpbuffer
, len
);
1204 strcpy(tmpbuffer
+ len
, buffer
);
1205 D(Printf("createresidentver: tmpbuffer: \"%s\"\n", tmpbuffer
));
1207 error
= makedatafromstring(tmpbuffer
);
1215 /* Retrieve version information from library. Returns 0 for success.
1218 int createlibraryver(struct Library
*MyLibrary
)
1220 STRPTR buffer
, tmpbuffer
;
1221 int error
, foundver
= FALSE
, pos
;
1223 if (MyLibrary
->lib_IdString
)
1225 //Printf("createlibraryver: lib_IdString \"%s\"\n", (LONG) MyLibrary->lib_IdString);
1226 buffer
= skipwhites(MyLibrary
->lib_IdString
);
1228 //Printf("createlibraryver: buffer \"%s\"\n", (LONG) buffer);
1230 /* Find full 'ver.rev' version info
1237 /* NOTE: Not isspace()! - Piru */
1238 if (myisspace(buffer
[pos
]) &&
1239 (add
= StrToLong(buffer
+ pos
+ 1, &dummy
)) != -1 &&
1240 buffer
[pos
+ 1 + add
] == '.')
1250 /* If could not find 'ver.rev', find any numeric */
1258 /* NOTE: Not isspace()! - Piru */
1259 if (myisspace(buffer
[pos
]) &&
1260 StrToLong(buffer
+ pos
+ 1, &dummy
) != -1)
1272 /* If could not find any version info, use the resident rt_Name */
1276 error
= RETURN_WARN
;
1279 tmpbuffer
= AllocVec(strlen(MyLibrary
->lib_Node
.ln_Name
) + strlen(buffer
) + 1, MEMF_ANY
);
1282 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1286 strcpy(tmpbuffer
, MyLibrary
->lib_Node
.ln_Name
);
1287 strcat(tmpbuffer
, buffer
);
1288 //Printf("createlibraryver: tmpbuffer: \"%s\"\n", (LONG) tmpbuffer);
1289 pos
= makedatafromstring(tmpbuffer
);
1301 /* Create default strings
1304 int createdefvers(CONST_STRPTR name
)
1306 FreeVec(parsedver
.pv_revname
);
1307 FreeVec(parsedver
.pv_vername
);
1308 FreeVec(parsedver
.pv_name
);
1310 parsedver
.pv_name
= dupstr(name
, -1);
1311 parsedver
.pv_vername
= AllocVec(14, MEMF_ANY
);
1312 parsedver
.pv_revname
= AllocVec(15, MEMF_ANY
);
1314 if (parsedver
.pv_name
&&
1315 parsedver
.pv_vername
&&
1316 parsedver
.pv_revname
)
1318 __sprintf(parsedver
.pv_vername
, "%ld", (long)parsedver
.pv_version
);
1319 __sprintf(parsedver
.pv_revname
, ".%ld", (long)parsedver
.pv_revision
);
1328 /* Create version info from named resident
1331 int makeresidentver(CONST_STRPTR name
)
1333 struct Resident
*MyResident
;
1336 if ((MyResident
= findresident(name
)))
1338 error
= createresidentver(MyResident
);
1339 if (error
!= RETURN_OK
)
1341 /* get values from residenttag */
1342 parsedver
.pv_version
= MyResident
->rt_Version
;
1343 parsedver
.pv_revision
= -1;
1344 error
= createdefvers(MyResident
->rt_Name
);
1352 /* Create version info from named list node
1355 int makeexeclistver(struct List
*list
, CONST_STRPTR name
)
1357 struct Library
*MyLibrary
;
1362 MyLibrary
= (struct Library
*) findname(list
, name
);
1365 /* get values from library */
1366 ULONG ver
= MyLibrary
->lib_Version
;
1367 ULONG rev
= MyLibrary
->lib_Revision
;
1369 error
= createlibraryver(MyLibrary
);
1370 if (error
!= RETURN_OK
||
1371 parsedver
.pv_version
!= ver
||
1372 parsedver
.pv_revision
!= rev
)
1374 /* special case where createlibraryrev was successful, but
1375 * version or revision don't match.
1377 if (error
== RETURN_OK
)
1379 /* If there is extrastr, make sure there's linefeed, too.
1381 if (parsedver
.pv_extrastr
)
1383 parsedver
.pv_extralf
= "\n";
1387 /* get values from library */
1388 parsedver
.pv_version
= ver
;
1389 parsedver
.pv_revision
= rev
;
1391 error
= createdefvers(MyLibrary
->lib_Node
.ln_Name
);
1401 /* Find resident from seglist, return NULL if none found
1404 struct Resident
*FindLibResident(BPTR Segment
)
1412 MySegment
= (IPTR
*) BADDR(Segment
);
1413 MyBuffer
= (UWORD
*) &MySegment
[1];
1414 EndBuffer
= (UWORD
*) &MySegment
[(MySegment
[-1] - sizeof(ULONG
) * 4) / sizeof(ULONG
)];
1416 while (MyBuffer
< EndBuffer
)
1418 struct Resident
*MyResident
;
1420 MyResident
= (struct Resident
*) MyBuffer
;
1421 if (MyResident
->rt_MatchWord
== RTC_MATCHWORD
&&
1422 MyResident
->rt_MatchTag
== MyResident
)
1430 Segment
=(BPTR
) MySegment
[0];
1433 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
1438 /* Find $VER: tag from seglist, return NULL if none found
1439 Returns dupstr()d string or NULL.
1442 STRPTR
FindSegmentVER(BPTR Segment
)
1447 CONST_STRPTR MyBuffer
;
1449 CONST_STRPTR EndBuffer
;
1450 CONST_STRPTR SegmentEnd
;
1452 MySegment
= BADDR(Segment
);
1453 MyBuffer
= (CONST_STRPTR
) (MySegment
+ sizeof(BPTR
));
1454 BufferLen
= *(ULONG
*)(MySegment
- sizeof(ULONG
));
1455 SegmentEnd
= (CONST_STRPTR
) (MySegment
+ (BufferLen
- sizeof(BPTR
)));
1456 EndBuffer
= SegmentEnd
- 5;
1458 while (MyBuffer
< EndBuffer
)
1460 if (MyBuffer
[0] == '$' &&
1461 MyBuffer
[1] == 'V' &&
1462 MyBuffer
[2] == 'E' &&
1463 MyBuffer
[3] == 'R' &&
1466 CONST_STRPTR EndPtr
;
1469 /* Required because some smartass could end his $VER: tag
1470 * without '\0' in the segment to save space. - Piru
1472 for (EndPtr
= MyBuffer
; EndPtr
< SegmentEnd
&& *EndPtr
; EndPtr
++)
1474 if (EndPtr
- MyBuffer
)
1476 return dupstr(MyBuffer
, EndPtr
- MyBuffer
);
1483 Segment
=*(BPTR
*)MySegment
;
1486 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
1491 /* Create version info from named device
1494 int makedevicever(CONST_STRPTR name
)
1496 struct DevProc
*MyDevProc
;
1499 MyDevProc
= GetDeviceProc((STRPTR
) name
, NULL
);
1502 if (MyDevProc
->dvp_DevNode
->dol_Type
== DLT_DEVICE
)
1506 SegList
= MyDevProc
->dvp_DevNode
->dol_misc
.dol_handler
.dol_SegList
;
1509 struct Resident
*MyResident
;
1511 MyResident
= FindLibResident(SegList
);
1514 error
= createresidentver(MyResident
);
1517 error
= RETURN_FAIL
;
1520 FreeDeviceProc(MyDevProc
);
1523 if (error
!= RETURN_OK
&& error
!= -1)
1525 Printf("Could not find version information for '%s'\n", name
);
1531 static int elf_read_block(BPTR file
, ULONG offset
, APTR buffer
, ULONG size
)
1533 if (Seek(file
, offset
, OFFSET_BEGINNING
) < 0)
1536 return Read(file
, buffer
, size
);
1539 static void *load_block(BPTR file
, ULONG offset
, ULONG size
)
1541 void *block
= AllocMem(size
, MEMF_ANY
);
1545 if (elf_read_block(file
, offset
, block
, size
) == size
)
1548 FreeMem(block
, size
);
1554 static inline UWORD
elf_read_word(UWORD data
, struct elfheader
*eh
)
1556 switch (eh
->ident
[EI_DATA
])
1559 return AROS_LE2WORD(data
);
1562 return AROS_BE2WORD(data
);
1569 static inline ULONG
elf_read_long(ULONG data
, struct elfheader
*eh
)
1571 switch (eh
->ident
[EI_DATA
])
1574 return AROS_LE2LONG(data
);
1577 return AROS_BE2LONG(data
);
1584 static ULONG
read_shnum(BPTR file
, struct elfheader
*eh
)
1586 ULONG shnum
= elf_read_word(eh
->shnum
, eh
);
1588 /* the ELF header only uses 16 bits to store the count of section headers,
1589 * so it can't handle more than 65535 headers. if the count is 0, and an
1590 * offset is defined, then the real count can be found in the first
1591 * section header (which always exists).
1593 * similarly, if the string table index is SHN_XINDEX, then the actual
1594 * index is found in the first section header also.
1596 * see the System V ABI 2001-04-24 draft for more details.
1601 ULONG shoff
= elf_read_long(eh
->shoff
, eh
);
1606 if (elf_read_block(file
, shoff
, &sh
, sizeof(sh
)) != sizeof(sh
))
1609 /* wider section header count is in the size field */
1610 shnum
= elf_read_long(sh
.size
, eh
);
1616 static BOOL
ARM_ParseAttrs(UBYTE
*data
, ULONG len
, struct elfheader
*eh
)
1618 struct attrs_section
*attrs
;
1620 if (data
[0] != ATTR_VERSION_CURRENT
)
1622 D(Printf("Unknown attributes version: 0x%02\n", data
[0]));
1626 attrs
= (void *)data
+ 1;
1629 ULONG attrs_size
= elf_read_long(attrs
->size
, eh
);
1631 if (!strcmp(attrs
->vendor
, "aeabi"))
1633 struct attrs_subsection
*aeabi_attrs
= (void *)attrs
->vendor
+ 6;
1634 ULONG aeabi_len
= attrs_size
- 10;
1636 D(Printf("Found aeabi attributes @ 0x%p (length %u)\n", aeabi_attrs
, aeabi_len
));
1638 while (aeabi_len
> 0)
1640 ULONG aeabi_attrs_size
= elf_read_long(aeabi_attrs
->size
, eh
);
1642 if (aeabi_attrs
->tag
== Tag_File
)
1644 UBYTE
*file_subsection
= (void *)aeabi_attrs
+ sizeof(struct attrs_subsection
);
1645 UBYTE file_len
= aeabi_attrs_size
- sizeof(struct attrs_subsection
);
1647 D(Printf("Found file-wide attributes @ 0x%p (length %u)\n", file_subsection
, file_len
));
1649 while (file_len
> 0)
1654 tag
= *file_subsection
++;
1659 D(Printf("Mailformed attribute tag %d (no data)\n", tag
));
1665 case Tag_CPU_raw_name
:
1667 case Tag_compatibility
:
1668 case Tag_also_compatible_with
:
1669 case Tag_conformance
:
1670 /* These two are NULL-terminated strings. Just skip. */
1674 if (*file_subsection
++ == 0)
1680 /* Read ULEB128 value */
1686 byte
= *file_subsection
++;
1689 val
|= (byte
& 0x7F) << shift
;
1700 D(Printf("ARM CPU architecture set to %d\n", val
));
1701 parsedver
.pv_arm_cpu
= val
;
1705 D(Printf("ARM FPU architecture set to %d\n", val
));
1706 parsedver
.pv_arm_fpu
= val
;
1713 aeabi_attrs
= (void *)aeabi_attrs
+ aeabi_attrs_size
;
1714 aeabi_len
-= aeabi_attrs_size
;
1719 attrs
= (void *)attrs
+ attrs_size
;
1725 static int arm_read_cpudata(BPTR file
, struct elfheader
*eh
)
1733 int_shnum
= read_shnum(file
, eh
);
1737 shoff
= elf_read_long(eh
->shoff
, eh
);
1738 shentsize
= elf_read_word(eh
->shentsize
, eh
);
1740 /* load section headers */
1741 if (!(sh
= load_block(file
, shoff
, int_shnum
* shentsize
)))
1744 for (i
= 0; i
< int_shnum
; i
++)
1746 if (sh
[i
].type
== SHT_ARM_ATTRIBUTES
)
1748 ULONG off
= elf_read_long(sh
[i
].offset
, eh
);
1749 ULONG len
= elf_read_long(sh
[i
].size
, eh
);
1750 void *data
= load_block(file
, off
, len
);
1752 D(Printf("ARM ATTRIBUTES section %d loaded at 0x%p\n", i
, data
));
1756 ARM_ParseAttrs(data
, len
, eh
);
1763 FreeMem(sh
, int_shnum
* shentsize
);
1769 /* Retrieve version information from file. Return 0 for success.
1771 #define BUFFERSIZE (16384 + 1)
1773 int makefilever(CONST_STRPTR name
)
1776 int error
; // = RETURN_OK;
1778 file
= Open((STRPTR
) name
, MODE_OLDFILE
);
1783 buffer
= AllocMem(BUFFERSIZE
, MEMF_PUBLIC
);
1786 int len
= BUFFERSIZE
- 1;
1790 ULONG len
= Read(file
, buffer
, sizeof(struct elfheader
));
1792 if (len
== sizeof(struct elfheader
))
1794 if (buffer
[0] == 0x7f && buffer
[1] == 'E' && buffer
[2] == 'L' && buffer
[3] == 'F')
1796 /* It's a ELF file, read machine ID */
1797 struct elfheader
*eh
= (struct elfheader
*)buffer
;
1799 parsedver
.pv_arch
= elf_read_word(eh
->machine
, eh
);
1800 if (parsedver
.pv_arch
== EM_ARM
)
1801 arm_read_cpudata(file
, eh
);
1806 if (buffer
[0] == 0 && buffer
[1] == 0 && buffer
[2] == 0x03 && buffer
[3] == 0xF3)
1808 /* It's AmigaOS hunk file. m68k obviously :) */
1809 parsedver
.pv_arch
= EM_68K
;
1812 /* Rewind the file */
1813 Seek(file
, 0, OFFSET_BEGINNING
);
1816 error
= findinfile(file
, "$VER:", buffer
, &len
, parsedver
.pv_md5sum
);
1817 if (error
== RETURN_OK
)
1819 parsedver
.pv_flags
|= PVF_MD5SUM
;
1826 startbuffer
= skipwhites(buffer
);
1828 //Printf("startbuffer \"%s\"\n", startbuffer);
1829 error
= makedatafromstring(startbuffer
);
1835 error
= RETURN_ERROR
;
1839 file
= LoadSeg((STRPTR
) name
);
1842 struct Resident
*MyResident
;
1844 MyResident
= FindLibResident(file
);
1846 (MyResident->rt_Type == NT_LIBRARY ||
1847 MyResident->rt_Type == NT_DEVICE)*/)
1849 error
= createresidentver(MyResident
);
1856 if (error
!= RETURN_OK
)
1858 /* If user didn't ask for md5sum or we could not calculate it.
1860 if (!args
.arg_md5sum
|| (!(parsedver
.pv_flags
& PVF_MD5SUM
)))
1862 Printf("Could not find version information for '%s'\n", (IPTR
) name
);
1869 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1872 FreeMem(buffer
, BUFFERSIZE
);
1876 error
= RETURN_FAIL
;
1877 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1885 LONG ioerr
= IoErr();
1887 if (ioerr
== ERROR_OBJECT_NOT_FOUND
||
1888 ioerr
== ERROR_OBJECT_WRONG_TYPE
)
1894 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1895 error
= RETURN_FAIL
;
1904 int makerescmdver(CONST_STRPTR name
)
1907 struct Segment
*segment
;
1911 segment
= FindSegment((STRPTR
) name
, NULL
, 0);
1914 segment
= FindSegment((STRPTR
) name
, NULL
, 1);
1919 if (segment
->seg_UC
== CMD_INTERNAL
||
1920 segment
->seg_UC
== CMD_DISABLED
)
1923 error
= makeresidentver("shell");
1928 STRPTR buffer
= FindSegmentVER(segment
->seg_Seg
);
1933 startbuffer
= skipwhites(buffer
);
1935 //Printf("startbuffer \"%s\"\n", (LONG) startbuffer);
1936 error
= makedatafromstring(startbuffer
);
1949 int setvervar(CONST_STRPTR name
, LONG ver
, LONG rev
)
1953 __sprintf(buf
, "%ld.%ld", (long) ver
, (long) rev
);
1955 return SetVar((STRPTR
) name
, buf
, -1, GVF_LOCAL_ONLY
| LV_VAR
) ? RETURN_OK
: -1;
1960 int makekickversion(void)
1962 parsedver
.pv_version
= SysBase
->LibNode
.lib_Version
;
1963 parsedver
.pv_revision
= SysBase
->SoftVer
;
1965 setvervar("Kickstart",
1966 parsedver
.pv_version
,
1967 parsedver
.pv_revision
);
1969 Printf("Kickstart %ld.%ld",
1970 (LONG
) parsedver
.pv_version
, (LONG
) parsedver
.pv_revision
);
1977 int makewbversion(void)
1980 struct Library
*VersionBase
;
1982 VersionBase
= OpenLibrary("version.library", 0);
1985 error
= makeexeclistver(&SysBase
->LibList
, "version.library");
1987 if (error
== RETURN_OK
)
1989 STRPTR newname
= dupstr("Workbench", -1);
1992 FreeVec(parsedver
.pv_name
);
1993 parsedver
.pv_name
= newname
;
1995 setvervar("Workbench", parsedver
.pv_version
, parsedver
.pv_revision
);
1998 CloseLibrary(VersionBase
);
2006 int makesysver(void)
2010 error
= makekickversion();
2011 if (error
== RETURN_OK
)
2013 error
= makewbversion();
2015 if (error
== RETURN_OK
)
2021 /* prevent silly errormsg if no version.library */
2023 error
= RETURN_WARN
;
2031 /* Determine, by which means to get the version-string.
2034 int makeverstring(CONST_STRPTR name
)
2036 int error
; // = RETURN_OK;
2037 BOOL volume
= name
[strlen(name
) - 1] == ':';
2038 CONST_STRPTR filepart
= FilePart(name
);
2042 if (!volume
&& !args
.arg_file
)
2046 error
= makeresidentver(filepart
);
2047 if (error
!= RETURN_OK
)
2052 error
= makeexeclistver(&SysBase
->LibList
, filepart
);
2053 if (error
!= RETURN_OK
)
2056 ULONG namelen
= strlen(filepart
);
2058 /* 12 is "MOSSYS:LIBS/" */
2059 if ((namebuf
= AllocVec(12 + namelen
+ 4 + 1, MEMF_PUBLIC
)))
2061 strcpy(namebuf
, "LIBS:");
2062 strcat(namebuf
, filepart
);
2063 error
= makefilever(namebuf
);
2067 if (error
!= RETURN_OK
)
2069 error
= makeexeclistver(&SysBase
->DeviceList
, filepart
);
2070 if (error
!= RETURN_OK
)
2072 strcpy(namebuf
, "DEVS:");
2073 strcat(namebuf
, filepart
);
2074 error
= makefilever(namebuf
);
2084 if (!args
.arg_res
&& error
== -1)
2088 error
= makedevicever(name
);
2094 error
= makefilever(name
);
2099 if (!args
.arg_file
&& error
== -1)
2101 error
= makerescmdver(name
);
2106 /* If user asked for md5sum, and we could calculate it, don't print error
2107 * but the md5sum + file.
2109 if (args
.arg_md5sum
&& (parsedver
.pv_flags
& PVF_MD5SUM
))
2111 parsedver
.pv_name
= dupstr(name
, -1);
2112 parsedver
.pv_flags
|= PVF_NOVERSION
;
2119 PrintFault(ERROR_OBJECT_NOT_FOUND
, (STRPTR
) ERROR_HEADER
);
2120 error
= RETURN_FAIL
;
2128 void freeverstring(void)
2130 parsedver
.pv_flags
= 0;
2131 parsedver
.pv_version
= 0;
2132 parsedver
.pv_revision
= 0;
2134 FreeVec(parsedver
.pv_extrastr
);
2135 parsedver
.pv_extrastr
= NULL
;
2136 parsedver
.pv_extralf
= NULL
;
2137 FreeVec(parsedver
.pv_datestr
);
2138 parsedver
.pv_datestr
= NULL
;
2139 FreeVec(parsedver
.pv_revname
);
2140 parsedver
.pv_revname
= NULL
;
2141 FreeVec(parsedver
.pv_vername
);
2142 parsedver
.pv_vername
= NULL
;
2143 FreeVec(parsedver
.pv_name
);
2144 parsedver
.pv_name
= NULL
;
2147 /* Compare the version given as argument with the version from the object.
2148 * Return RETURN_WARN, if args-v>object-v, otherwise return RETURN_OK.
2151 int cmpargsparsed(void)
2153 if (args
.arg_version
)
2155 if (*(args
.arg_version
) > parsedver
.pv_version
)
2159 else if (*(args
.arg_version
) == parsedver
.pv_version
&& args
.arg_revision
)
2161 if (*(args
.arg_revision
) > parsedver
.pv_revision
)
2167 else if (args
.arg_revision
)
2169 if (*(args
.arg_revision
) > parsedver
.pv_revision
)
2177 /******************************* main program ****************************/
2179 int __nocommandline
;
2183 LONG error
= RETURN_FAIL
;
2187 rda
= ReadArgs(TEMPLATE
, (IPTR
*) &args
, NULL
);
2190 if (!args
.arg_name
|| !*args
.arg_name
)
2192 /* No args, make system version */
2193 error
= makesysver();
2194 if (error
== RETURN_OK
)
2197 if (parsedver
.pv_flags
& PVF_NOVERSION
)
2199 error
= RETURN_FAIL
;
2201 if (error
== RETURN_OK
)
2203 error
= cmpargsparsed();
2215 * version file ver rev
2217 if (!args
.arg_version
&& !args
.arg_revision
)
2220 while (args
.arg_name
[narg
]) { narg
++; }
2221 if (narg
== 2 || narg
== 3)
2223 if (StrToLong(args
.arg_name
[1], &mversion
) > 0)
2225 args
.arg_version
= &mversion
;
2226 args
.arg_name
[1] = args
.arg_name
[2];
2229 args
.arg_name
[2] = NULL
;
2233 if (StrToLong(args
.arg_name
[1], &mrevision
) > 0)
2235 args
.arg_revision
= &mrevision
;
2236 args
.arg_name
[1] = NULL
;
2243 multifile
= args
.arg_name
[1] != NULL
;
2245 for (name
= args
.arg_name
; *name
; name
++)
2247 error
= makeverstring(*name
);
2248 if (error
== RETURN_OK
)
2254 /* Single args, do compare stuff also */
2255 if (parsedver
.pv_flags
& PVF_NOVERSION
)
2257 error
= RETURN_FAIL
;
2259 if (error
== RETURN_OK
)
2261 error
= cmpargsparsed();
2274 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
2275 error
= RETURN_FAIL
;