summaryrefslogtreecommitdiffstats
path: root/rootdev.c
blob: c3dc175d8fc99221c44f1231f5996b9bffe37d24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/* Taken from util-linux source. GPLv2.
 * Emits the current rootfs device.
 * Works by searching /dev recursively for a BLK device with the same device
 * number as '/'.
 */

#include <stdio.h>
#include <err.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>


static int
find_dev_recursive(char *dirnamebuf, int number, int deviceOnly) {
        DIR *dp;
        struct dirent *dir;
        struct stat s;
        int dirnamelen = 0;

        if ((dp = opendir(dirnamebuf)) == NULL)
                err(1, "can't read directory %s", dirnamebuf);
        dirnamelen = strlen(dirnamebuf);
        while ((dir = readdir(dp)) != NULL) {
                if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
                        continue;
                if (dirnamelen + 1 + strlen(dir->d_name) > PATH_MAX)
                        continue;
                dirnamebuf[dirnamelen] = '/';
                strcpy(dirnamebuf+dirnamelen+1, dir->d_name);
                if (lstat(dirnamebuf, &s) < 0)
                        continue;
                if ((s.st_mode & S_IFMT) == S_IFBLK && s.st_rdev == number){
                        if (deviceOnly) {
                                int len = strlen(dirnamebuf);
                                char c = 0;
                                do {
                                        c = dirnamebuf[len-1];
                                        --len;
                                }while(c > 0 && c < 9 && len > 0);
                                /* arm has "p" for partition */
                                if (dirnamebuf[len-1] == 'p')
                                        --len;
                                dirnamebuf[len]='\0';
                        }
                        return 1;
                }
                if ((s.st_mode & S_IFMT) == S_IFDIR &&
                    find_dev_recursive(dirnamebuf, number, deviceOnly))
                        return 1;
        }
        dirnamebuf[dirnamelen] = 0;
        closedir(dp);
        return 0;
}

void usage(){
   printf ("rootdev \n\t-d (for device only)\n");
}

int main(int argc, char *argv[]) {
        struct stat s;
        char *file = "/";
        static char name[PATH_MAX+1];
        int deviceOnly=0;
        int c;
        extern char *optarg;
        extern int optind, optopt;
        while ((c = getopt(argc, argv, "hd")) != -1) {
                switch(c) {
                case 'd':
                        deviceOnly=1;
                        break;
                case 'h':
                default:
                        usage();
                        return 1;
                }
        }
        if (argc - optind >= 1)
                file = argv[optind];

        if (stat(file, &s) < 0)
                err(1, "unable to stat %s", file);

        if (!s.st_dev)
                err(1, "unknown device number 0");

        strcpy(name, "/dev");

        if (!find_dev_recursive(name, s.st_dev, deviceOnly)) {
                fprintf(stderr, "unable to find match\n");
                return 1;
        }

        printf("%s\n", name);

        return 0;
}