chiark / gitweb /
volume_id: provide library
[elogind.git] / extras / volume_id / libvolume_id / ocfs.c
1 /*
2  * volume_id - reads filesystem label and uuid
3  *
4  * Copyright (C) 2004 Andre Masella <andre@masella.no-ip.org>
5  * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
6  *
7  *      This program is free software; you can redistribute it and/or modify it
8  *      under the terms of the GNU General Public License as published by the
9  *      Free Software Foundation version 2 of the License.
10  */
11
12 #ifndef _GNU_SOURCE
13 #define _GNU_SOURCE 1
14 #endif
15
16 #ifdef HAVE_CONFIG_H
17 #  include <config.h>
18 #endif
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <ctype.h>
26
27 #include "libvolume_id.h"
28 #include "logging.h"
29 #include "util.h"
30
31
32 struct ocfs1_super_block_header {
33         uint32_t        minor_version;
34         uint32_t        major_version;
35         uint8_t         signature[128];
36         uint8_t         mount_point[128];
37         uint64_t        serial_num;
38         uint64_t        device_size;
39         uint64_t        start_off;
40         uint64_t        bitmap_off;
41         uint64_t        publ_off;
42         uint64_t        vote_off;
43         uint64_t        root_bitmap_off;
44         uint64_t        data_start_off;
45         uint64_t        root_bitmap_size;
46         uint64_t        root_off;
47         uint64_t        root_size;
48         uint64_t        cluster_size;
49         uint64_t        num_nodes;
50         uint64_t        num_clusters;
51         uint64_t        dir_node_size;
52         uint64_t        file_node_size;
53         uint64_t        internal_off;
54         uint64_t        node_cfg_off;
55         uint64_t        node_cfg_size;
56         uint64_t        new_cfg_off;
57         uint32_t        prot_bits;
58         int32_t         excl_mount;
59 } PACKED;
60
61 struct ocfs1_super_block_label {
62         struct ocfs1_disk_lock {
63                 uint32_t        curr_master;
64                 uint8_t         file_lock;
65                 uint8_t         compat_pad[3];
66                 uint64_t        last_write_time;
67                 uint64_t        last_read_time;
68                 uint32_t        writer_node_num;
69                 uint32_t        reader_node_num;
70                 uint64_t        oin_node_map;
71                 uint64_t        dlock_seq_num;
72         } PACKED disk_lock;
73         uint8_t         label[64];
74         uint16_t        label_len;
75         uint8_t         vol_id[16];
76         uint16_t        vol_id_len;
77         uint8_t         cluster_name[64];
78         uint16_t        cluster_name_len;
79 } PACKED;
80
81 struct ocfs2_super_block {
82         uint8_t         i_signature[8];
83         uint32_t        i_generation;
84         int16_t         i_suballoc_slot;
85         uint16_t        i_suballoc_bit;
86         uint32_t        i_reserved0;
87         uint32_t        i_clusters;
88         uint32_t        i_uid;
89         uint32_t        i_gid;
90         uint64_t        i_size;
91         uint16_t        i_mode;
92         uint16_t        i_links_count;
93         uint32_t        i_flags;
94         uint64_t        i_atime;
95         uint64_t        i_ctime;
96         uint64_t        i_mtime;
97         uint64_t        i_dtime;
98         uint64_t        i_blkno;
99         uint64_t        i_last_eb_blk;
100         uint32_t        i_fs_generation;
101         uint32_t        i_atime_nsec;
102         uint32_t        i_ctime_nsec;
103         uint32_t        i_mtime_nsec;
104         uint64_t        i_reserved1[9];
105         uint64_t        i_pad1;
106         uint16_t        s_major_rev_level;
107         uint16_t        s_minor_rev_level;
108         uint16_t        s_mnt_count;
109         int16_t         s_max_mnt_count;
110         uint16_t        s_state;
111         uint16_t        s_errors;
112         uint32_t        s_checkinterval;
113         uint64_t        s_lastcheck;
114         uint32_t        s_creator_os;
115         uint32_t        s_feature_compat;
116         uint32_t        s_feature_incompat;
117         uint32_t        s_feature_ro_compat;
118         uint64_t        s_root_blkno;
119         uint64_t        s_system_dir_blkno;
120         uint32_t        s_blocksize_bits;
121         uint32_t        s_clustersize_bits;
122         uint16_t        s_max_slots;
123         uint16_t        s_reserved1;
124         uint32_t        s_reserved2;
125         uint64_t        s_first_cluster_group;
126         uint8_t         s_label[64];
127         uint8_t         s_uuid[16];
128 } PACKED;
129
130 int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off)
131 {
132         const uint8_t *buf;
133         struct ocfs1_super_block_header *osh;
134         struct ocfs1_super_block_label *osl;
135
136         buf = volume_id_get_buffer(id, off, 0x200);
137         if (buf == NULL)
138                 return -1;
139
140         osh = (struct ocfs1_super_block_header *) buf;
141         if (memcmp(osh->signature, "OracleCFS", 9) != 0)
142                 return -1;
143         snprintf(id->type_version, sizeof(id->type_version)-1,
144                  "%u.%u", osh->major_version, osh->minor_version);
145
146         dbg("found OracleCFS signature, now reading label");
147         buf = volume_id_get_buffer(id, off + 0x200, 0x200);
148         if (buf == NULL)
149                 return -1;
150
151         osl = (struct ocfs1_super_block_label *) buf;
152         volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
153         if (osl->label_len <= 64) {
154                 volume_id_set_label_raw(id, osl->label, 64);
155                 volume_id_set_label_string(id, osl->label, 64);
156         }
157         if (osl->vol_id_len == 16)
158                 volume_id_set_uuid(id, osl->vol_id, UUID_DCE);
159         id->type = "ocfs";
160         return 0;
161 }
162
163 #define OCFS2_MAX_BLOCKSIZE             0x1000
164 #define OCFS2_SUPER_BLOCK_BLKNO         2
165
166 int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off)
167 {
168         const uint8_t *buf;
169         struct ocfs2_super_block *os;
170         size_t blksize;
171
172         dbg("probing at offset 0x%llx", (unsigned long long) off);
173
174         for (blksize = 0x200; blksize <= OCFS2_MAX_BLOCKSIZE; blksize <<= 1) {
175                 buf = volume_id_get_buffer(id, off + OCFS2_SUPER_BLOCK_BLKNO * blksize, 0x200);
176                 if (buf == NULL)
177                         return -1;
178
179                 os = (struct ocfs2_super_block *) buf;
180                 if (memcmp(os->i_signature, "OCFSV2", 6) != 0)
181                         continue;
182
183                 volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
184                 volume_id_set_label_raw(id, os->s_label, 64);
185                 volume_id_set_label_string(id, os->s_label, 64);
186                 volume_id_set_uuid(id, os->s_uuid, UUID_DCE);
187                 snprintf(id->type_version, sizeof(id->type_version)-1,
188                          "%u.%u", os->s_major_rev_level, os->s_minor_rev_level);
189                 id->type = "ocfs2";
190                 return 0;
191         }
192         return -1;
193 }