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 #if defined(__AROSPLATFORM_SMP__)
85 #include <aros/types/spinlock_s.h>
86 #include <proto/execlock.h>
87 #include <resources/execlock.h>
90 /*===[md5.h]==============================================================*/
92 /* Data structure for MD5 (Message-Digest) computation */
94 ULONG buf
[4]; /* scratch buffer */
95 ULONG i
[2]; /* number of _bits_ handled mod 2^64 */
96 unsigned char in
[64]; /* input buffer */
99 void MD5Init(MD5_CTX
*mdContext
);
100 void MD5Update(MD5_CTX
*mdContext
, unsigned char *inBuf
, unsigned int inLen
);
101 void MD5Final(unsigned char digest
[16], MD5_CTX
*mdContext
);
103 /*==[md5.c]===============================================================*/
106 * Used in 'version' as is, just removed the #include "ambient.h"
108 * Harry Sintonen <sintonen@iki.fi>
112 * Ambient - the ultimate desktop
113 * ------------------------------
114 * (c) 2001-2003 by David Gerber <zapek@meanmachine.ch>
115 * All Rights Reserved
120 //#include "ambient.h"
121 //#include <exec/types.h>
124 ***********************************************************************
125 ** md5.c -- the source code for MD5 routines **
126 ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
127 ** Created: 2/17/90 RLR **
128 ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
129 ***********************************************************************
133 * Edited 7 May 93 by CP to change the interface to match that
134 * of the MD5 routines in RSAREF. Due to this alteration, this
135 * code is "derived from the RSA Data Security, Inc. MD5 Message-
136 * Digest Algorithm". (See below.)
140 ***********************************************************************
141 ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
143 ** License to copy and use this software is granted provided that **
144 ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
145 ** Digest Algorithm" in all material mentioning or referencing this **
146 ** software or this function. **
148 ** License is also granted to make and use derivative works **
149 ** provided that such works are identified as "derived from the RSA **
150 ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
151 ** material mentioning or referencing the derived work. **
153 ** RSA Data Security, Inc. makes no representations concerning **
154 ** either the merchantability of this software or the suitability **
155 ** of this software for any particular purpose. It is provided "as **
156 ** is" without express or implied warranty of any kind. **
158 ** These notices must be retained in any copies of any part of this **
159 ** documentation and/or software. **
160 ***********************************************************************
166 ***********************************************************************
167 ** Message-digest routines: **
168 ** To form the message digest for a message M **
169 ** (1) Initialize a context buffer mdContext using MD5Init **
170 ** (2) Call MD5Update on mdContext and M **
171 ** (3) Call MD5Final on mdContext **
172 ** The message digest is now in the bugffer passed to MD5Final **
173 ***********************************************************************
176 static unsigned char PADDING
[64] = {
177 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
187 /* F, G, H and I are basic MD5 functions */
188 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
189 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
190 #define H(x, y, z) ((x) ^ (y) ^ (z))
191 #define I(x, y, z) ((y) ^ ((x) | (~z)))
193 /* ROTATE_LEFT rotates x left n bits */
194 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
196 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
197 /* Rotation is separate from addition to prevent recomputation */
198 #define FF(a, b, c, d, x, s, ac) \
199 {(a) += F ((b), (c), (d)) + (x) + (ULONG)(ac); \
200 (a) = ROTATE_LEFT ((a), (s)); \
203 #define GG(a, b, c, d, x, s, ac) \
204 {(a) += G ((b), (c), (d)) + (x) + (ULONG)(ac); \
205 (a) = ROTATE_LEFT ((a), (s)); \
208 #define HH(a, b, c, d, x, s, ac) \
209 {(a) += H ((b), (c), (d)) + (x) + (ULONG)(ac); \
210 (a) = ROTATE_LEFT ((a), (s)); \
213 #define II(a, b, c, d, x, s, ac) \
214 {(a) += I ((b), (c), (d)) + (x) + (ULONG)(ac); \
215 (a) = ROTATE_LEFT ((a), (s)); \
219 static void Transform(register ULONG
*buf
,register ULONG
*in
);
221 /* The routine MD5Init initializes the message-digest context
222 mdContext. All fields are set to zero.
224 void MD5Init ( MD5_CTX
*mdContext
)
226 mdContext
->i
[0] = mdContext
->i
[1] = (ULONG
)0;
228 /* Load magic initialization constants.
230 mdContext
->buf
[0] = (ULONG
)0x67452301L
;
231 mdContext
->buf
[1] = (ULONG
)0xefcdab89L
;
232 mdContext
->buf
[2] = (ULONG
)0x98badcfeL
;
233 mdContext
->buf
[3] = (ULONG
)0x10325476L
;
236 /* The routine MD5Update updates the message-digest context to
237 account for the presence of each of the characters inBuf[0..inLen-1]
238 in the message whose digest is being computed.
240 void MD5Update (MD5_CTX
*mdContext
, unsigned char *inBuf
,
247 /* compute number of bytes mod 64 */
248 mdi
= (int)((mdContext
->i
[0] >> 3) & 0x3F);
250 /* update number of bits */
251 if ((mdContext
->i
[0] + ((ULONG
)inLen
<< 3)) < mdContext
->i
[0])
253 mdContext
->i
[0] += ((ULONG
)inLen
<< 3);
254 mdContext
->i
[1] += ((ULONG
)inLen
>> 29);
258 /* add new character to buffer, increment mdi */
259 mdContext
->in
[mdi
++] = *inBuf
++;
261 /* transform if necessary */
264 for (i
= 0, ii
= 0; i
< 16; i
++, ii
+= 4)
265 in
[i
] = (((ULONG
)mdContext
->in
[ii
+3]) << 24) |
266 (((ULONG
)mdContext
->in
[ii
+2]) << 16) |
267 (((ULONG
)mdContext
->in
[ii
+1]) << 8) |
268 ((ULONG
)mdContext
->in
[ii
]);
269 Transform (mdContext
->buf
, in
);
275 /* The routine MD5Final terminates the message-digest computation and
276 ends with the desired message digest in mdContext->digest[0...15].
278 void MD5Final (unsigned char digest
[16], MD5_CTX
*mdContext
)
285 /* save number of bits */
286 in
[14] = mdContext
->i
[0];
287 in
[15] = mdContext
->i
[1];
289 /* compute number of bytes mod 64 */
290 mdi
= (int)((mdContext
->i
[0] >> 3) & 0x3F);
292 /* pad out to 56 mod 64 */
293 padLen
= (mdi
< 56) ? (56 - mdi
) : (120 - mdi
);
294 MD5Update (mdContext
, PADDING
, padLen
);
296 /* append length in bits and transform */
297 for (i
= 0, ii
= 0; i
< 14; i
++, ii
+= 4)
298 in
[i
] = (((ULONG
)mdContext
->in
[ii
+3]) << 24) |
299 (((ULONG
)mdContext
->in
[ii
+2]) << 16) |
300 (((ULONG
)mdContext
->in
[ii
+1]) << 8) |
301 ((ULONG
)mdContext
->in
[ii
]);
302 Transform (mdContext
->buf
, in
);
304 /* store buffer in digest */
305 for (i
= 0, ii
= 0; i
< 4; i
++, ii
+= 4)
307 digest
[ii
] = (unsigned char) (mdContext
->buf
[i
] & 0xFF);
308 digest
[ii
+1] = (unsigned char)((mdContext
->buf
[i
] >> 8) & 0xFF);
309 digest
[ii
+2] = (unsigned char)((mdContext
->buf
[i
] >> 16) & 0xFF);
310 digest
[ii
+3] = (unsigned char)((mdContext
->buf
[i
] >> 24) & 0xFF);
314 /* Basic MD5 step. Transforms buf based on in. Note that if the Mysterious
315 Constants are arranged backwards in little-endian order and decrypted with
316 the DES they produce OCCULT MESSAGES!
318 void Transform(register ULONG
*buf
,register ULONG
*in
)
320 register ULONG a
= buf
[0], b
= buf
[1], c
= buf
[2], d
= buf
[3];
327 FF ( a
, b
, c
, d
, in
[ 0], S11
, 0xD76AA478L
); /* 1 */
328 FF ( d
, a
, b
, c
, in
[ 1], S12
, 0xE8C7B756L
); /* 2 */
329 FF ( c
, d
, a
, b
, in
[ 2], S13
, 0x242070DBL
); /* 3 */
330 FF ( b
, c
, d
, a
, in
[ 3], S14
, 0xC1BDCEEEL
); /* 4 */
331 FF ( a
, b
, c
, d
, in
[ 4], S11
, 0xF57C0FAFL
); /* 5 */
332 FF ( d
, a
, b
, c
, in
[ 5], S12
, 0x4787C62AL
); /* 6 */
333 FF ( c
, d
, a
, b
, in
[ 6], S13
, 0xA8304613L
); /* 7 */
334 FF ( b
, c
, d
, a
, in
[ 7], S14
, 0xFD469501L
); /* 8 */
335 FF ( a
, b
, c
, d
, in
[ 8], S11
, 0x698098D8L
); /* 9 */
336 FF ( d
, a
, b
, c
, in
[ 9], S12
, 0x8B44F7AFL
); /* 10 */
337 FF ( c
, d
, a
, b
, in
[10], S13
, 0xFFFF5BB1L
); /* 11 */
338 FF ( b
, c
, d
, a
, in
[11], S14
, 0x895CD7BEL
); /* 12 */
339 FF ( a
, b
, c
, d
, in
[12], S11
, 0x6B901122L
); /* 13 */
340 FF ( d
, a
, b
, c
, in
[13], S12
, 0xFD987193L
); /* 14 */
341 FF ( c
, d
, a
, b
, in
[14], S13
, 0xA679438EL
); /* 15 */
342 FF ( b
, c
, d
, a
, in
[15], S14
, 0x49B40821L
); /* 16 */
349 GG ( a
, b
, c
, d
, in
[ 1], S21
, 0xF61E2562L
); /* 17 */
350 GG ( d
, a
, b
, c
, in
[ 6], S22
, 0xC040B340L
); /* 18 */
351 GG ( c
, d
, a
, b
, in
[11], S23
, 0x265E5A51L
); /* 19 */
352 GG ( b
, c
, d
, a
, in
[ 0], S24
, 0xE9B6C7AAL
); /* 20 */
353 GG ( a
, b
, c
, d
, in
[ 5], S21
, 0xD62F105DL
); /* 21 */
354 GG ( d
, a
, b
, c
, in
[10], S22
, 0x02441453L
); /* 22 */
355 GG ( c
, d
, a
, b
, in
[15], S23
, 0xD8A1E681L
); /* 23 */
356 GG ( b
, c
, d
, a
, in
[ 4], S24
, 0xE7D3FBC8L
); /* 24 */
357 GG ( a
, b
, c
, d
, in
[ 9], S21
, 0x21E1CDE6L
); /* 25 */
358 GG ( d
, a
, b
, c
, in
[14], S22
, 0xC33707D6L
); /* 26 */
359 GG ( c
, d
, a
, b
, in
[ 3], S23
, 0xF4D50D87L
); /* 27 */
360 GG ( b
, c
, d
, a
, in
[ 8], S24
, 0x455A14EDL
); /* 28 */
361 GG ( a
, b
, c
, d
, in
[13], S21
, 0xA9E3E905L
); /* 29 */
362 GG ( d
, a
, b
, c
, in
[ 2], S22
, 0xFCEFA3F8L
); /* 30 */
363 GG ( c
, d
, a
, b
, in
[ 7], S23
, 0x676F02D9L
); /* 31 */
364 GG ( b
, c
, d
, a
, in
[12], S24
, 0x8D2A4C8AL
); /* 32 */
371 HH ( a
, b
, c
, d
, in
[ 5], S31
, 0xFFFA3942L
); /* 33 */
372 HH ( d
, a
, b
, c
, in
[ 8], S32
, 0x8771F681L
); /* 34 */
373 HH ( c
, d
, a
, b
, in
[11], S33
, 0x6D9D6122L
); /* 35 */
374 HH ( b
, c
, d
, a
, in
[14], S34
, 0xFDE5380CL
); /* 36 */
375 HH ( a
, b
, c
, d
, in
[ 1], S31
, 0xA4BEEA44L
); /* 37 */
376 HH ( d
, a
, b
, c
, in
[ 4], S32
, 0x4BDECFA9L
); /* 38 */
377 HH ( c
, d
, a
, b
, in
[ 7], S33
, 0xF6BB4B60L
); /* 39 */
378 HH ( b
, c
, d
, a
, in
[10], S34
, 0xBEBFBC70L
); /* 40 */
379 HH ( a
, b
, c
, d
, in
[13], S31
, 0x289B7EC6L
); /* 41 */
380 HH ( d
, a
, b
, c
, in
[ 0], S32
, 0xEAA127FAL
); /* 42 */
381 HH ( c
, d
, a
, b
, in
[ 3], S33
, 0xD4EF3085L
); /* 43 */
382 HH ( b
, c
, d
, a
, in
[ 6], S34
, 0x04881D05L
); /* 44 */
383 HH ( a
, b
, c
, d
, in
[ 9], S31
, 0xD9D4D039L
); /* 45 */
384 HH ( d
, a
, b
, c
, in
[12], S32
, 0xE6DB99E5L
); /* 46 */
385 HH ( c
, d
, a
, b
, in
[15], S33
, 0x1FA27CF8L
); /* 47 */
386 HH ( b
, c
, d
, a
, in
[ 2], S34
, 0xC4AC5665L
); /* 48 */
393 II ( a
, b
, c
, d
, in
[ 0], S41
, 0xF4292244L
); /* 49 */
394 II ( d
, a
, b
, c
, in
[ 7], S42
, 0x432AFF97L
); /* 50 */
395 II ( c
, d
, a
, b
, in
[14], S43
, 0xAB9423A7L
); /* 51 */
396 II ( b
, c
, d
, a
, in
[ 5], S44
, 0xFC93A039L
); /* 52 */
397 II ( a
, b
, c
, d
, in
[12], S41
, 0x655B59C3L
); /* 53 */
398 II ( d
, a
, b
, c
, in
[ 3], S42
, 0x8F0CCC92L
); /* 54 */
399 II ( c
, d
, a
, b
, in
[10], S43
, 0xFFEFF47DL
); /* 55 */
400 II ( b
, c
, d
, a
, in
[ 1], S44
, 0x85845DD1L
); /* 56 */
401 II ( a
, b
, c
, d
, in
[ 8], S41
, 0x6FA87E4FL
); /* 57 */
402 II ( d
, a
, b
, c
, in
[15], S42
, 0xFE2CE6E0L
); /* 58 */
403 II ( c
, d
, a
, b
, in
[ 6], S43
, 0xA3014314L
); /* 59 */
404 II ( b
, c
, d
, a
, in
[13], S44
, 0x4E0811A1L
); /* 60 */
405 II ( a
, b
, c
, d
, in
[ 4], S41
, 0xF7537E82L
); /* 61 */
406 II ( d
, a
, b
, c
, in
[11], S42
, 0xBD3AF235L
); /* 62 */
407 II ( c
, d
, a
, b
, in
[ 2], S43
, 0x2AD7D2BBL
); /* 63 */
408 II ( b
, c
, d
, a
, in
[ 9], S44
, 0xEB86D391L
); /* 64 */
416 /*==[end md5.c]============================================================*/
419 const TEXT version
[] = "$VER: Version 42.3 (20.11.2015)\n";
420 const TEXT ver
[] = "$VER:";
422 static const char ERROR_HEADER
[] = "Version";
424 #define TEMPLATE "NAME/M,MD5SUM/S,VERSION/N,REVISION/N,FILE/S,FULL/S,RES/S,ARCH/S"
427 CONST_STRPTR
*arg_name
;
438 LONG mversion
, mrevision
;
457 parsedver
= { NULL
, 0, 0, 0, 0, -1, 0, NULL
, NULL
, NULL
, NULL
, NULL
, {0}};
459 #define PVF_MD5SUM (1 << 0)
460 #define PVF_NOVERSION (1 << 1)
463 int makeverstring(CONST_STRPTR name
);
465 void printverstring(void);
467 void freeverstring(void);
469 int makesysver(void);
471 int cmpargsparsed(void);
474 /**************************** support functions ************************/
476 /* Duplicate string, by given length or -1 for full length
479 STRPTR
dupstr(CONST_STRPTR buffer
, LONG len
)
486 len
= strlen(buffer
);
488 ret
= AllocVec(len
+ 1, MEMF_ANY
);
491 CopyMem((STRPTR
) buffer
, ret
, len
);
501 inline int myisspace(int c
)
503 return (c
== ' ' || c
== '\t');
507 /* Return a pointer to a string, stripped by all leading whitespace characters
511 STRPTR
skipwhites(CONST_STRPTR buffer
)
515 if (buffer
[0] == '\0' || !isspace(buffer
[0]))
517 return (STRPTR
) buffer
;
523 /* Return a pointer to a string, stripped by all leading space characters
527 STRPTR
skipspaces(CONST_STRPTR buffer
)
531 if (buffer
[0] == '\0' || buffer
[0] != ' ')
533 return (STRPTR
) buffer
;
539 /* Strip all whitespace-characters from the end of a string. Note that the
540 * buffer passed in will be modified!
543 void stripwhites(STRPTR buffer
)
545 int len
= strlen(buffer
);
549 if (!isspace(buffer
[len
-1]))
560 /* Searches for a given string in a file and stores up to *lenptr characters
561 * into the buffer beginning with the first character after the given string.
564 int findinfile(BPTR file
, CONST_STRPTR string
, STRPTR buffer
, int *lenptr
, unsigned char digest
[16])
566 int error
= RETURN_OK
;
567 int buflen
= *lenptr
, len
= 0, pos
, stringlen
;
573 tmp
= AllocMem(buflen
, MEMF_PUBLIC
);
579 stringlen
= strlen(string
);
588 while ((len
= Read(file
, &tmp
[len
], buflen
- len
)) > 0)
594 MD5Update(&md5ctx
, bufpos
, len
);
599 /* If we get here we're scanning the rest of the file for md5sum. - Piru */
604 while ((len
- pos
) >= stringlen
)
606 /* Compare the current buffer position with the supplied string. */
607 if (strncmp(&tmp
[pos
], string
, stringlen
) == 0)
609 /* It is equal! Now move the rest of the buffer to the top of
610 * the buffer and fill it up.
612 int findstrlen
= len
- pos
;
614 memcpy(buffer
, &tmp
[pos
+ stringlen
], findstrlen
);
616 len
= Read(file
, &buffer
[findstrlen
], buflen
- findstrlen
);
621 MD5Update(&md5ctx
, &buffer
[findstrlen
], len
);
624 *lenptr
= findstrlen
+ len
;
635 /* Move the rest of the buffer that could not be compared (because it
636 * is smaller than the string to compare) to the top of the buffer.
640 memmove(tmp
, &tmp
[len
- stringlen
], stringlen
);
644 /* If we're not md5summing, stop file scanning now. - Piru */
645 if (!args
.arg_md5sum
)
656 FreeMem(tmp
, buflen
);
665 memset(digest
, 0, 16);
666 MD5Final(digest
, &md5ctx
);
673 /*************************** parsing functions *************************/
675 /* Convert a date in the form DD.MM.YY or DD.MM.YYYY into a numerical
676 * value. Return FALSE, if buffer doesn't contain a valid date.
679 BOOL
makedatefromstring(CONST_STRPTR
*bufptr
)
681 CONST_STRPTR buffer
= *bufptr
;
683 CONST_STRPTR headerstart
, end
;
689 //if (isspace(buffer[0]))
692 headerstart
= buffer
;
694 buffer
= strchr(buffer
, '(');
700 end
= strchr(buffer
, ')');
705 len
= (int)(end
- buffer
);
706 newbuf
= dupstr(buffer
, len
);
711 for (i
= 0; i
< len
; i
++)
715 if (c
== '.' || c
== '/')
717 else if (!isalnum(c
))
725 D(Printf("date: \"%s\"\n", newbuf
));
727 dt
.dat_Format
= FORMAT_CDN
;
729 dt
.dat_StrDay
= NULL
;
730 dt
.dat_StrDate
= newbuf
;
731 dt
.dat_StrTime
= NULL
;
732 res
= StrToDate(&dt
);
735 dt
.dat_Format
= FORMAT_DOS
;
736 res
= StrToDate(&dt
);
739 //Printf("StrToDate failed!\n");
746 //parsedver.pv_days = dt.dat_Stamp.ds_Days;
748 parsedver
.pv_datestr
= AllocVec(buffer
- headerstart
+ LEN_DATSTRING
+ 2, MEMF_ANY
);
749 if (!parsedver
.pv_datestr
)
754 dt
.dat_Stamp
.ds_Minute
= 0;
755 dt
.dat_Stamp
.ds_Tick
= 0;
757 dt
.dat_StrDate
= parsedver
.pv_datestr
+ (buffer
- headerstart
);
758 dt
.dat_Format
= FORMAT_DEF
;
761 //Printf("DateToStr failed!\n");
765 CopyMem((STRPTR
) headerstart
, parsedver
.pv_datestr
, buffer
- headerstart
);
766 res
= strlen(parsedver
.pv_datestr
);
767 parsedver
.pv_datestr
[res
++] = ')';
768 parsedver
.pv_datestr
[res
] = '\0';
776 /* Check whether the given string contains a version in the form
777 * <version>.<revision> . If not return FALSE, otherwise fill in parsedver and
781 BOOL
makeversionfromstring(CONST_STRPTR
*bufptr
)
784 CONST_STRPTR buffer
= *bufptr
;
785 CONST_STRPTR verstart
, revstart
;
787 //Printf("makeversionfromstring: buffer \"%s\"\n", (LONG) buffer);
792 pos
= StrToLong((STRPTR
) buffer
, &ver
);
797 parsedver
.pv_version
= ver
;
798 parsedver
.pv_revision
= -1;
800 parsedver
.pv_vername
= dupstr(verstart
, pos
);
801 if (!parsedver
.pv_vername
)
810 buffer
= skipspaces(buffer
); /* NOTE: skipspaces, not skipwhites! */
818 pos
= StrToLong((STRPTR
) buffer
, &rev
);
825 parsedver
.pv_revision
= rev
;
827 /* calc the revision string len */
828 pos
= buffer
+ pos
- revstart
;
829 parsedver
.pv_revname
= dupstr(revstart
, pos
);
830 if (!parsedver
.pv_revname
)
835 *bufptr
= revstart
+ pos
;
840 static const char *arm_cpus
[] =
858 static const char *arm_fpus
[] =
869 void printverstring(void)
873 if (parsedver
.pv_flags
& PVF_MD5SUM
)
875 /* Endianess safe version */
876 Printf("%02lX%02lX%02lX%02lX"
877 "%02lX%02lX%02lX%02lX"
878 "%02lX%02lX%02lX%02lX"
879 "%02lX%02lX%02lX%02lX ",
880 parsedver
.pv_md5sum
[0],
881 parsedver
.pv_md5sum
[1],
882 parsedver
.pv_md5sum
[2],
883 parsedver
.pv_md5sum
[3],
884 parsedver
.pv_md5sum
[4],
885 parsedver
.pv_md5sum
[5],
886 parsedver
.pv_md5sum
[6],
887 parsedver
.pv_md5sum
[7],
888 parsedver
.pv_md5sum
[8],
889 parsedver
.pv_md5sum
[9],
890 parsedver
.pv_md5sum
[10],
891 parsedver
.pv_md5sum
[11],
892 parsedver
.pv_md5sum
[12],
893 parsedver
.pv_md5sum
[13],
894 parsedver
.pv_md5sum
[14],
895 parsedver
.pv_md5sum
[15]);
899 /* "01234567012345670123456701234567: " */
900 PutStr("<no md5sum available> ");
904 if (parsedver
.pv_flags
& PVF_NOVERSION
)
906 Printf("%s\n", (IPTR
) parsedver
.pv_name
);
912 /* If md5sum output was there, avoid linefeed to allow parsing the output - Piru */
915 parsedver
.pv_extralf
= " ";
918 Printf("%s%s%s%s%s%s%s\n",
919 (IPTR
) parsedver
.pv_name
, (IPTR
) (*parsedver
.pv_name
? " " : ""),
920 (IPTR
) parsedver
.pv_vername
, (IPTR
) parsedver
.pv_revname
,
921 (IPTR
) (parsedver
.pv_datestr
? (IPTR
)parsedver
.pv_datestr
: (IPTR
)""),
922 (IPTR
) (parsedver
.pv_extralf
? (IPTR
)parsedver
.pv_extralf
: (IPTR
)""),
923 (IPTR
) (parsedver
.pv_extrastr
? (IPTR
)parsedver
.pv_extrastr
: (IPTR
)""));
928 (IPTR
) parsedver
.pv_name
, (IPTR
) (*parsedver
.pv_name
? " " : ""),
929 (IPTR
) parsedver
.pv_vername
, (IPTR
) parsedver
.pv_revname
);
936 if (parsedver
.pv_arch
== EM_ARM
)
938 Printf("Architecture: ");
940 if (parsedver
.pv_arm_cpu
== (UBYTE
)-1)
941 Printf("ARM (unspecified)");
942 else if (parsedver
.pv_arm_cpu
<= ELF_CPU_ARMv7EM
)
943 Printf(arm_cpus
[parsedver
.pv_arm_cpu
]);
945 Printf("Unknown ARM (%d)", parsedver
.pv_arm_cpu
);
947 if (parsedver
.pv_arm_fpu
> 6)
948 Printf(" Unknown FPU (%d)", parsedver
.pv_arm_fpu
);
949 else if (parsedver
.pv_arm_fpu
)
950 Printf(" %s", arm_fpus
[parsedver
.pv_arm_fpu
]);
956 switch (parsedver
.pv_arch
)
959 /* No information available */
985 Printf("Architecture: %s\n", arch
);
993 int makedata(CONST_STRPTR buffer
, CONST_STRPTR ptr
, int pos
)
995 D(Printf("makedata: buffer \"%s\" ptr \"%s\"\n", buffer
, ptr
));
997 if (makeversionfromstring(&ptr
))
1003 /* Copy the program-name into a buffer. */
1004 parsedver
.pv_name
= dupstr(buffer
, pos
);
1005 if (!parsedver
.pv_name
)
1007 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1011 /* Now find the date */
1012 D(Printf("makedata: ptr #1: \"%s\"\n", ptr
));
1013 doskip
= strchr(ptr
, '(') ? TRUE
: FALSE
;
1014 (void) makedatefromstring(&ptr
);
1016 D(Printf("makedata: ptr #2: \"%s\"\n", ptr
));
1018 ptr
= skipspaces(ptr
); /* NOTE: not skipwhites! */
1019 for (endp
= ptr
; *endp
!= '\0' && *endp
!= '\r' && *endp
!= '\n'; endp
++)
1022 if (pos
&& ptr
[pos
-1] == '$')
1026 parsedver
.pv_extrastr
= dupstr(ptr
, pos
);
1027 if (!parsedver
.pv_extrastr
)
1029 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1033 D(Printf("makedata: Extra string: %s\n", parsedver
.pv_extrastr
));
1035 parsedver
.pv_extralf
= "\n";
1045 /* Retrieves version information from string. The data is stored in the
1046 * global struct parsedver.pv_
1050 int makedatafromstring(CONST_STRPTR buffer
)
1052 int error
= RETURN_OK
;
1056 while (buffer
[pos
] && buffer
[pos
] != '\r' && buffer
[pos
] != '\n')
1058 /* NOTE: Not isspace()! - Piru */
1059 if (myisspace(buffer
[pos
]) &&
1060 (add
= StrToLong((STRPTR
) buffer
+ pos
+ 1, &dummy
)) != -1)
1064 /* Found something, which looks like a version. Now check, if it
1068 D(Printf("makedatafromstring: buffer + %ld: \"%s\"\n", pos
, buffer
+ pos
));
1070 ptr
= buffer
+ pos
+ 1;
1072 if (makedata(buffer
, ptr
, pos
))
1080 if (!buffer
[pos
] || buffer
[pos
] == '\r' || buffer
[pos
] == '\n')
1084 /* use the whatever is after ver tag as name */
1085 for (endp
= buffer
; *endp
!= '\0' && *endp
!= '\r' && *endp
!= '\n'; endp
++)
1087 pos
= endp
- buffer
;
1089 parsedver
.pv_name
= dupstr(buffer
, pos
);
1090 if (!parsedver
.pv_name
)
1092 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1097 /* Strip any whitespaces from the tail of the program-name.
1099 if (parsedver
.pv_name
)
1101 stripwhites(parsedver
.pv_name
);
1108 /* Case-insensitive FindResident()
1111 struct Resident
*findresident(CONST_STRPTR name
)
1113 struct Resident
**rp
;
1114 struct Resident
*resident
;
1116 rp
= (struct Resident
**) SysBase
->ResModules
;
1118 while ((resident
= *rp
++))
1121 if (((LONG
)resident
) < 0)
1122 rp
= (struct Resident
**)((ULONG
)resident
& 0x7fffffff);
1124 if (((IPTR
)resident
) & 0x01)
1125 rp
= (struct Resident
**)((IPTR
)resident
& ~1);
1128 if (!Stricmp(resident
->rt_Name
, (STRPTR
) name
))
1137 /* Case-insensitive FindName()
1140 struct Node
*findname(struct List
*list
, CONST_STRPTR name
)
1144 ForeachNode(list
, node
)
1146 if (!Stricmp(node
->ln_Name
, (STRPTR
) name
))
1156 /* Retrieve information from resident modules. Returns 0 for success.
1159 int createresidentver(struct Resident
*MyResident
)
1161 STRPTR buffer
= NULL
;
1162 CONST_STRPTR name
= NULL
;
1166 BOOL foundver
= FALSE
;
1169 if (MyResident
->rt_IdString
)
1171 buffer
= skipwhites(MyResident
->rt_IdString
);
1172 D(Printf("createresidentver: buffer \"%s\"\n", buffer
));
1174 /* Locate version part */
1179 /* NOTE: Not isspace()! - Piru */
1180 if (myisspace(buffer
[pos
]) &&
1181 StrToLong(buffer
+ pos
+ 1, &dummy
) != -1)
1189 D(Printf("createresidentver: buffer: \"%s\"\n", buffer
));
1191 name
= MyResident
->rt_IdString
;
1192 len
= buffer
- name
;
1195 /* If could not find any version info, use the resident rt_Name */
1199 D(Printf("createresidentver: buffer: \"%s\"\n", buffer
));
1201 if ((!args
.arg_full
) || (!name
))
1203 name
= MyResident
->rt_Name
;
1204 len
= strlen(MyResident
->rt_Name
);
1207 tmpbuffer
= AllocVec(len
+ strlen(buffer
) + 1, MEMF_ANY
);
1210 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1213 CopyMem(name
, tmpbuffer
, len
);
1214 strcpy(tmpbuffer
+ len
, buffer
);
1215 D(Printf("createresidentver: tmpbuffer: \"%s\"\n", tmpbuffer
));
1217 error
= makedatafromstring(tmpbuffer
);
1225 /* Retrieve version information from library. Returns 0 for success.
1228 int createlibraryver(struct Library
*MyLibrary
)
1230 STRPTR buffer
, tmpbuffer
;
1231 int error
, foundver
= FALSE
, pos
;
1233 if (MyLibrary
->lib_IdString
)
1235 //Printf("createlibraryver: lib_IdString \"%s\"\n", (LONG) MyLibrary->lib_IdString);
1236 buffer
= skipwhites(MyLibrary
->lib_IdString
);
1238 //Printf("createlibraryver: buffer \"%s\"\n", (LONG) buffer);
1240 /* Find full 'ver.rev' version info
1247 /* NOTE: Not isspace()! - Piru */
1248 if (myisspace(buffer
[pos
]) &&
1249 (add
= StrToLong(buffer
+ pos
+ 1, &dummy
)) != -1 &&
1250 buffer
[pos
+ 1 + add
] == '.')
1260 /* If could not find 'ver.rev', find any numeric */
1268 /* NOTE: Not isspace()! - Piru */
1269 if (myisspace(buffer
[pos
]) &&
1270 StrToLong(buffer
+ pos
+ 1, &dummy
) != -1)
1282 /* If could not find any version info, use the resident rt_Name */
1286 error
= RETURN_WARN
;
1289 tmpbuffer
= AllocVec(strlen(MyLibrary
->lib_Node
.ln_Name
) + strlen(buffer
) + 1, MEMF_ANY
);
1292 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1296 strcpy(tmpbuffer
, MyLibrary
->lib_Node
.ln_Name
);
1297 strcat(tmpbuffer
, buffer
);
1298 //Printf("createlibraryver: tmpbuffer: \"%s\"\n", (LONG) tmpbuffer);
1299 pos
= makedatafromstring(tmpbuffer
);
1311 /* Create default strings
1314 int createdefvers(CONST_STRPTR name
)
1316 FreeVec(parsedver
.pv_revname
);
1317 FreeVec(parsedver
.pv_vername
);
1318 FreeVec(parsedver
.pv_name
);
1320 parsedver
.pv_name
= dupstr(name
, -1);
1321 parsedver
.pv_vername
= AllocVec(14, MEMF_ANY
);
1322 parsedver
.pv_revname
= AllocVec(15, MEMF_ANY
);
1324 if (parsedver
.pv_name
&&
1325 parsedver
.pv_vername
&&
1326 parsedver
.pv_revname
)
1328 __sprintf(parsedver
.pv_vername
, "%ld", (long)parsedver
.pv_version
);
1329 __sprintf(parsedver
.pv_revname
, ".%ld", (long)parsedver
.pv_revision
);
1338 /* Create version info from named resident
1341 int makeresidentver(CONST_STRPTR name
)
1343 struct Resident
*MyResident
;
1346 if ((MyResident
= findresident(name
)))
1348 error
= createresidentver(MyResident
);
1349 if (error
!= RETURN_OK
)
1351 /* get values from residenttag */
1352 parsedver
.pv_version
= MyResident
->rt_Version
;
1353 parsedver
.pv_revision
= -1;
1354 error
= createdefvers(MyResident
->rt_Name
);
1362 /* Create version info from named list node
1365 int makeexeclistver(struct List
*list
, CONST_STRPTR name
)
1367 struct Library
*MyLibrary
;
1369 #if defined(__AROSPLATFORM_SMP__)
1370 void *ExecLockBase
= OpenResource("execlock.resource");
1373 ObtainSystemLock(list
, SPINLOCK_MODE_READ
, LOCKF_FORBID
);
1379 MyLibrary
= (struct Library
*) findname(list
, name
);
1382 /* get values from library */
1383 ULONG ver
= MyLibrary
->lib_Version
;
1384 ULONG rev
= MyLibrary
->lib_Revision
;
1386 error
= createlibraryver(MyLibrary
);
1387 if (error
!= RETURN_OK
||
1388 parsedver
.pv_version
!= ver
||
1389 parsedver
.pv_revision
!= rev
)
1391 /* special case where createlibraryrev was successful, but
1392 * version or revision don't match.
1394 if (error
== RETURN_OK
)
1396 /* If there is extrastr, make sure there's linefeed, too.
1398 if (parsedver
.pv_extrastr
)
1400 parsedver
.pv_extralf
= "\n";
1404 /* get values from library */
1405 parsedver
.pv_version
= ver
;
1406 parsedver
.pv_revision
= rev
;
1408 error
= createdefvers(MyLibrary
->lib_Node
.ln_Name
);
1412 #if defined(__AROSPLATFORM_SMP__)
1414 ReleaseSystemLock(list
, LOCKF_FORBID
);
1425 /* Find resident from seglist, return NULL if none found
1428 struct Resident
*FindLibResident(BPTR Segment
)
1436 MySegment
= (IPTR
*) BADDR(Segment
);
1437 MyBuffer
= (UWORD
*) &MySegment
[1];
1438 EndBuffer
= (UWORD
*) &MySegment
[(MySegment
[-1] - sizeof(ULONG
) * 4) / sizeof(ULONG
)];
1440 while (MyBuffer
< EndBuffer
)
1442 struct Resident
*MyResident
;
1444 MyResident
= (struct Resident
*) MyBuffer
;
1445 if (MyResident
->rt_MatchWord
== RTC_MATCHWORD
&&
1446 MyResident
->rt_MatchTag
== MyResident
)
1454 Segment
=(BPTR
) MySegment
[0];
1457 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
1462 /* Find $VER: tag from seglist, return NULL if none found
1463 Returns dupstr()d string or NULL.
1466 STRPTR
FindSegmentVER(BPTR Segment
)
1471 CONST_STRPTR MyBuffer
;
1473 CONST_STRPTR EndBuffer
;
1474 CONST_STRPTR SegmentEnd
;
1476 MySegment
= BADDR(Segment
);
1477 MyBuffer
= (CONST_STRPTR
) (MySegment
+ sizeof(BPTR
));
1478 BufferLen
= *(ULONG
*)(MySegment
- sizeof(ULONG
));
1479 SegmentEnd
= (CONST_STRPTR
) (MySegment
+ (BufferLen
- sizeof(BPTR
)));
1480 EndBuffer
= SegmentEnd
- 5;
1482 while (MyBuffer
< EndBuffer
)
1484 if (MyBuffer
[0] == '$' &&
1485 MyBuffer
[1] == 'V' &&
1486 MyBuffer
[2] == 'E' &&
1487 MyBuffer
[3] == 'R' &&
1490 CONST_STRPTR EndPtr
;
1493 /* Required because some smartass could end his $VER: tag
1494 * without '\0' in the segment to save space. - Piru
1496 for (EndPtr
= MyBuffer
; EndPtr
< SegmentEnd
&& *EndPtr
; EndPtr
++)
1498 if (EndPtr
- MyBuffer
)
1500 return dupstr(MyBuffer
, EndPtr
- MyBuffer
);
1507 Segment
=*(BPTR
*)MySegment
;
1510 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
1515 /* Create version info from named device
1518 int makedevicever(CONST_STRPTR name
)
1520 struct DevProc
*MyDevProc
;
1523 MyDevProc
= GetDeviceProc((STRPTR
) name
, NULL
);
1526 if (MyDevProc
->dvp_DevNode
->dol_Type
== DLT_DEVICE
)
1530 SegList
= MyDevProc
->dvp_DevNode
->dol_misc
.dol_handler
.dol_SegList
;
1533 struct Resident
*MyResident
;
1535 MyResident
= FindLibResident(SegList
);
1538 error
= createresidentver(MyResident
);
1541 error
= RETURN_FAIL
;
1544 FreeDeviceProc(MyDevProc
);
1547 if (error
!= RETURN_OK
&& error
!= -1)
1549 Printf("Could not find version information for '%s'\n", name
);
1555 static int elf_read_block(BPTR file
, ULONG offset
, APTR buffer
, ULONG size
)
1557 if (Seek(file
, offset
, OFFSET_BEGINNING
) < 0)
1560 return Read(file
, buffer
, size
);
1563 static void *load_block(BPTR file
, ULONG offset
, ULONG size
)
1565 void *block
= AllocMem(size
, MEMF_ANY
);
1569 if (elf_read_block(file
, offset
, block
, size
) == size
)
1572 FreeMem(block
, size
);
1578 static inline UWORD
elf_read_word(UWORD data
, struct elfheader
*eh
)
1580 switch (eh
->ident
[EI_DATA
])
1583 return AROS_LE2WORD(data
);
1586 return AROS_BE2WORD(data
);
1593 static inline ULONG
elf_read_long(ULONG data
, struct elfheader
*eh
)
1595 switch (eh
->ident
[EI_DATA
])
1598 return AROS_LE2LONG(data
);
1601 return AROS_BE2LONG(data
);
1608 static ULONG
read_shnum(BPTR file
, struct elfheader
*eh
)
1610 ULONG shnum
= elf_read_word(eh
->shnum
, eh
);
1612 /* the ELF header only uses 16 bits to store the count of section headers,
1613 * so it can't handle more than 65535 headers. if the count is 0, and an
1614 * offset is defined, then the real count can be found in the first
1615 * section header (which always exists).
1617 * similarly, if the string table index is SHN_XINDEX, then the actual
1618 * index is found in the first section header also.
1620 * see the System V ABI 2001-04-24 draft for more details.
1625 ULONG shoff
= elf_read_long(eh
->shoff
, eh
);
1630 if (elf_read_block(file
, shoff
, &sh
, sizeof(sh
)) != sizeof(sh
))
1633 /* wider section header count is in the size field */
1634 shnum
= elf_read_long(sh
.size
, eh
);
1640 static BOOL
ARM_ParseAttrs(UBYTE
*data
, ULONG len
, struct elfheader
*eh
)
1642 struct attrs_section
*attrs
;
1644 if (data
[0] != ATTR_VERSION_CURRENT
)
1646 D(Printf("Unknown attributes version: 0x%02\n", data
[0]));
1650 attrs
= (void *)data
+ 1;
1653 ULONG attrs_size
= elf_read_long(attrs
->size
, eh
);
1655 if (!strcmp(attrs
->vendor
, "aeabi"))
1657 struct attrs_subsection
*aeabi_attrs
= (void *)attrs
->vendor
+ 6;
1658 ULONG aeabi_len
= attrs_size
- 10;
1660 D(Printf("Found aeabi attributes @ 0x%p (length %u)\n", aeabi_attrs
, aeabi_len
));
1662 while (aeabi_len
> 0)
1664 ULONG aeabi_attrs_size
= elf_read_long(aeabi_attrs
->size
, eh
);
1666 if (aeabi_attrs
->tag
== Tag_File
)
1668 UBYTE
*file_subsection
= (void *)aeabi_attrs
+ sizeof(struct attrs_subsection
);
1669 UBYTE file_len
= aeabi_attrs_size
- sizeof(struct attrs_subsection
);
1671 D(Printf("Found file-wide attributes @ 0x%p (length %u)\n", file_subsection
, file_len
));
1673 while (file_len
> 0)
1678 tag
= *file_subsection
++;
1683 D(Printf("Mailformed attribute tag %d (no data)\n", tag
));
1689 case Tag_CPU_raw_name
:
1691 case Tag_compatibility
:
1692 case Tag_also_compatible_with
:
1693 case Tag_conformance
:
1694 /* These two are NULL-terminated strings. Just skip. */
1698 if (*file_subsection
++ == 0)
1704 /* Read ULEB128 value */
1710 byte
= *file_subsection
++;
1713 val
|= (byte
& 0x7F) << shift
;
1724 D(Printf("ARM CPU architecture set to %d\n", val
));
1725 parsedver
.pv_arm_cpu
= val
;
1729 D(Printf("ARM FPU architecture set to %d\n", val
));
1730 parsedver
.pv_arm_fpu
= val
;
1737 aeabi_attrs
= (void *)aeabi_attrs
+ aeabi_attrs_size
;
1738 aeabi_len
-= aeabi_attrs_size
;
1743 attrs
= (void *)attrs
+ attrs_size
;
1749 static int arm_read_cpudata(BPTR file
, struct elfheader
*eh
)
1757 int_shnum
= read_shnum(file
, eh
);
1761 shoff
= elf_read_long(eh
->shoff
, eh
);
1762 shentsize
= elf_read_word(eh
->shentsize
, eh
);
1764 /* load section headers */
1765 if (!(sh
= load_block(file
, shoff
, int_shnum
* shentsize
)))
1768 for (i
= 0; i
< int_shnum
; i
++)
1770 if (sh
[i
].type
== SHT_ARM_ATTRIBUTES
)
1772 ULONG off
= elf_read_long(sh
[i
].offset
, eh
);
1773 ULONG len
= elf_read_long(sh
[i
].size
, eh
);
1774 void *data
= load_block(file
, off
, len
);
1776 D(Printf("ARM ATTRIBUTES section %d loaded at 0x%p\n", i
, data
));
1780 ARM_ParseAttrs(data
, len
, eh
);
1787 FreeMem(sh
, int_shnum
* shentsize
);
1793 /* Retrieve version information from file. Return 0 for success.
1795 #define BUFFERSIZE (16384 + 1)
1797 int makefilever(CONST_STRPTR name
)
1800 int error
; // = RETURN_OK;
1802 file
= Open((STRPTR
) name
, MODE_OLDFILE
);
1807 buffer
= AllocMem(BUFFERSIZE
, MEMF_PUBLIC
);
1810 int len
= BUFFERSIZE
- 1;
1814 ULONG len
= Read(file
, buffer
, sizeof(struct elfheader
));
1816 if (len
== sizeof(struct elfheader
))
1818 if (buffer
[0] == 0x7f && buffer
[1] == 'E' && buffer
[2] == 'L' && buffer
[3] == 'F')
1820 /* It's an ELF file, read machine ID */
1821 struct elfheader
*eh
= (struct elfheader
*)buffer
;
1823 parsedver
.pv_arch
= elf_read_word(eh
->machine
, eh
);
1824 if (parsedver
.pv_arch
== EM_ARM
)
1825 arm_read_cpudata(file
, eh
);
1830 if (buffer
[0] == 0 && buffer
[1] == 0 && buffer
[2] == 0x03 && buffer
[3] == 0xF3)
1832 /* It's AmigaOS hunk file. m68k obviously :) */
1833 parsedver
.pv_arch
= EM_68K
;
1836 /* Rewind the file */
1837 Seek(file
, 0, OFFSET_BEGINNING
);
1840 error
= findinfile(file
, ver
, buffer
, &len
, parsedver
.pv_md5sum
);
1841 if (error
== RETURN_OK
)
1843 parsedver
.pv_flags
|= PVF_MD5SUM
;
1850 startbuffer
= skipwhites(buffer
);
1852 //Printf("startbuffer \"%s\"\n", startbuffer);
1853 error
= makedatafromstring(startbuffer
);
1859 error
= RETURN_ERROR
;
1863 file
= LoadSeg((STRPTR
) name
);
1866 struct Resident
*MyResident
;
1868 MyResident
= FindLibResident(file
);
1870 (MyResident->rt_Type == NT_LIBRARY ||
1871 MyResident->rt_Type == NT_DEVICE)*/)
1873 error
= createresidentver(MyResident
);
1880 if (error
!= RETURN_OK
)
1882 /* If user didn't ask for md5sum or we could not calculate it.
1884 if (!args
.arg_md5sum
|| (!(parsedver
.pv_flags
& PVF_MD5SUM
)))
1886 Printf("Could not find version information for '%s'\n", (IPTR
) name
);
1893 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1896 FreeMem(buffer
, BUFFERSIZE
);
1900 error
= RETURN_FAIL
;
1901 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1909 LONG ioerr
= IoErr();
1911 if (ioerr
== ERROR_OBJECT_NOT_FOUND
||
1912 ioerr
== ERROR_OBJECT_WRONG_TYPE
)
1918 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1919 error
= RETURN_FAIL
;
1928 int makerescmdver(CONST_STRPTR name
)
1931 struct Segment
*segment
;
1935 segment
= FindSegment((STRPTR
) name
, NULL
, 0);
1938 segment
= FindSegment((STRPTR
) name
, NULL
, 1);
1943 if (segment
->seg_UC
== CMD_INTERNAL
||
1944 segment
->seg_UC
== CMD_DISABLED
)
1947 error
= makeresidentver("shell");
1952 STRPTR buffer
= FindSegmentVER(segment
->seg_Seg
);
1957 startbuffer
= skipwhites(buffer
);
1959 //Printf("startbuffer \"%s\"\n", (LONG) startbuffer);
1960 error
= makedatafromstring(startbuffer
);
1973 int setvervar(CONST_STRPTR name
, LONG ver
, LONG rev
)
1977 __sprintf(buf
, "%ld.%ld", (long) ver
, (long) rev
);
1979 return SetVar((STRPTR
) name
, buf
, -1, GVF_LOCAL_ONLY
| LV_VAR
) ? RETURN_OK
: -1;
1984 int makekickversion(void)
1986 parsedver
.pv_version
= SysBase
->LibNode
.lib_Version
;
1987 parsedver
.pv_revision
= SysBase
->SoftVer
;
1989 setvervar("Kickstart",
1990 parsedver
.pv_version
,
1991 parsedver
.pv_revision
);
1993 Printf("Kickstart %ld.%ld",
1994 (LONG
) parsedver
.pv_version
, (LONG
) parsedver
.pv_revision
);
2001 int makewbversion(void)
2004 struct Library
*VersionBase
;
2006 VersionBase
= OpenLibrary("version.library", 0);
2009 error
= makeexeclistver(&SysBase
->LibList
, "version.library");
2011 if (error
== RETURN_OK
)
2013 STRPTR newname
= dupstr("Workbench", -1);
2016 FreeVec(parsedver
.pv_name
);
2017 parsedver
.pv_name
= newname
;
2019 setvervar("Workbench", parsedver
.pv_version
, parsedver
.pv_revision
);
2022 CloseLibrary(VersionBase
);
2030 int makesysver(void)
2034 error
= makekickversion();
2035 if (error
== RETURN_OK
)
2037 error
= makewbversion();
2039 if (error
== RETURN_OK
)
2045 /* prevent silly errormsg if no version.library */
2047 error
= RETURN_WARN
;
2055 /* Determine, by which means to get the version-string.
2058 int makeverstring(CONST_STRPTR name
)
2060 int error
; // = RETURN_OK;
2061 BOOL volume
= name
[strlen(name
) - 1] == ':';
2062 CONST_STRPTR filepart
= FilePart(name
);
2066 if (!volume
&& !args
.arg_file
)
2070 error
= makeresidentver(filepart
);
2071 if (error
!= RETURN_OK
)
2076 error
= makeexeclistver(&SysBase
->LibList
, filepart
);
2077 if (error
!= RETURN_OK
)
2080 ULONG namelen
= strlen(filepart
);
2082 /* 12 is "MOSSYS:LIBS/" */
2083 if ((namebuf
= AllocVec(12 + namelen
+ 4 + 1, MEMF_PUBLIC
)))
2085 strcpy(namebuf
, "LIBS:");
2086 strcat(namebuf
, filepart
);
2087 error
= makefilever(namebuf
);
2091 if (error
!= RETURN_OK
)
2093 error
= makeexeclistver(&SysBase
->DeviceList
, filepart
);
2094 if (error
!= RETURN_OK
)
2096 strcpy(namebuf
, "DEVS:");
2097 strcat(namebuf
, filepart
);
2098 error
= makefilever(namebuf
);
2108 if (!args
.arg_res
&& error
== -1)
2112 error
= makedevicever(name
);
2118 error
= makefilever(name
);
2123 if (!args
.arg_file
&& error
== -1)
2125 error
= makerescmdver(name
);
2130 /* If user asked for md5sum, and we could calculate it, don't print error
2131 * but the md5sum + file.
2133 if (args
.arg_md5sum
&& (parsedver
.pv_flags
& PVF_MD5SUM
))
2135 parsedver
.pv_name
= dupstr(name
, -1);
2136 parsedver
.pv_flags
|= PVF_NOVERSION
;
2143 PrintFault(ERROR_OBJECT_NOT_FOUND
, (STRPTR
) ERROR_HEADER
);
2144 error
= RETURN_FAIL
;
2152 void freeverstring(void)
2154 parsedver
.pv_flags
= 0;
2155 parsedver
.pv_version
= 0;
2156 parsedver
.pv_revision
= 0;
2158 FreeVec(parsedver
.pv_extrastr
);
2159 parsedver
.pv_extrastr
= NULL
;
2160 parsedver
.pv_extralf
= NULL
;
2161 FreeVec(parsedver
.pv_datestr
);
2162 parsedver
.pv_datestr
= NULL
;
2163 FreeVec(parsedver
.pv_revname
);
2164 parsedver
.pv_revname
= NULL
;
2165 FreeVec(parsedver
.pv_vername
);
2166 parsedver
.pv_vername
= NULL
;
2167 FreeVec(parsedver
.pv_name
);
2168 parsedver
.pv_name
= NULL
;
2171 /* Compare the version given as argument with the version from the object.
2172 * Return RETURN_WARN, if args-v>object-v, otherwise return RETURN_OK.
2175 int cmpargsparsed(void)
2177 if (args
.arg_version
)
2179 if (*(args
.arg_version
) > parsedver
.pv_version
)
2183 else if (*(args
.arg_version
) == parsedver
.pv_version
&& args
.arg_revision
)
2185 if (*(args
.arg_revision
) > parsedver
.pv_revision
)
2191 else if (args
.arg_revision
)
2193 if (*(args
.arg_revision
) > parsedver
.pv_revision
)
2201 /******************************* main program ****************************/
2203 int __nocommandline
;
2207 LONG error
= RETURN_FAIL
;
2211 rda
= ReadArgs(TEMPLATE
, (IPTR
*) &args
, NULL
);
2214 if (!args
.arg_name
|| !*args
.arg_name
)
2216 /* No args, make system version */
2217 error
= makesysver();
2218 if (error
== RETURN_OK
)
2221 if (parsedver
.pv_flags
& PVF_NOVERSION
)
2223 error
= RETURN_FAIL
;
2225 if (error
== RETURN_OK
)
2227 error
= cmpargsparsed();
2239 * version file ver rev
2241 if (!args
.arg_version
&& !args
.arg_revision
)
2244 while (args
.arg_name
[narg
]) { narg
++; }
2245 if (narg
== 2 || narg
== 3)
2247 if (StrToLong(args
.arg_name
[1], &mversion
) > 0)
2249 args
.arg_version
= &mversion
;
2250 args
.arg_name
[1] = args
.arg_name
[2];
2253 args
.arg_name
[2] = NULL
;
2257 if (StrToLong(args
.arg_name
[1], &mrevision
) > 0)
2259 args
.arg_revision
= &mrevision
;
2260 args
.arg_name
[1] = NULL
;
2267 multifile
= args
.arg_name
[1] != NULL
;
2269 for (name
= args
.arg_name
; *name
; name
++)
2271 error
= makeverstring(*name
);
2272 if (error
== RETURN_OK
)
2278 /* Single args, do compare stuff also */
2279 if (parsedver
.pv_flags
& PVF_NOVERSION
)
2281 error
= RETURN_FAIL
;
2283 if (error
== RETURN_OK
)
2285 error
= cmpargsparsed();
2298 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
2299 error
= RETURN_FAIL
;