1#include <errno.h>
2#include <fcntl.h>
3#include <stdio.h>
4#include <unistd.h>
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <md5.h>
8
9/* When this was written, bionic's md5.h did not define this. */
10#ifndef MD5_DIGEST_LENGTH
11#define MD5_DIGEST_LENGTH 16
12#endif
13
14static int usage()
15{
16    fprintf(stderr,"md5 file ...\n");
17    return -1;
18}
19
20static int do_md5(const char *path)
21{
22    unsigned int i;
23    int fd;
24    MD5_CTX md5_ctx;
25    unsigned char md5[MD5_DIGEST_LENGTH];
26
27    fd = open(path, O_RDONLY);
28    if (fd < 0) {
29        fprintf(stderr,"could not open %s, %s\n", path, strerror(errno));
30        return -1;
31    }
32
33    /* Note that bionic's MD5_* functions return void. */
34    MD5_Init(&md5_ctx);
35
36    while (1) {
37        char buf[4096];
38        ssize_t rlen;
39        rlen = read(fd, buf, sizeof(buf));
40        if (rlen == 0)
41            break;
42        else if (rlen < 0) {
43            (void)close(fd);
44            fprintf(stderr,"could not read %s, %s\n", path, strerror(errno));
45            return -1;
46        }
47        MD5_Update(&md5_ctx, buf, rlen);
48    }
49    if (close(fd)) {
50        fprintf(stderr,"could not close %s, %s\n", path, strerror(errno));
51        return -1;
52    }
53
54    MD5_Final(md5, &md5_ctx);
55
56    for (i = 0; i < (int)sizeof(md5); i++)
57        printf("%02x", md5[i]);
58    printf("  %s\n", path);
59
60    return 0;
61}
62
63int md5_main(int argc, char *argv[])
64{
65    int i, ret = 0;
66
67    if (argc < 2)
68        return usage();
69
70    /* loop over the file args */
71    for (i = 1; i < argc; i++) {
72        if (do_md5(argv[i]))
73            ret = 1;
74    }
75
76    return ret;
77}
78