1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <fs_dm.h>
17 #include "securec.h"
18 #include "beget_ext.h"
19 #include <linux/dm-ioctl.h>
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/sysmacros.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include "ueventd.h"
27 #include "ueventd_socket.h"
28 #include <limits.h>
29
30 #ifdef __cplusplus
31 #if __cplusplus
32 extern "C" {
33 #endif
34 #endif
35
36 #define DM_VERSION0 (4)
37 #define DM_VERSION1 (0)
38 #define DM_VERSION2 (0)
39 #define DM_ALIGN_MASK (7)
40 #define DM_ALIGN(x) (((x) + DM_ALIGN_MASK) & ~DM_ALIGN_MASK)
41 #define DEVICE_MAPPER_PATH "/dev/mapper/control"
42 #define DM_DEVICE_PATH_PREFIX "/dev/block/dm-"
43
44 #define FS_DM_RETURN_ERR_IF_NULL(__ptr) \
45 do { \
46 if ((__ptr) == NULL) { \
47 BEGET_LOGE("error, %s is NULL\n", #__ptr); \
48 return -1; \
49 } \
50 } while (0)
51
InitDmIo(struct dm_ioctl * io,const char * devName)52 static int InitDmIo(struct dm_ioctl *io, const char *devName)
53 {
54 errno_t err;
55
56 err = memset_s(io, sizeof(*io), 0, sizeof(*io));
57 if (err != EOK) {
58 BEGET_LOGE("memset io, ret=%d", err);
59 return -1;
60 }
61
62 io->version[0] = DM_VERSION0;
63 io->version[1] = DM_VERSION1;
64 io->version[2] = DM_VERSION2;
65 io->data_size = sizeof(*io);
66 io->data_start = 0;
67
68 if (devName == NULL) {
69 return 0;
70 }
71
72 err = strcpy_s(io->name, sizeof(io->name), devName);
73 if (err != EOK) {
74 BEGET_LOGE("cp devName, ret=%d", err);
75 return -1;
76 }
77
78 return 0;
79 }
80
CreateDmDevice(int fd,const char * devName)81 static int CreateDmDevice(int fd, const char *devName)
82 {
83 int rc;
84 struct dm_ioctl io;
85
86 rc = InitDmIo(&io, devName);
87 if (rc != 0) {
88 return rc;
89 }
90
91 rc = ioctl(fd, DM_DEV_CREATE, &io);
92 if (rc != 0) {
93 BEGET_LOGE("error, DM_DEV_CREATE failed for %s, ret=%d", devName, rc);
94 return rc;
95 }
96
97 return 0;
98 }
99
LoadDmDeviceTable(int fd,const char * devName,DmVerityTarget * target,bool needDmVerity)100 static int LoadDmDeviceTable(int fd, const char *devName,
101 DmVerityTarget *target, bool needDmVerity)
102 {
103 int rc;
104 errno_t err;
105 char *parasBuf = NULL;
106 size_t parasTotalSize;
107 struct dm_ioctl *io = NULL;
108 struct dm_target_spec *ts = NULL;
109 char *paras = NULL;
110
111 FS_DM_RETURN_ERR_IF_NULL(target);
112 FS_DM_RETURN_ERR_IF_NULL(target->paras);
113
114 parasTotalSize = DM_ALIGN(sizeof(*io) + sizeof(*ts) + target->paras_len + 1);
115 parasBuf = calloc(1, parasTotalSize);
116 if (parasBuf == NULL) {
117 BEGET_LOGE("error, calloc dm table fail");
118 return -1;
119 }
120
121 io = (struct dm_ioctl *)parasBuf;
122 ts = (struct dm_target_spec *)(parasBuf + sizeof(*io));
123 paras = parasBuf + sizeof(*io) + sizeof((*ts));
124
125 do {
126 rc = InitDmIo(io, devName);
127 if (rc != 0) {
128 BEGET_LOGE("error 0x%x, init dm io", rc);
129 break;
130 }
131
132 io->data_size = parasTotalSize;
133 io->data_start = sizeof(*io);
134 io->target_count = 1;
135 io->flags |= DM_READONLY_FLAG;
136
137 ts->status = 0;
138 ts->sector_start = target->start;
139 ts->length = target->length;
140 char *targetType = needDmVerity ? "verity" : "linear";
141 err = strcpy_s(ts->target_type, sizeof(ts->target_type), targetType);
142 if (err != EOK) {
143 rc = -1;
144 BEGET_LOGE("error 0x%x, cp target type", err);
145 break;
146 }
147
148 err = strcpy_s(paras, target->paras_len + 1, target->paras);
149 if (err != EOK) {
150 rc = -1;
151 BEGET_LOGE("error 0x%x, cp target paras", err);
152 break;
153 }
154
155 ts->next = parasTotalSize - sizeof(*io);
156
157 rc = ioctl(fd, DM_TABLE_LOAD, io);
158 if (rc != 0) {
159 BEGET_LOGE("error 0x%x, DM_TABLE_LOAD failed for %s", rc, devName);
160 break;
161 }
162 } while (0);
163
164 free(parasBuf);
165
166 return rc;
167 }
168
ActiveDmDevice(int fd,const char * devName)169 static int ActiveDmDevice(int fd, const char *devName)
170 {
171 int rc;
172 struct dm_ioctl io;
173
174 rc = InitDmIo(&io, devName);
175 if (rc != 0) {
176 return rc;
177 }
178
179 io.flags |= DM_READONLY_FLAG;
180
181 rc = ioctl(fd, DM_DEV_SUSPEND, &io);
182 if (rc != 0) {
183 BEGET_LOGE("error, DM_TABLE_SUSPEND for %s, ret=%d", devName, rc);
184 return rc;
185 }
186
187 return 0;
188 }
189
GetDmDevPath(int fd,char ** dmDevPath,const char * devName)190 int GetDmDevPath(int fd, char **dmDevPath, const char *devName)
191 {
192 int rc;
193 char *path = NULL;
194 size_t path_len = strlen(DM_DEVICE_PATH_PREFIX) + 32;
195 unsigned int dev_num;
196 struct dm_ioctl io;
197
198 rc = InitDmIo(&io, devName);
199 if (rc != 0) {
200 BEGET_LOGE("error 0x%x, init Dm io", rc);
201 return rc;
202 }
203
204 rc = ioctl(fd, DM_DEV_STATUS, &io);
205 if (rc != 0) {
206 BEGET_LOGE("error, DM_DEV_STATUS for %s, ret=%d", devName, rc);
207 return rc;
208 }
209
210 dev_num = minor(io.dev);
211
212 path = calloc(1, path_len);
213 if (path == NULL) {
214 BEGET_LOGE("error, alloc dm dev path");
215 return -1;
216 }
217
218 rc = snprintf_s(path, path_len, path_len - 1, "%s%u", DM_DEVICE_PATH_PREFIX, dev_num);
219 if (rc < 0) {
220 BEGET_LOGE("error 0x%x, cp dm dev path", rc);
221 free(path);
222 return -1;
223 }
224
225 *dmDevPath = path;
226
227 return 0;
228 }
229
FsDmCreateDevice(char ** dmDevPath,const char * devName,DmVerityTarget * target)230 int FsDmCreateDevice(char **dmDevPath, const char *devName, DmVerityTarget *target)
231 {
232 int rc;
233 int fd = -1;
234
235 fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
236 if (fd < 0) {
237 BEGET_LOGE("error 0x%x, open %s", errno, DEVICE_MAPPER_PATH);
238 return -1;
239 }
240
241 rc = CreateDmDevice(fd, devName);
242 if (rc != 0) {
243 BEGET_LOGE("error 0x%x, create dm device fail", rc);
244 close(fd);
245 return rc;
246 }
247
248 rc = LoadDmDeviceTable(fd, devName, target, true);
249 if (rc != 0) {
250 BEGET_LOGE("error 0x%x, load device table fail", rc);
251 close(fd);
252 return rc;
253 }
254
255 rc = ActiveDmDevice(fd, devName);
256 if (rc != 0) {
257 BEGET_LOGE("error 0x%x, active device fail", rc);
258 close(fd);
259 return rc;
260 }
261
262 rc = GetDmDevPath(fd, dmDevPath, devName);
263 if (rc != 0) {
264 BEGET_LOGE("error 0x%x, get dm dev fail", rc);
265 close(fd);
266 return rc;
267 }
268 close(fd);
269 return 0;
270 }
271
FsDmInitDmDev(char * devPath,bool useSocket)272 int FsDmInitDmDev(char *devPath, bool useSocket)
273 {
274 int rc;
275 char dmDevPath[PATH_MAX] = {0};
276 char *devName = NULL;
277
278 if (devPath == NULL) {
279 BEGET_LOGE("error, devPath is NULL");
280 return -1;
281 }
282
283 devName = basename(devPath);
284
285 rc = snprintf_s(&dmDevPath[0], sizeof(dmDevPath), sizeof(dmDevPath) - 1, "%s%s", "/sys/block/", devName);
286 if (rc < 0) {
287 BEGET_LOGE("error 0x%x, format dm dev", rc);
288 return rc;
289 }
290
291 int ueventSockFd = -1;
292 if (useSocket) {
293 ueventSockFd = UeventdSocketInit();
294 if (ueventSockFd < 0) {
295 BEGET_LOGE("error, Failed to create uevent socket");
296 return -1;
297 }
298 }
299
300 RetriggerUeventByPath(ueventSockFd, &dmDevPath[0]);
301
302 close(ueventSockFd);
303
304 return 0;
305 }
306
FsDmRemoveDevice(const char * devName)307 int FsDmRemoveDevice(const char *devName)
308 {
309 int rc;
310 int fd = -1;
311 struct dm_ioctl io;
312
313 fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
314 if (fd < 0) {
315 BEGET_LOGE("error 0x%x, open %s", errno, DEVICE_MAPPER_PATH);
316 return -1;
317 }
318
319 rc = InitDmIo(&io, devName);
320 if (rc != 0) {
321 close(fd);
322 BEGET_LOGE("error 0x%x, init dm io", rc);
323 return -1;
324 }
325
326 io.flags |= DM_READONLY_FLAG;
327
328 rc = ioctl(fd, DM_DEV_REMOVE, &io);
329 if (rc != 0) {
330 close(fd);
331 BEGET_LOGE("error, DM_DEV_REMOVE failed for %s, ret=%d", devName, rc);
332 return -1;
333 }
334
335 close(fd);
336 return 0;
337 }
338
DmGetDeviceName(int fd,const char * devName,char * outDevName,const uint64_t outDevNameLen)339 static int DmGetDeviceName(int fd, const char *devName, char *outDevName, const uint64_t outDevNameLen)
340 {
341 int rc;
342 char *path = NULL;
343 size_t pathLen = strlen(DM_DEVICE_PATH_PREFIX) + 32;
344 struct dm_ioctl io;
345 rc = InitDmIo(&io, devName);
346 if (rc != 0) {
347 BEGET_LOGE("init dm io failed");
348 return rc;
349 }
350
351 rc = ioctl(fd, DM_DEV_STATUS, &io);
352 if (rc != 0) {
353 BEGET_LOGE("get DM_DEV_STATUS failed");
354 return rc;
355 }
356
357 int devNum = (io.dev & 0xff) | ((io.dev >> 12) & 0xff00);
358 path = calloc(1, pathLen);
359 if (path == NULL) {
360 BEGET_LOGE("calloc path failed");
361 return rc;
362 }
363
364 rc = snprintf_s(path, pathLen, pathLen - 1, "%s%d", DM_DEVICE_PATH_PREFIX, devNum);
365 if (rc < 0) {
366 BEGET_LOGE("copy dm path failed");
367 free(path);
368 path = NULL;
369 return rc;
370 }
371
372 rc = memcpy_s(outDevName, outDevNameLen, path, pathLen);
373 if (rc < 0) {
374 BEGET_LOGE("copy dm path failed");
375 }
376 BEGET_LOGI("dm get device outDevName %s, devNum %d", path, devNum);
377 free(path);
378 path = NULL;
379 return rc;
380 }
381
FsDmCreateLinearDevice(const char * devName,char * dmBlkName,uint64_t dmBlkNameLen,DmVerityTarget * target)382 int FsDmCreateLinearDevice(const char *devName, char *dmBlkName, uint64_t dmBlkNameLen, DmVerityTarget *target)
383 {
384 int rc;
385 int fd = -1;
386 fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
387 if (fd < 0) {
388 BEGET_LOGE("open mapper path failed");
389 return -1;
390 }
391
392 rc = CreateDmDevice(fd, devName);
393 if (rc) {
394 BEGET_LOGE("create dm device failed");
395 close(fd);
396 return -1;
397 }
398
399 rc = DmGetDeviceName(fd, devName, dmBlkName, dmBlkNameLen);
400 if (rc) {
401 BEGET_LOGE("get dm device name failed");
402 close(fd);
403 return -1;
404 }
405
406 rc = LoadDmDeviceTable(fd, devName, target, false);
407 if (rc) {
408 BEGET_LOGE("load dm device name failed");
409 close(fd);
410 return -1;
411 }
412
413 rc = ActiveDmDevice(fd, devName);
414 if (rc) {
415 BEGET_LOGE("active dm device name failed");
416 close(fd);
417 return -1;
418 }
419 close(fd);
420 BEGET_LOGE("fs create rofs linear device success, dev is [%s]", devName);
421 return 0;
422 }
423
424 #ifdef __cplusplus
425 #if __cplusplus
426 }
427 #endif
428 #endif
429