1 #include "c.h"
2 #include "strutils.h"
3
4 #ifdef HAVE_LIBBLKID
5 # include <blkid.h>
6 #endif
7
8 #include "fdiskP.h"
9
10 struct fdisk_wipe {
11 struct list_head wipes;
12 uint64_t start; /* sectors */
13 uint64_t size; /* sectors */
14 };
15
16 static struct fdisk_wipe *fdisk_get_wipe_area(
17 struct fdisk_context *cxt,
18 uint64_t start,
19 uint64_t size)
20 {
21 struct list_head *p;
22
23 if (cxt == NULL || list_empty(&cxt->wipes))
24 return NULL;
25
26 list_for_each(p, &cxt->wipes) {
27 struct fdisk_wipe *wp = list_entry(p, struct fdisk_wipe, wipes);
28 if (wp->start == start && wp->size == size)
29 return wp;
30 }
31 return NULL;
32 }
33
34 void fdisk_free_wipe_areas(struct fdisk_context *cxt)
35 {
36 while (!list_empty(&cxt->wipes)) {
37 struct fdisk_wipe *wp = list_entry(cxt->wipes.next,
38 struct fdisk_wipe, wipes);
39 DBG(WIPE, ul_debugobj(wp, "free [start=%ju, size=%ju]",
40 (uintmax_t) wp->start, (uintmax_t) wp->size));
41 list_del(&wp->wipes);
42 free(wp);
43 }
44 }
45
46 int fdisk_has_wipe_area(struct fdisk_context *cxt,
47 uint64_t start,
48 uint64_t size)
49 {
50 return fdisk_get_wipe_area(cxt, start, size) != NULL;
51 }
52
53 /* Add/remove new wiping area
54 *
55 * Returns: <0 on error, or old area setting (1: enabled, 0: disabled)
56 */
57 int fdisk_set_wipe_area(struct fdisk_context *cxt,
58 uint64_t start,
59 uint64_t size,
60 int enable)
61 {
62 struct fdisk_wipe *wp;
63
64 if (FDISK_IS_UNDEF(start) || FDISK_IS_UNDEF(size))
65 return -EINVAL;
66
67 wp = fdisk_get_wipe_area(cxt, start, size);
68
69 /* disable */
70 if (!enable) {
71 if (wp) {
72 DBG(WIPE, ul_debugobj(wp, "disable [start=%ju, size=%ju]",
73 (uintmax_t) start, (uintmax_t) size));
74 list_del(&wp->wipes);
75 free(wp);
76 return 1;
77 }
78 return 0;
79 }
80
81 /* enable */
82 if (wp)
83 return 1; /* already enabled */
84
85 wp = calloc(1, sizeof(*wp));
86 if (!wp)
87 return -ENOMEM;
88
89 DBG(WIPE, ul_debugobj(wp, "enable [start=%ju, size=%ju]",
90 (uintmax_t) start, (uintmax_t) size));
91
92 INIT_LIST_HEAD(&wp->wipes);
93 wp->start = start;
94 wp->size = size;
95 list_add_tail(&wp->wipes, &cxt->wipes);
96
97 return 0;
98 }
99
100 #ifndef HAVE_LIBBLKID
101 int fdisk_do_wipe(struct fdisk_context *cxt __attribute__((__unused__)))
102 {
103 return 0;
104 }
105 #else
106 int fdisk_do_wipe(struct fdisk_context *cxt)
107 {
108 struct list_head *p;
109 blkid_probe pr;
110 int rc;
111
112 assert(cxt);
113 assert(cxt->dev_fd >= 0);
114
115 if (list_empty(&cxt->wipes))
116 return 0;
117
118 pr = blkid_new_probe();
119 if (!pr)
120 return -ENOMEM;
121
122 list_for_each(p, &cxt->wipes) {
123 struct fdisk_wipe *wp = list_entry(p, struct fdisk_wipe, wipes);
124 blkid_loff_t start = (blkid_loff_t) wp->start * cxt->sector_size,
125 size = (blkid_loff_t) wp->size * cxt->sector_size;
126
127 DBG(WIPE, ul_debugobj(wp, "initialize libblkid prober [start=%ju, size=%ju]",
128 (uintmax_t) start, (uintmax_t) size));
129
130 rc = blkid_probe_set_device(pr, cxt->dev_fd, start, size);
131 if (rc) {
132 DBG(WIPE, ul_debugobj(wp, "blkid_probe_set_device() failed [rc=%d]", rc));
133 return rc;
134 }
135
136 blkid_probe_enable_superblocks(pr, 1);
137 blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC |
138 BLKID_SUBLKS_BADCSUM);
139 blkid_probe_enable_partitions(pr, 1);
140 blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC |
141 BLKID_PARTS_FORCE_GPT);
142
143 while (blkid_do_probe(pr) == 0) {
144 DBG(WIPE, ul_debugobj(wp, " wiping..."));
145 blkid_do_wipe(pr, FALSE);
146 }
147 }
148
149 blkid_free_probe(pr);
150 return 0;
151 }
152 #endif
153
154
155 /*
156 * Please don't call this function if there is already a PT.
157 *
158 * Returns: 0 if nothing found, < 0 on error, 1 if found a signature
159 */
160 #ifndef HAVE_LIBBLKID
161 int fdisk_check_collisions(struct fdisk_context *cxt __attribute__((__unused__)))
162 {
163 return 0;
164 }
165 #else
166 int fdisk_check_collisions(struct fdisk_context *cxt)
167 {
168 int rc = 0;
169 blkid_probe pr;
170
171 assert(cxt);
172 assert(cxt->dev_fd >= 0);
173
174 DBG(WIPE, ul_debugobj(cxt, "wipe check: initialize libblkid prober"));
175
176 pr = blkid_new_probe();
177 if (!pr)
178 return -ENOMEM;
179 rc = blkid_probe_set_device(pr, cxt->dev_fd, 0, 0);
180 if (rc)
181 return rc;
182
183 cxt->pt_collision = 0;
184 free(cxt->collision);
185 cxt->collision = NULL;
186
187 blkid_probe_enable_superblocks(pr, 1);
188 blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE |
189 BLKID_SUBLKS_BADCSUM);
190 blkid_probe_enable_partitions(pr, 1);
191 blkid_probe_set_partitions_flags(pr, BLKID_PARTS_FORCE_GPT);
192
193 /* we care about the first found FS/raid, so don't call blkid_do_probe()
194 * in loop or don't use blkid_do_fullprobe() ... */
195 rc = blkid_do_probe(pr);
196 if (rc == 0) {
197 const char *name = NULL;
198
199 if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0)
200 cxt->collision = strdup(name);
201 else if (blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) {
202 cxt->collision = strdup(name);
203 cxt->pt_collision = 1;
204 }
205
206 if (name && !cxt->collision)
207 rc = -ENOMEM;
208 }
209
210 blkid_free_probe(pr);
211 return rc < 0 ? rc : cxt->collision ? 1 : 0;
212 }
213 #endif