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 -- message-digest computation
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
44 If the tag contains a trailing space and dollar sign, you may use the Unix command ident.
56 ******************************************************************************/
58 #define ELF_32BIT /* This is needed for correct .ARM.Attributes parsing */
60 #include <aros/arosbase.h>
61 #include <aros/debug.h>
62 #include <aros/inquire.h>
63 #include <proto/aros.h>
71 #include <proto/exec.h>
72 #include <exec/execbase.h>
73 #include <exec/libraries.h>
74 #include <exec/memory.h>
75 #include <exec/resident.h>
76 #include <proto/dos.h>
77 #include <proto/utility.h>
78 #include <proto/alib.h>
79 #include <dos/datetime.h>
81 #include <dos/dosextens.h>
84 /*===[md5.h]==============================================================*/
86 /* Data structure for MD5 (Message-Digest) computation */
88 ULONG buf
[4]; /* scratch buffer */
89 ULONG i
[2]; /* number of _bits_ handled mod 2^64 */
90 unsigned char in
[64]; /* input buffer */
93 void MD5Init(MD5_CTX
*mdContext
);
94 void MD5Update(MD5_CTX
*mdContext
, unsigned char *inBuf
, unsigned int inLen
);
95 void MD5Final(unsigned char digest
[16], MD5_CTX
*mdContext
);
97 /*==[md5.c]===============================================================*/
100 * Used in 'version' as is, just removed the #include "ambient.h"
102 * Harry Sintonen <sintonen@iki.fi>
106 * Ambient - the ultimate desktop
107 * ------------------------------
108 * (c) 2001-2003 by David Gerber <zapek@meanmachine.ch>
109 * All Rights Reserved
114 //#include "ambient.h"
115 //#include <exec/types.h>
118 ***********************************************************************
119 ** md5.c -- the source code for MD5 routines **
120 ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
121 ** Created: 2/17/90 RLR **
122 ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
123 ***********************************************************************
127 * Edited 7 May 93 by CP to change the interface to match that
128 * of the MD5 routines in RSAREF. Due to this alteration, this
129 * code is "derived from the RSA Data Security, Inc. MD5 Message-
130 * Digest Algorithm". (See below.)
134 ***********************************************************************
135 ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
137 ** License to copy and use this software is granted provided that **
138 ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
139 ** Digest Algorithm" in all material mentioning or referencing this **
140 ** software or this function. **
142 ** License is also granted to make and use derivative works **
143 ** provided that such works are identified as "derived from the RSA **
144 ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
145 ** material mentioning or referencing the derived work. **
147 ** RSA Data Security, Inc. makes no representations concerning **
148 ** either the merchantability of this software or the suitability **
149 ** of this software for any particular purpose. It is provided "as **
150 ** is" without express or implied warranty of any kind. **
152 ** These notices must be retained in any copies of any part of this **
153 ** documentation and/or software. **
154 ***********************************************************************
160 ***********************************************************************
161 ** Message-digest routines: **
162 ** To form the message digest for a message M **
163 ** (1) Initialize a context buffer mdContext using MD5Init **
164 ** (2) Call MD5Update on mdContext and M **
165 ** (3) Call MD5Final on mdContext **
166 ** The message digest is now in the bugffer passed to MD5Final **
167 ***********************************************************************
170 static unsigned char PADDING
[64] = {
171 0x80, 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,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
181 /* F, G, H and I are basic MD5 functions */
182 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
183 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
184 #define H(x, y, z) ((x) ^ (y) ^ (z))
185 #define I(x, y, z) ((y) ^ ((x) | (~z)))
187 /* ROTATE_LEFT rotates x left n bits */
188 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
190 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
191 /* Rotation is separate from addition to prevent recomputation */
192 #define FF(a, b, c, d, x, s, ac) \
193 {(a) += F ((b), (c), (d)) + (x) + (ULONG)(ac); \
194 (a) = ROTATE_LEFT ((a), (s)); \
197 #define GG(a, b, c, d, x, s, ac) \
198 {(a) += G ((b), (c), (d)) + (x) + (ULONG)(ac); \
199 (a) = ROTATE_LEFT ((a), (s)); \
202 #define HH(a, b, c, d, x, s, ac) \
203 {(a) += H ((b), (c), (d)) + (x) + (ULONG)(ac); \
204 (a) = ROTATE_LEFT ((a), (s)); \
207 #define II(a, b, c, d, x, s, ac) \
208 {(a) += I ((b), (c), (d)) + (x) + (ULONG)(ac); \
209 (a) = ROTATE_LEFT ((a), (s)); \
213 static void Transform(register ULONG
*buf
,register ULONG
*in
);
215 /* The routine MD5Init initializes the message-digest context
216 mdContext. All fields are set to zero.
218 void MD5Init ( MD5_CTX
*mdContext
)
220 mdContext
->i
[0] = mdContext
->i
[1] = (ULONG
)0;
222 /* Load magic initialization constants.
224 mdContext
->buf
[0] = (ULONG
)0x67452301L
;
225 mdContext
->buf
[1] = (ULONG
)0xefcdab89L
;
226 mdContext
->buf
[2] = (ULONG
)0x98badcfeL
;
227 mdContext
->buf
[3] = (ULONG
)0x10325476L
;
230 /* The routine MD5Update updates the message-digest context to
231 account for the presence of each of the characters inBuf[0..inLen-1]
232 in the message whose digest is being computed.
234 void MD5Update (MD5_CTX
*mdContext
, unsigned char *inBuf
,
241 /* compute number of bytes mod 64 */
242 mdi
= (int)((mdContext
->i
[0] >> 3) & 0x3F);
244 /* update number of bits */
245 if ((mdContext
->i
[0] + ((ULONG
)inLen
<< 3)) < mdContext
->i
[0])
247 mdContext
->i
[0] += ((ULONG
)inLen
<< 3);
248 mdContext
->i
[1] += ((ULONG
)inLen
>> 29);
252 /* add new character to buffer, increment mdi */
253 mdContext
->in
[mdi
++] = *inBuf
++;
255 /* transform if necessary */
258 for (i
= 0, ii
= 0; i
< 16; i
++, ii
+= 4)
259 in
[i
] = (((ULONG
)mdContext
->in
[ii
+3]) << 24) |
260 (((ULONG
)mdContext
->in
[ii
+2]) << 16) |
261 (((ULONG
)mdContext
->in
[ii
+1]) << 8) |
262 ((ULONG
)mdContext
->in
[ii
]);
263 Transform (mdContext
->buf
, in
);
269 /* The routine MD5Final terminates the message-digest computation and
270 ends with the desired message digest in mdContext->digest[0...15].
272 void MD5Final (unsigned char digest
[16], MD5_CTX
*mdContext
)
279 /* save number of bits */
280 in
[14] = mdContext
->i
[0];
281 in
[15] = mdContext
->i
[1];
283 /* compute number of bytes mod 64 */
284 mdi
= (int)((mdContext
->i
[0] >> 3) & 0x3F);
286 /* pad out to 56 mod 64 */
287 padLen
= (mdi
< 56) ? (56 - mdi
) : (120 - mdi
);
288 MD5Update (mdContext
, PADDING
, padLen
);
290 /* append length in bits and transform */
291 for (i
= 0, ii
= 0; i
< 14; i
++, ii
+= 4)
292 in
[i
] = (((ULONG
)mdContext
->in
[ii
+3]) << 24) |
293 (((ULONG
)mdContext
->in
[ii
+2]) << 16) |
294 (((ULONG
)mdContext
->in
[ii
+1]) << 8) |
295 ((ULONG
)mdContext
->in
[ii
]);
296 Transform (mdContext
->buf
, in
);
298 /* store buffer in digest */
299 for (i
= 0, ii
= 0; i
< 4; i
++, ii
+= 4)
301 digest
[ii
] = (unsigned char) (mdContext
->buf
[i
] & 0xFF);
302 digest
[ii
+1] = (unsigned char)((mdContext
->buf
[i
] >> 8) & 0xFF);
303 digest
[ii
+2] = (unsigned char)((mdContext
->buf
[i
] >> 16) & 0xFF);
304 digest
[ii
+3] = (unsigned char)((mdContext
->buf
[i
] >> 24) & 0xFF);
308 /* Basic MD5 step. Transforms buf based on in. Note that if the Mysterious
309 Constants are arranged backwards in little-endian order and decrypted with
310 the DES they produce OCCULT MESSAGES!
312 void Transform(register ULONG
*buf
,register ULONG
*in
)
314 register ULONG a
= buf
[0], b
= buf
[1], c
= buf
[2], d
= buf
[3];
321 FF ( a
, b
, c
, d
, in
[ 0], S11
, 0xD76AA478L
); /* 1 */
322 FF ( d
, a
, b
, c
, in
[ 1], S12
, 0xE8C7B756L
); /* 2 */
323 FF ( c
, d
, a
, b
, in
[ 2], S13
, 0x242070DBL
); /* 3 */
324 FF ( b
, c
, d
, a
, in
[ 3], S14
, 0xC1BDCEEEL
); /* 4 */
325 FF ( a
, b
, c
, d
, in
[ 4], S11
, 0xF57C0FAFL
); /* 5 */
326 FF ( d
, a
, b
, c
, in
[ 5], S12
, 0x4787C62AL
); /* 6 */
327 FF ( c
, d
, a
, b
, in
[ 6], S13
, 0xA8304613L
); /* 7 */
328 FF ( b
, c
, d
, a
, in
[ 7], S14
, 0xFD469501L
); /* 8 */
329 FF ( a
, b
, c
, d
, in
[ 8], S11
, 0x698098D8L
); /* 9 */
330 FF ( d
, a
, b
, c
, in
[ 9], S12
, 0x8B44F7AFL
); /* 10 */
331 FF ( c
, d
, a
, b
, in
[10], S13
, 0xFFFF5BB1L
); /* 11 */
332 FF ( b
, c
, d
, a
, in
[11], S14
, 0x895CD7BEL
); /* 12 */
333 FF ( a
, b
, c
, d
, in
[12], S11
, 0x6B901122L
); /* 13 */
334 FF ( d
, a
, b
, c
, in
[13], S12
, 0xFD987193L
); /* 14 */
335 FF ( c
, d
, a
, b
, in
[14], S13
, 0xA679438EL
); /* 15 */
336 FF ( b
, c
, d
, a
, in
[15], S14
, 0x49B40821L
); /* 16 */
343 GG ( a
, b
, c
, d
, in
[ 1], S21
, 0xF61E2562L
); /* 17 */
344 GG ( d
, a
, b
, c
, in
[ 6], S22
, 0xC040B340L
); /* 18 */
345 GG ( c
, d
, a
, b
, in
[11], S23
, 0x265E5A51L
); /* 19 */
346 GG ( b
, c
, d
, a
, in
[ 0], S24
, 0xE9B6C7AAL
); /* 20 */
347 GG ( a
, b
, c
, d
, in
[ 5], S21
, 0xD62F105DL
); /* 21 */
348 GG ( d
, a
, b
, c
, in
[10], S22
, 0x02441453L
); /* 22 */
349 GG ( c
, d
, a
, b
, in
[15], S23
, 0xD8A1E681L
); /* 23 */
350 GG ( b
, c
, d
, a
, in
[ 4], S24
, 0xE7D3FBC8L
); /* 24 */
351 GG ( a
, b
, c
, d
, in
[ 9], S21
, 0x21E1CDE6L
); /* 25 */
352 GG ( d
, a
, b
, c
, in
[14], S22
, 0xC33707D6L
); /* 26 */
353 GG ( c
, d
, a
, b
, in
[ 3], S23
, 0xF4D50D87L
); /* 27 */
354 GG ( b
, c
, d
, a
, in
[ 8], S24
, 0x455A14EDL
); /* 28 */
355 GG ( a
, b
, c
, d
, in
[13], S21
, 0xA9E3E905L
); /* 29 */
356 GG ( d
, a
, b
, c
, in
[ 2], S22
, 0xFCEFA3F8L
); /* 30 */
357 GG ( c
, d
, a
, b
, in
[ 7], S23
, 0x676F02D9L
); /* 31 */
358 GG ( b
, c
, d
, a
, in
[12], S24
, 0x8D2A4C8AL
); /* 32 */
365 HH ( a
, b
, c
, d
, in
[ 5], S31
, 0xFFFA3942L
); /* 33 */
366 HH ( d
, a
, b
, c
, in
[ 8], S32
, 0x8771F681L
); /* 34 */
367 HH ( c
, d
, a
, b
, in
[11], S33
, 0x6D9D6122L
); /* 35 */
368 HH ( b
, c
, d
, a
, in
[14], S34
, 0xFDE5380CL
); /* 36 */
369 HH ( a
, b
, c
, d
, in
[ 1], S31
, 0xA4BEEA44L
); /* 37 */
370 HH ( d
, a
, b
, c
, in
[ 4], S32
, 0x4BDECFA9L
); /* 38 */
371 HH ( c
, d
, a
, b
, in
[ 7], S33
, 0xF6BB4B60L
); /* 39 */
372 HH ( b
, c
, d
, a
, in
[10], S34
, 0xBEBFBC70L
); /* 40 */
373 HH ( a
, b
, c
, d
, in
[13], S31
, 0x289B7EC6L
); /* 41 */
374 HH ( d
, a
, b
, c
, in
[ 0], S32
, 0xEAA127FAL
); /* 42 */
375 HH ( c
, d
, a
, b
, in
[ 3], S33
, 0xD4EF3085L
); /* 43 */
376 HH ( b
, c
, d
, a
, in
[ 6], S34
, 0x04881D05L
); /* 44 */
377 HH ( a
, b
, c
, d
, in
[ 9], S31
, 0xD9D4D039L
); /* 45 */
378 HH ( d
, a
, b
, c
, in
[12], S32
, 0xE6DB99E5L
); /* 46 */
379 HH ( c
, d
, a
, b
, in
[15], S33
, 0x1FA27CF8L
); /* 47 */
380 HH ( b
, c
, d
, a
, in
[ 2], S34
, 0xC4AC5665L
); /* 48 */
387 II ( a
, b
, c
, d
, in
[ 0], S41
, 0xF4292244L
); /* 49 */
388 II ( d
, a
, b
, c
, in
[ 7], S42
, 0x432AFF97L
); /* 50 */
389 II ( c
, d
, a
, b
, in
[14], S43
, 0xAB9423A7L
); /* 51 */
390 II ( b
, c
, d
, a
, in
[ 5], S44
, 0xFC93A039L
); /* 52 */
391 II ( a
, b
, c
, d
, in
[12], S41
, 0x655B59C3L
); /* 53 */
392 II ( d
, a
, b
, c
, in
[ 3], S42
, 0x8F0CCC92L
); /* 54 */
393 II ( c
, d
, a
, b
, in
[10], S43
, 0xFFEFF47DL
); /* 55 */
394 II ( b
, c
, d
, a
, in
[ 1], S44
, 0x85845DD1L
); /* 56 */
395 II ( a
, b
, c
, d
, in
[ 8], S41
, 0x6FA87E4FL
); /* 57 */
396 II ( d
, a
, b
, c
, in
[15], S42
, 0xFE2CE6E0L
); /* 58 */
397 II ( c
, d
, a
, b
, in
[ 6], S43
, 0xA3014314L
); /* 59 */
398 II ( b
, c
, d
, a
, in
[13], S44
, 0x4E0811A1L
); /* 60 */
399 II ( a
, b
, c
, d
, in
[ 4], S41
, 0xF7537E82L
); /* 61 */
400 II ( d
, a
, b
, c
, in
[11], S42
, 0xBD3AF235L
); /* 62 */
401 II ( c
, d
, a
, b
, in
[ 2], S43
, 0x2AD7D2BBL
); /* 63 */
402 II ( b
, c
, d
, a
, in
[ 9], S44
, 0xEB86D391L
); /* 64 */
410 /*==[end md5.c]============================================================*/
413 const TEXT version
[] = "$VER: Version 42.3 (20.11.2015)\n";
414 const TEXT ver
[] = "$VER:";
416 static const char ERROR_HEADER
[] = "Version";
418 #define TEMPLATE "NAME/M,MD5SUM/S,VERSION/N,REVISION/N,FILE/S,FULL/S,RES/S,ARCH/S"
421 CONST_STRPTR
*arg_name
;
432 LONG mversion
, mrevision
;
451 parsedver
= { NULL
, 0, 0, 0, 0, -1, 0, NULL
, NULL
, NULL
, NULL
, NULL
, {0}};
453 #define PVF_MD5SUM (1 << 0)
454 #define PVF_NOVERSION (1 << 1)
457 int makeverstring(CONST_STRPTR name
);
459 void printverstring(void);
461 void freeverstring(void);
463 int makesysver(void);
465 int cmpargsparsed(void);
468 /**************************** support functions ************************/
470 /* Duplicate string, by given length or -1 for full length
473 STRPTR
dupstr(CONST_STRPTR buffer
, LONG len
)
480 len
= strlen(buffer
);
482 ret
= AllocVec(len
+ 1, MEMF_ANY
);
485 CopyMem((STRPTR
) buffer
, ret
, len
);
495 inline int myisspace(int c
)
497 return (c
== ' ' || c
== '\t');
501 /* Return a pointer to a string, stripped by all leading whitespace characters
505 STRPTR
skipwhites(CONST_STRPTR buffer
)
509 if (buffer
[0] == '\0' || !isspace(buffer
[0]))
511 return (STRPTR
) buffer
;
517 /* Return a pointer to a string, stripped by all leading space characters
521 STRPTR
skipspaces(CONST_STRPTR buffer
)
525 if (buffer
[0] == '\0' || buffer
[0] != ' ')
527 return (STRPTR
) buffer
;
533 /* Strip all whitespace-characters from the end of a string. Note that the
534 * buffer passed in will be modified!
537 void stripwhites(STRPTR buffer
)
539 int len
= strlen(buffer
);
543 if (!isspace(buffer
[len
-1]))
554 /* Searches for a given string in a file and stores up to *lenptr characters
555 * into the buffer beginning with the first character after the given string.
558 int findinfile(BPTR file
, CONST_STRPTR string
, STRPTR buffer
, int *lenptr
, unsigned char digest
[16])
560 int error
= RETURN_OK
;
561 int buflen
= *lenptr
, len
= 0, pos
, stringlen
;
567 tmp
= AllocMem(buflen
, MEMF_PUBLIC
);
573 stringlen
= strlen(string
);
582 while ((len
= Read(file
, &tmp
[len
], buflen
- len
)) > 0)
588 MD5Update(&md5ctx
, bufpos
, len
);
593 /* If we get here we're scanning the rest of the file for md5sum. - Piru */
598 while ((len
- pos
) >= stringlen
)
600 /* Compare the current buffer position with the supplied string. */
601 if (strncmp(&tmp
[pos
], string
, stringlen
) == 0)
603 /* It is equal! Now move the rest of the buffer to the top of
604 * the buffer and fill it up.
606 int findstrlen
= len
- pos
;
608 memcpy(buffer
, &tmp
[pos
+ stringlen
], findstrlen
);
610 len
= Read(file
, &buffer
[findstrlen
], buflen
- findstrlen
);
615 MD5Update(&md5ctx
, &buffer
[findstrlen
], len
);
618 *lenptr
= findstrlen
+ len
;
629 /* Move the rest of the buffer that could not be compared (because it
630 * is smaller than the string to compare) to the top of the buffer.
634 memmove(tmp
, &tmp
[len
- stringlen
], stringlen
);
638 /* If we're not md5summing, stop file scanning now. - Piru */
639 if (!args
.arg_md5sum
)
650 FreeMem(tmp
, buflen
);
659 memset(digest
, 0, 16);
660 MD5Final(digest
, &md5ctx
);
667 /*************************** parsing functions *************************/
669 /* Convert a date in the form DD.MM.YY or DD.MM.YYYY into a numerical
670 * value. Return FALSE, if buffer doesn't contain a valid date.
673 BOOL
makedatefromstring(CONST_STRPTR
*bufptr
)
675 CONST_STRPTR buffer
= *bufptr
;
677 CONST_STRPTR headerstart
, end
;
683 //if (isspace(buffer[0]))
686 headerstart
= buffer
;
688 buffer
= strchr(buffer
, '(');
694 end
= strchr(buffer
, ')');
699 len
= (int)(end
- buffer
);
700 newbuf
= dupstr(buffer
, len
);
705 for (i
= 0; i
< len
; i
++)
709 if (c
== '.' || c
== '/')
711 else if (!isalnum(c
))
719 D(Printf("date: \"%s\"\n", newbuf
));
721 dt
.dat_Format
= FORMAT_CDN
;
723 dt
.dat_StrDay
= NULL
;
724 dt
.dat_StrDate
= newbuf
;
725 dt
.dat_StrTime
= NULL
;
726 res
= StrToDate(&dt
);
729 dt
.dat_Format
= FORMAT_DOS
;
730 res
= StrToDate(&dt
);
733 //Printf("StrToDate failed!\n");
740 //parsedver.pv_days = dt.dat_Stamp.ds_Days;
742 parsedver
.pv_datestr
= AllocVec(buffer
- headerstart
+ LEN_DATSTRING
+ 2, MEMF_ANY
);
743 if (!parsedver
.pv_datestr
)
748 dt
.dat_Stamp
.ds_Minute
= 0;
749 dt
.dat_Stamp
.ds_Tick
= 0;
751 dt
.dat_StrDate
= parsedver
.pv_datestr
+ (buffer
- headerstart
);
752 dt
.dat_Format
= FORMAT_DEF
;
755 //Printf("DateToStr failed!\n");
759 CopyMem((STRPTR
) headerstart
, parsedver
.pv_datestr
, buffer
- headerstart
);
760 res
= strlen(parsedver
.pv_datestr
);
761 parsedver
.pv_datestr
[res
++] = ')';
762 parsedver
.pv_datestr
[res
] = '\0';
770 /* Check whether the given string contains a version in the form
771 * <version>.<revision> . If not return FALSE, otherwise fill in parsedver and
775 BOOL
makeversionfromstring(CONST_STRPTR
*bufptr
)
778 CONST_STRPTR buffer
= *bufptr
;
779 CONST_STRPTR verstart
, revstart
;
781 //Printf("makeversionfromstring: buffer \"%s\"\n", (LONG) buffer);
786 pos
= StrToLong((STRPTR
) buffer
, &ver
);
791 parsedver
.pv_version
= ver
;
792 parsedver
.pv_revision
= -1;
794 parsedver
.pv_vername
= dupstr(verstart
, pos
);
795 if (!parsedver
.pv_vername
)
804 buffer
= skipspaces(buffer
); /* NOTE: skipspaces, not skipwhites! */
812 pos
= StrToLong((STRPTR
) buffer
, &rev
);
819 parsedver
.pv_revision
= rev
;
821 /* calc the revision string len */
822 pos
= buffer
+ pos
- revstart
;
823 parsedver
.pv_revname
= dupstr(revstart
, pos
);
824 if (!parsedver
.pv_revname
)
829 *bufptr
= revstart
+ pos
;
834 static const char *arm_cpus
[] =
852 static const char *arm_fpus
[] =
863 void printverstring(void)
867 if (parsedver
.pv_flags
& PVF_MD5SUM
)
869 /* Endianess safe version */
870 Printf("%02lX%02lX%02lX%02lX"
871 "%02lX%02lX%02lX%02lX"
872 "%02lX%02lX%02lX%02lX"
873 "%02lX%02lX%02lX%02lX ",
874 parsedver
.pv_md5sum
[0],
875 parsedver
.pv_md5sum
[1],
876 parsedver
.pv_md5sum
[2],
877 parsedver
.pv_md5sum
[3],
878 parsedver
.pv_md5sum
[4],
879 parsedver
.pv_md5sum
[5],
880 parsedver
.pv_md5sum
[6],
881 parsedver
.pv_md5sum
[7],
882 parsedver
.pv_md5sum
[8],
883 parsedver
.pv_md5sum
[9],
884 parsedver
.pv_md5sum
[10],
885 parsedver
.pv_md5sum
[11],
886 parsedver
.pv_md5sum
[12],
887 parsedver
.pv_md5sum
[13],
888 parsedver
.pv_md5sum
[14],
889 parsedver
.pv_md5sum
[15]);
893 /* "01234567012345670123456701234567: " */
894 PutStr("<no md5sum available> ");
898 if (parsedver
.pv_flags
& PVF_NOVERSION
)
900 Printf("%s\n", (IPTR
) parsedver
.pv_name
);
906 /* If md5sum output was there, avoid linefeed to allow parsing the output - Piru */
909 parsedver
.pv_extralf
= " ";
912 Printf("%s%s%s%s%s%s%s\n",
913 (IPTR
) parsedver
.pv_name
, (IPTR
) (*parsedver
.pv_name
? " " : ""),
914 (IPTR
) parsedver
.pv_vername
, (IPTR
) parsedver
.pv_revname
,
915 (IPTR
) (parsedver
.pv_datestr
? (IPTR
)parsedver
.pv_datestr
: (IPTR
)""),
916 (IPTR
) (parsedver
.pv_extralf
? (IPTR
)parsedver
.pv_extralf
: (IPTR
)""),
917 (IPTR
) (parsedver
.pv_extrastr
? (IPTR
)parsedver
.pv_extrastr
: (IPTR
)""));
922 (IPTR
) parsedver
.pv_name
, (IPTR
) (*parsedver
.pv_name
? " " : ""),
923 (IPTR
) parsedver
.pv_vername
, (IPTR
) parsedver
.pv_revname
);
930 if (parsedver
.pv_arch
== EM_ARM
)
932 Printf("Architecture: ");
934 if (parsedver
.pv_arm_cpu
== (UBYTE
)-1)
935 Printf("ARM (unspecified)");
936 else if (parsedver
.pv_arm_cpu
<= ELF_CPU_ARMv7EM
)
937 Printf(arm_cpus
[parsedver
.pv_arm_cpu
]);
939 Printf("Unknown ARM (%d)", parsedver
.pv_arm_cpu
);
941 if (parsedver
.pv_arm_fpu
> 6)
942 Printf(" Unknown FPU (%d)", parsedver
.pv_arm_fpu
);
943 else if (parsedver
.pv_arm_fpu
)
944 Printf(" %s", arm_fpus
[parsedver
.pv_arm_fpu
]);
950 switch (parsedver
.pv_arch
)
953 /* No information available */
979 Printf("Architecture: %s\n", arch
);
987 int makedata(CONST_STRPTR buffer
, CONST_STRPTR ptr
, int pos
)
989 D(Printf("makedata: buffer \"%s\" ptr \"%s\"\n", buffer
, ptr
));
991 if (makeversionfromstring(&ptr
))
997 /* Copy the program-name into a buffer. */
998 parsedver
.pv_name
= dupstr(buffer
, pos
);
999 if (!parsedver
.pv_name
)
1001 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1005 /* Now find the date */
1006 D(Printf("makedata: ptr #1: \"%s\"\n", ptr
));
1007 doskip
= strchr(ptr
, '(') ? TRUE
: FALSE
;
1008 (void) makedatefromstring(&ptr
);
1010 D(Printf("makedata: ptr #2: \"%s\"\n", ptr
));
1012 ptr
= skipspaces(ptr
); /* NOTE: not skipwhites! */
1013 for (endp
= ptr
; *endp
!= '\0' && *endp
!= '\r' && *endp
!= '\n'; endp
++)
1016 if (pos
&& ptr
[pos
-1] == '$')
1020 parsedver
.pv_extrastr
= dupstr(ptr
, pos
);
1021 if (!parsedver
.pv_extrastr
)
1023 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1027 D(Printf("makedata: Extra string: %s\n", parsedver
.pv_extrastr
));
1029 parsedver
.pv_extralf
= "\n";
1039 /* Retrieves version information from string. The data is stored in the
1040 * global struct parsedver.pv_
1044 int makedatafromstring(CONST_STRPTR buffer
)
1046 int error
= RETURN_OK
;
1050 while (buffer
[pos
] && buffer
[pos
] != '\r' && buffer
[pos
] != '\n')
1052 /* NOTE: Not isspace()! - Piru */
1053 if (myisspace(buffer
[pos
]) &&
1054 (add
= StrToLong((STRPTR
) buffer
+ pos
+ 1, &dummy
)) != -1)
1058 /* Found something, which looks like a version. Now check, if it
1062 D(Printf("makedatafromstring: buffer + %ld: \"%s\"\n", pos
, buffer
+ pos
));
1064 ptr
= buffer
+ pos
+ 1;
1066 if (makedata(buffer
, ptr
, pos
))
1074 if (!buffer
[pos
] || buffer
[pos
] == '\r' || buffer
[pos
] == '\n')
1078 /* use the whatever is after ver tag as name */
1079 for (endp
= buffer
; *endp
!= '\0' && *endp
!= '\r' && *endp
!= '\n'; endp
++)
1081 pos
= endp
- buffer
;
1083 parsedver
.pv_name
= dupstr(buffer
, pos
);
1084 if (!parsedver
.pv_name
)
1086 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1091 /* Strip any whitespaces from the tail of the program-name.
1093 if (parsedver
.pv_name
)
1095 stripwhites(parsedver
.pv_name
);
1102 /* Case-insensitive FindResident()
1105 struct Resident
*findresident(CONST_STRPTR name
)
1107 struct Resident
**rp
;
1108 struct Resident
*resident
;
1110 rp
= (struct Resident
**) SysBase
->ResModules
;
1112 while ((resident
= *rp
++))
1115 if (((LONG
)resident
) < 0)
1116 rp
= (struct Resident
**)((ULONG
)resident
& 0x7fffffff);
1118 if (((IPTR
)resident
) & 0x01)
1119 rp
= (struct Resident
**)((IPTR
)resident
& ~1);
1122 if (!Stricmp(resident
->rt_Name
, (STRPTR
) name
))
1131 /* Case-insensitive FindName()
1134 struct Node
*findname(struct List
*list
, CONST_STRPTR name
)
1138 ForeachNode(list
, node
)
1140 if (!Stricmp(node
->ln_Name
, (STRPTR
) name
))
1150 /* Retrieve information from resident modules. Returns 0 for success.
1153 int createresidentver(struct Resident
*MyResident
)
1155 STRPTR buffer
= NULL
;
1156 CONST_STRPTR name
= NULL
;
1160 BOOL foundver
= FALSE
;
1163 if (MyResident
->rt_IdString
)
1165 buffer
= skipwhites(MyResident
->rt_IdString
);
1166 D(Printf("createresidentver: buffer \"%s\"\n", buffer
));
1168 /* Locate version part */
1173 /* NOTE: Not isspace()! - Piru */
1174 if (myisspace(buffer
[pos
]) &&
1175 StrToLong(buffer
+ pos
+ 1, &dummy
) != -1)
1183 D(Printf("createresidentver: buffer: \"%s\"\n", buffer
));
1185 name
= MyResident
->rt_IdString
;
1186 len
= buffer
- name
;
1189 /* If could not find any version info, use the resident rt_Name */
1193 D(Printf("createresidentver: buffer: \"%s\"\n", buffer
));
1195 if ((!args
.arg_full
) || (!name
))
1197 name
= MyResident
->rt_Name
;
1198 len
= strlen(MyResident
->rt_Name
);
1201 tmpbuffer
= AllocVec(len
+ strlen(buffer
) + 1, MEMF_ANY
);
1204 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1207 CopyMem(name
, tmpbuffer
, len
);
1208 strcpy(tmpbuffer
+ len
, buffer
);
1209 D(Printf("createresidentver: tmpbuffer: \"%s\"\n", tmpbuffer
));
1211 error
= makedatafromstring(tmpbuffer
);
1219 /* Retrieve version information from library. Returns 0 for success.
1222 int createlibraryver(struct Library
*MyLibrary
)
1224 STRPTR buffer
, tmpbuffer
;
1225 int error
, foundver
= FALSE
, pos
;
1227 if (MyLibrary
->lib_IdString
)
1229 //Printf("createlibraryver: lib_IdString \"%s\"\n", (LONG) MyLibrary->lib_IdString);
1230 buffer
= skipwhites(MyLibrary
->lib_IdString
);
1232 //Printf("createlibraryver: buffer \"%s\"\n", (LONG) buffer);
1234 /* Find full 'ver.rev' version info
1241 /* NOTE: Not isspace()! - Piru */
1242 if (myisspace(buffer
[pos
]) &&
1243 (add
= StrToLong(buffer
+ pos
+ 1, &dummy
)) != -1 &&
1244 buffer
[pos
+ 1 + add
] == '.')
1254 /* If could not find 'ver.rev', find any numeric */
1262 /* NOTE: Not isspace()! - Piru */
1263 if (myisspace(buffer
[pos
]) &&
1264 StrToLong(buffer
+ pos
+ 1, &dummy
) != -1)
1276 /* If could not find any version info, use the resident rt_Name */
1280 error
= RETURN_WARN
;
1283 tmpbuffer
= AllocVec(strlen(MyLibrary
->lib_Node
.ln_Name
) + strlen(buffer
) + 1, MEMF_ANY
);
1286 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1290 strcpy(tmpbuffer
, MyLibrary
->lib_Node
.ln_Name
);
1291 strcat(tmpbuffer
, buffer
);
1292 //Printf("createlibraryver: tmpbuffer: \"%s\"\n", (LONG) tmpbuffer);
1293 pos
= makedatafromstring(tmpbuffer
);
1305 /* Create default strings
1308 int createdefvers(CONST_STRPTR name
)
1310 FreeVec(parsedver
.pv_revname
);
1311 FreeVec(parsedver
.pv_vername
);
1312 FreeVec(parsedver
.pv_name
);
1314 parsedver
.pv_name
= dupstr(name
, -1);
1315 parsedver
.pv_vername
= AllocVec(14, MEMF_ANY
);
1316 parsedver
.pv_revname
= AllocVec(15, MEMF_ANY
);
1318 if (parsedver
.pv_name
&&
1319 parsedver
.pv_vername
&&
1320 parsedver
.pv_revname
)
1322 __sprintf(parsedver
.pv_vername
, "%ld", (long)parsedver
.pv_version
);
1323 __sprintf(parsedver
.pv_revname
, ".%ld", (long)parsedver
.pv_revision
);
1332 /* Create version info from named resident
1335 int makeresidentver(CONST_STRPTR name
)
1337 struct Resident
*MyResident
;
1340 if ((MyResident
= findresident(name
)))
1342 error
= createresidentver(MyResident
);
1343 if (error
!= RETURN_OK
)
1345 /* get values from residenttag */
1346 parsedver
.pv_version
= MyResident
->rt_Version
;
1347 parsedver
.pv_revision
= -1;
1348 error
= createdefvers(MyResident
->rt_Name
);
1356 /* Create version info from named list node
1359 int makeexeclistver(struct List
*list
, CONST_STRPTR name
)
1361 struct Library
*MyLibrary
;
1366 MyLibrary
= (struct Library
*) findname(list
, name
);
1369 /* get values from library */
1370 ULONG ver
= MyLibrary
->lib_Version
;
1371 ULONG rev
= MyLibrary
->lib_Revision
;
1373 error
= createlibraryver(MyLibrary
);
1374 if (error
!= RETURN_OK
||
1375 parsedver
.pv_version
!= ver
||
1376 parsedver
.pv_revision
!= rev
)
1378 /* special case where createlibraryrev was successful, but
1379 * version or revision don't match.
1381 if (error
== RETURN_OK
)
1383 /* If there is extrastr, make sure there's linefeed, too.
1385 if (parsedver
.pv_extrastr
)
1387 parsedver
.pv_extralf
= "\n";
1391 /* get values from library */
1392 parsedver
.pv_version
= ver
;
1393 parsedver
.pv_revision
= rev
;
1395 error
= createdefvers(MyLibrary
->lib_Node
.ln_Name
);
1405 /* Find resident from seglist, return NULL if none found
1408 struct Resident
*FindLibResident(BPTR Segment
)
1416 MySegment
= (IPTR
*) BADDR(Segment
);
1417 MyBuffer
= (UWORD
*) &MySegment
[1];
1418 EndBuffer
= (UWORD
*) &MySegment
[(MySegment
[-1] - sizeof(ULONG
) * 4) / sizeof(ULONG
)];
1420 while (MyBuffer
< EndBuffer
)
1422 struct Resident
*MyResident
;
1424 MyResident
= (struct Resident
*) MyBuffer
;
1425 if (MyResident
->rt_MatchWord
== RTC_MATCHWORD
&&
1426 MyResident
->rt_MatchTag
== MyResident
)
1434 Segment
=(BPTR
) MySegment
[0];
1437 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
1442 /* Find $VER: tag from seglist, return NULL if none found
1443 Returns dupstr()d string or NULL.
1446 STRPTR
FindSegmentVER(BPTR Segment
)
1451 CONST_STRPTR MyBuffer
;
1453 CONST_STRPTR EndBuffer
;
1454 CONST_STRPTR SegmentEnd
;
1456 MySegment
= BADDR(Segment
);
1457 MyBuffer
= (CONST_STRPTR
) (MySegment
+ sizeof(BPTR
));
1458 BufferLen
= *(ULONG
*)(MySegment
- sizeof(ULONG
));
1459 SegmentEnd
= (CONST_STRPTR
) (MySegment
+ (BufferLen
- sizeof(BPTR
)));
1460 EndBuffer
= SegmentEnd
- 5;
1462 while (MyBuffer
< EndBuffer
)
1464 if (MyBuffer
[0] == '$' &&
1465 MyBuffer
[1] == 'V' &&
1466 MyBuffer
[2] == 'E' &&
1467 MyBuffer
[3] == 'R' &&
1470 CONST_STRPTR EndPtr
;
1473 /* Required because some smartass could end his $VER: tag
1474 * without '\0' in the segment to save space. - Piru
1476 for (EndPtr
= MyBuffer
; EndPtr
< SegmentEnd
&& *EndPtr
; EndPtr
++)
1478 if (EndPtr
- MyBuffer
)
1480 return dupstr(MyBuffer
, EndPtr
- MyBuffer
);
1487 Segment
=*(BPTR
*)MySegment
;
1490 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
1495 /* Create version info from named device
1498 int makedevicever(CONST_STRPTR name
)
1500 struct DevProc
*MyDevProc
;
1503 MyDevProc
= GetDeviceProc((STRPTR
) name
, NULL
);
1506 if (MyDevProc
->dvp_DevNode
->dol_Type
== DLT_DEVICE
)
1510 SegList
= MyDevProc
->dvp_DevNode
->dol_misc
.dol_handler
.dol_SegList
;
1513 struct Resident
*MyResident
;
1515 MyResident
= FindLibResident(SegList
);
1518 error
= createresidentver(MyResident
);
1521 error
= RETURN_FAIL
;
1524 FreeDeviceProc(MyDevProc
);
1527 if (error
!= RETURN_OK
&& error
!= -1)
1529 Printf("Could not find version information for '%s'\n", name
);
1535 static int elf_read_block(BPTR file
, ULONG offset
, APTR buffer
, ULONG size
)
1537 if (Seek(file
, offset
, OFFSET_BEGINNING
) < 0)
1540 return Read(file
, buffer
, size
);
1543 static void *load_block(BPTR file
, ULONG offset
, ULONG size
)
1545 void *block
= AllocMem(size
, MEMF_ANY
);
1549 if (elf_read_block(file
, offset
, block
, size
) == size
)
1552 FreeMem(block
, size
);
1558 static inline UWORD
elf_read_word(UWORD data
, struct elfheader
*eh
)
1560 switch (eh
->ident
[EI_DATA
])
1563 return AROS_LE2WORD(data
);
1566 return AROS_BE2WORD(data
);
1573 static inline ULONG
elf_read_long(ULONG data
, struct elfheader
*eh
)
1575 switch (eh
->ident
[EI_DATA
])
1578 return AROS_LE2LONG(data
);
1581 return AROS_BE2LONG(data
);
1588 static ULONG
read_shnum(BPTR file
, struct elfheader
*eh
)
1590 ULONG shnum
= elf_read_word(eh
->shnum
, eh
);
1592 /* the ELF header only uses 16 bits to store the count of section headers,
1593 * so it can't handle more than 65535 headers. if the count is 0, and an
1594 * offset is defined, then the real count can be found in the first
1595 * section header (which always exists).
1597 * similarly, if the string table index is SHN_XINDEX, then the actual
1598 * index is found in the first section header also.
1600 * see the System V ABI 2001-04-24 draft for more details.
1605 ULONG shoff
= elf_read_long(eh
->shoff
, eh
);
1610 if (elf_read_block(file
, shoff
, &sh
, sizeof(sh
)) != sizeof(sh
))
1613 /* wider section header count is in the size field */
1614 shnum
= elf_read_long(sh
.size
, eh
);
1620 static BOOL
ARM_ParseAttrs(UBYTE
*data
, ULONG len
, struct elfheader
*eh
)
1622 struct attrs_section
*attrs
;
1624 if (data
[0] != ATTR_VERSION_CURRENT
)
1626 D(Printf("Unknown attributes version: 0x%02\n", data
[0]));
1630 attrs
= (void *)data
+ 1;
1633 ULONG attrs_size
= elf_read_long(attrs
->size
, eh
);
1635 if (!strcmp(attrs
->vendor
, "aeabi"))
1637 struct attrs_subsection
*aeabi_attrs
= (void *)attrs
->vendor
+ 6;
1638 ULONG aeabi_len
= attrs_size
- 10;
1640 D(Printf("Found aeabi attributes @ 0x%p (length %u)\n", aeabi_attrs
, aeabi_len
));
1642 while (aeabi_len
> 0)
1644 ULONG aeabi_attrs_size
= elf_read_long(aeabi_attrs
->size
, eh
);
1646 if (aeabi_attrs
->tag
== Tag_File
)
1648 UBYTE
*file_subsection
= (void *)aeabi_attrs
+ sizeof(struct attrs_subsection
);
1649 UBYTE file_len
= aeabi_attrs_size
- sizeof(struct attrs_subsection
);
1651 D(Printf("Found file-wide attributes @ 0x%p (length %u)\n", file_subsection
, file_len
));
1653 while (file_len
> 0)
1658 tag
= *file_subsection
++;
1663 D(Printf("Mailformed attribute tag %d (no data)\n", tag
));
1669 case Tag_CPU_raw_name
:
1671 case Tag_compatibility
:
1672 case Tag_also_compatible_with
:
1673 case Tag_conformance
:
1674 /* These two are NULL-terminated strings. Just skip. */
1678 if (*file_subsection
++ == 0)
1684 /* Read ULEB128 value */
1690 byte
= *file_subsection
++;
1693 val
|= (byte
& 0x7F) << shift
;
1704 D(Printf("ARM CPU architecture set to %d\n", val
));
1705 parsedver
.pv_arm_cpu
= val
;
1709 D(Printf("ARM FPU architecture set to %d\n", val
));
1710 parsedver
.pv_arm_fpu
= val
;
1717 aeabi_attrs
= (void *)aeabi_attrs
+ aeabi_attrs_size
;
1718 aeabi_len
-= aeabi_attrs_size
;
1723 attrs
= (void *)attrs
+ attrs_size
;
1729 static int arm_read_cpudata(BPTR file
, struct elfheader
*eh
)
1737 int_shnum
= read_shnum(file
, eh
);
1741 shoff
= elf_read_long(eh
->shoff
, eh
);
1742 shentsize
= elf_read_word(eh
->shentsize
, eh
);
1744 /* load section headers */
1745 if (!(sh
= load_block(file
, shoff
, int_shnum
* shentsize
)))
1748 for (i
= 0; i
< int_shnum
; i
++)
1750 if (sh
[i
].type
== SHT_ARM_ATTRIBUTES
)
1752 ULONG off
= elf_read_long(sh
[i
].offset
, eh
);
1753 ULONG len
= elf_read_long(sh
[i
].size
, eh
);
1754 void *data
= load_block(file
, off
, len
);
1756 D(Printf("ARM ATTRIBUTES section %d loaded at 0x%p\n", i
, data
));
1760 ARM_ParseAttrs(data
, len
, eh
);
1767 FreeMem(sh
, int_shnum
* shentsize
);
1773 /* Retrieve version information from file. Return 0 for success.
1775 #define BUFFERSIZE (16384 + 1)
1777 int makefilever(CONST_STRPTR name
)
1780 int error
; // = RETURN_OK;
1782 file
= Open((STRPTR
) name
, MODE_OLDFILE
);
1787 buffer
= AllocMem(BUFFERSIZE
, MEMF_PUBLIC
);
1790 int len
= BUFFERSIZE
- 1;
1794 ULONG len
= Read(file
, buffer
, sizeof(struct elfheader
));
1796 if (len
== sizeof(struct elfheader
))
1798 if (buffer
[0] == 0x7f && buffer
[1] == 'E' && buffer
[2] == 'L' && buffer
[3] == 'F')
1800 /* It's an ELF file, read machine ID */
1801 struct elfheader
*eh
= (struct elfheader
*)buffer
;
1803 parsedver
.pv_arch
= elf_read_word(eh
->machine
, eh
);
1804 if (parsedver
.pv_arch
== EM_ARM
)
1805 arm_read_cpudata(file
, eh
);
1810 if (buffer
[0] == 0 && buffer
[1] == 0 && buffer
[2] == 0x03 && buffer
[3] == 0xF3)
1812 /* It's AmigaOS hunk file. m68k obviously :) */
1813 parsedver
.pv_arch
= EM_68K
;
1816 /* Rewind the file */
1817 Seek(file
, 0, OFFSET_BEGINNING
);
1820 error
= findinfile(file
, ver
, buffer
, &len
, parsedver
.pv_md5sum
);
1821 if (error
== RETURN_OK
)
1823 parsedver
.pv_flags
|= PVF_MD5SUM
;
1830 startbuffer
= skipwhites(buffer
);
1832 //Printf("startbuffer \"%s\"\n", startbuffer);
1833 error
= makedatafromstring(startbuffer
);
1839 error
= RETURN_ERROR
;
1843 file
= LoadSeg((STRPTR
) name
);
1846 struct Resident
*MyResident
;
1848 MyResident
= FindLibResident(file
);
1850 (MyResident->rt_Type == NT_LIBRARY ||
1851 MyResident->rt_Type == NT_DEVICE)*/)
1853 error
= createresidentver(MyResident
);
1860 if (error
!= RETURN_OK
)
1862 /* If user didn't ask for md5sum or we could not calculate it.
1864 if (!args
.arg_md5sum
|| (!(parsedver
.pv_flags
& PVF_MD5SUM
)))
1866 Printf("Could not find version information for '%s'\n", (IPTR
) name
);
1873 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1876 FreeMem(buffer
, BUFFERSIZE
);
1880 error
= RETURN_FAIL
;
1881 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1889 LONG ioerr
= IoErr();
1891 if (ioerr
== ERROR_OBJECT_NOT_FOUND
||
1892 ioerr
== ERROR_OBJECT_WRONG_TYPE
)
1898 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1899 error
= RETURN_FAIL
;
1908 int makerescmdver(CONST_STRPTR name
)
1911 struct Segment
*segment
;
1915 segment
= FindSegment((STRPTR
) name
, NULL
, 0);
1918 segment
= FindSegment((STRPTR
) name
, NULL
, 1);
1923 if (segment
->seg_UC
== CMD_INTERNAL
||
1924 segment
->seg_UC
== CMD_DISABLED
)
1927 error
= makeresidentver("shell");
1932 STRPTR buffer
= FindSegmentVER(segment
->seg_Seg
);
1937 startbuffer
= skipwhites(buffer
);
1939 //Printf("startbuffer \"%s\"\n", (LONG) startbuffer);
1940 error
= makedatafromstring(startbuffer
);
1953 int setvervar(CONST_STRPTR name
, LONG ver
, LONG rev
)
1957 __sprintf(buf
, "%ld.%ld", (long) ver
, (long) rev
);
1959 return SetVar((STRPTR
) name
, buf
, -1, GVF_LOCAL_ONLY
| LV_VAR
) ? RETURN_OK
: -1;
1964 int makekickversion(void)
1966 parsedver
.pv_version
= SysBase
->LibNode
.lib_Version
;
1967 parsedver
.pv_revision
= SysBase
->SoftVer
;
1969 setvervar("Kickstart",
1970 parsedver
.pv_version
,
1971 parsedver
.pv_revision
);
1973 Printf("Kickstart %ld.%ld",
1974 (LONG
) parsedver
.pv_version
, (LONG
) parsedver
.pv_revision
);
1981 int makewbversion(void)
1984 struct Library
*VersionBase
;
1986 VersionBase
= OpenLibrary("version.library", 0);
1989 error
= makeexeclistver(&SysBase
->LibList
, "version.library");
1991 if (error
== RETURN_OK
)
1993 STRPTR newname
= dupstr("Workbench", -1);
1996 FreeVec(parsedver
.pv_name
);
1997 parsedver
.pv_name
= newname
;
1999 setvervar("Workbench", parsedver
.pv_version
, parsedver
.pv_revision
);
2002 CloseLibrary(VersionBase
);
2010 int makesysver(void)
2014 error
= makekickversion();
2015 if (error
== RETURN_OK
)
2017 error
= makewbversion();
2019 if (error
== RETURN_OK
)
2025 /* prevent silly errormsg if no version.library */
2027 error
= RETURN_WARN
;
2035 /* Determine, by which means to get the version-string.
2038 int makeverstring(CONST_STRPTR name
)
2040 int error
; // = RETURN_OK;
2041 BOOL volume
= name
[strlen(name
) - 1] == ':';
2042 CONST_STRPTR filepart
= FilePart(name
);
2046 if (!volume
&& !args
.arg_file
)
2050 error
= makeresidentver(filepart
);
2051 if (error
!= RETURN_OK
)
2056 error
= makeexeclistver(&SysBase
->LibList
, filepart
);
2057 if (error
!= RETURN_OK
)
2060 ULONG namelen
= strlen(filepart
);
2062 /* 12 is "MOSSYS:LIBS/" */
2063 if ((namebuf
= AllocVec(12 + namelen
+ 4 + 1, MEMF_PUBLIC
)))
2065 strcpy(namebuf
, "LIBS:");
2066 strcat(namebuf
, filepart
);
2067 error
= makefilever(namebuf
);
2071 if (error
!= RETURN_OK
)
2073 error
= makeexeclistver(&SysBase
->DeviceList
, filepart
);
2074 if (error
!= RETURN_OK
)
2076 strcpy(namebuf
, "DEVS:");
2077 strcat(namebuf
, filepart
);
2078 error
= makefilever(namebuf
);
2088 if (!args
.arg_res
&& error
== -1)
2092 error
= makedevicever(name
);
2098 error
= makefilever(name
);
2103 if (!args
.arg_file
&& error
== -1)
2105 error
= makerescmdver(name
);
2110 /* If user asked for md5sum, and we could calculate it, don't print error
2111 * but the md5sum + file.
2113 if (args
.arg_md5sum
&& (parsedver
.pv_flags
& PVF_MD5SUM
))
2115 parsedver
.pv_name
= dupstr(name
, -1);
2116 parsedver
.pv_flags
|= PVF_NOVERSION
;
2123 PrintFault(ERROR_OBJECT_NOT_FOUND
, (STRPTR
) ERROR_HEADER
);
2124 error
= RETURN_FAIL
;
2132 void freeverstring(void)
2134 parsedver
.pv_flags
= 0;
2135 parsedver
.pv_version
= 0;
2136 parsedver
.pv_revision
= 0;
2138 FreeVec(parsedver
.pv_extrastr
);
2139 parsedver
.pv_extrastr
= NULL
;
2140 parsedver
.pv_extralf
= NULL
;
2141 FreeVec(parsedver
.pv_datestr
);
2142 parsedver
.pv_datestr
= NULL
;
2143 FreeVec(parsedver
.pv_revname
);
2144 parsedver
.pv_revname
= NULL
;
2145 FreeVec(parsedver
.pv_vername
);
2146 parsedver
.pv_vername
= NULL
;
2147 FreeVec(parsedver
.pv_name
);
2148 parsedver
.pv_name
= NULL
;
2151 /* Compare the version given as argument with the version from the object.
2152 * Return RETURN_WARN, if args-v>object-v, otherwise return RETURN_OK.
2155 int cmpargsparsed(void)
2157 if (args
.arg_version
)
2159 if (*(args
.arg_version
) > parsedver
.pv_version
)
2163 else if (*(args
.arg_version
) == parsedver
.pv_version
&& args
.arg_revision
)
2165 if (*(args
.arg_revision
) > parsedver
.pv_revision
)
2171 else if (args
.arg_revision
)
2173 if (*(args
.arg_revision
) > parsedver
.pv_revision
)
2181 /******************************* main program ****************************/
2183 int __nocommandline
;
2187 LONG error
= RETURN_FAIL
;
2191 rda
= ReadArgs(TEMPLATE
, (IPTR
*) &args
, NULL
);
2194 if (!args
.arg_name
|| !*args
.arg_name
)
2196 /* No args, make system version */
2197 error
= makesysver();
2198 if (error
== RETURN_OK
)
2201 if (parsedver
.pv_flags
& PVF_NOVERSION
)
2203 error
= RETURN_FAIL
;
2205 if (error
== RETURN_OK
)
2207 error
= cmpargsparsed();
2219 * version file ver rev
2221 if (!args
.arg_version
&& !args
.arg_revision
)
2224 while (args
.arg_name
[narg
]) { narg
++; }
2225 if (narg
== 2 || narg
== 3)
2227 if (StrToLong(args
.arg_name
[1], &mversion
) > 0)
2229 args
.arg_version
= &mversion
;
2230 args
.arg_name
[1] = args
.arg_name
[2];
2233 args
.arg_name
[2] = NULL
;
2237 if (StrToLong(args
.arg_name
[1], &mrevision
) > 0)
2239 args
.arg_revision
= &mrevision
;
2240 args
.arg_name
[1] = NULL
;
2247 multifile
= args
.arg_name
[1] != NULL
;
2249 for (name
= args
.arg_name
; *name
; name
++)
2251 error
= makeverstring(*name
);
2252 if (error
== RETURN_OK
)
2258 /* Single args, do compare stuff also */
2259 if (parsedver
.pv_flags
& PVF_NOVERSION
)
2261 error
= RETURN_FAIL
;
2263 if (error
== RETURN_OK
)
2265 error
= cmpargsparsed();
2278 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
2279 error
= RETURN_FAIL
;