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 const char g_dmType[MAXNUMTYPE][MAX_WORDS_LEN] = {"verity", "linear", "snapshot", "snapshot-merge"};
37
InitDmIo(struct dm_ioctl * io,const char * devName)38 int InitDmIo(struct dm_ioctl *io, const char *devName)
39 {
40 errno_t err;
41
42 err = memset_s(io, sizeof(*io), 0, sizeof(*io));
43 if (err != EOK) {
44 BEGET_LOGE("memset io, ret=%d", err);
45 return -1;
46 }
47
48 io->version[0] = DM_VERSION0;
49 io->version[1] = DM_VERSION1;
50 io->version[2] = DM_VERSION2;
51 io->data_size = sizeof(*io);
52 io->data_start = 0;
53
54 if (devName == NULL) {
55 return 0;
56 }
57
58 err = strcpy_s(io->name, sizeof(io->name), devName);
59 if (err != EOK) {
60 BEGET_LOGE("cp devName, ret=%d", err);
61 return -1;
62 }
63
64 return 0;
65 }
66
CreateDmDev(int fd,const char * devName)67 int CreateDmDev(int fd, const char *devName)
68 {
69 int rc;
70 struct dm_ioctl io;
71
72 rc = InitDmIo(&io, devName);
73 if (rc != 0) {
74 return rc;
75 }
76
77 rc = ioctl(fd, DM_DEV_CREATE, &io);
78 if (rc != 0) {
79 BEGET_LOGE("error, DM_DEV_CREATE failed for %s, ret=%d", devName, rc);
80 return rc;
81 }
82
83 return 0;
84 }
85
LoadDmDeviceTable(int fd,const char * devName,DmVerityTarget * target,int dmTypeIdx)86 int LoadDmDeviceTable(int fd, const char *devName, DmVerityTarget *target, int dmTypeIdx)
87 {
88 int rc;
89 errno_t err;
90 char *parasBuf = NULL;
91 size_t parasTotalSize;
92 struct dm_ioctl *io = NULL;
93 struct dm_target_spec *ts = NULL;
94 char *paras = NULL;
95
96 FS_DM_RETURN_ERR_IF_NULL(target);
97 FS_DM_RETURN_ERR_IF_NULL(target->paras);
98 if (dmTypeIdx >= MAXNUMTYPE || dmTypeIdx < 0) {
99 BEGET_LOGE("dmTypeIdx error dmTypeIdx %d", dmTypeIdx);
100 return -1;
101 }
102
103 parasTotalSize = DM_ALIGN(sizeof(*io) + sizeof(*ts) + target->paras_len + 1);
104 parasBuf = calloc(1, parasTotalSize);
105 if (parasBuf == NULL) {
106 BEGET_LOGE("error, calloc dm table fail");
107 return -1;
108 }
109
110 io = (struct dm_ioctl *)parasBuf;
111 ts = (struct dm_target_spec *)(parasBuf + sizeof(*io));
112 paras = parasBuf + sizeof(*io) + sizeof((*ts));
113
114 do {
115 rc = InitDmIo(io, devName);
116 if (rc != 0) {
117 BEGET_LOGE("error 0x%x, init dm io", rc);
118 break;
119 }
120
121 io->data_size = parasTotalSize;
122 io->data_start = sizeof(*io);
123 io->target_count = 1;
124 if (dmTypeIdx != SNAPSHOT) {
125 io->flags |= DM_READONLY_FLAG;
126 }
127
128 ts->status = 0;
129 ts->sector_start = target->start;
130 ts->length = target->length;
131 err = strcpy_s(ts->target_type, sizeof(ts->target_type), g_dmType[dmTypeIdx]);
132 if (err != EOK) {
133 rc = -1;
134 BEGET_LOGE("error 0x%x, cp target type", err);
135 break;
136 }
137 BEGET_LOGI("get target type is %s", ts->target_type);
138 err = strcpy_s(paras, target->paras_len + 1, target->paras);
139 if (err != EOK) {
140 rc = -1;
141 BEGET_LOGE("error 0x%x, cp target paras", err);
142 break;
143 }
144
145 ts->next = parasTotalSize - sizeof(*io);
146
147 rc = ioctl(fd, DM_TABLE_LOAD, io);
148 if (rc != 0) {
149 BEGET_LOGE("error 0x%x, DM_TABLE_LOAD failed for %s", rc, devName);
150 break;
151 }
152 } while (0);
153
154 free(parasBuf);
155
156 return rc;
157 }
158
ActiveDmDevice(int fd,const char * devName)159 int ActiveDmDevice(int fd, const char *devName)
160 {
161 int rc;
162 struct dm_ioctl io;
163
164 rc = InitDmIo(&io, devName);
165 if (rc != 0) {
166 return rc;
167 }
168
169 io.flags |= DM_READONLY_FLAG;
170
171 rc = ioctl(fd, DM_DEV_SUSPEND, &io);
172 if (rc != 0) {
173 BEGET_LOGE("error, DM_TABLE_SUSPEND for %s, ret=%d", devName, rc);
174 return rc;
175 }
176
177 return 0;
178 }
179
GetDmDevPath(int fd,char ** dmDevPath,const char * devName)180 int GetDmDevPath(int fd, char **dmDevPath, const char *devName)
181 {
182 int rc;
183 char *path = NULL;
184 size_t path_len = strlen(DM_DEVICE_PATH_PREFIX) + 32;
185 unsigned int dev_num;
186 struct dm_ioctl io;
187
188 rc = InitDmIo(&io, devName);
189 if (rc != 0) {
190 BEGET_LOGE("error 0x%x, init Dm io", rc);
191 return rc;
192 }
193
194 rc = ioctl(fd, DM_DEV_STATUS, &io);
195 if (rc != 0) {
196 BEGET_LOGE("error, DM_DEV_STATUS for %s, ret=%d", devName, rc);
197 return rc;
198 }
199
200 dev_num = minor(io.dev);
201
202 path = calloc(1, path_len);
203 if (path == NULL) {
204 BEGET_LOGE("error, alloc dm dev path");
205 return -1;
206 }
207
208 rc = snprintf_s(path, path_len, path_len - 1, "%s%u", DM_DEVICE_PATH_PREFIX, dev_num);
209 if (rc < 0) {
210 BEGET_LOGE("error 0x%x, cp dm dev path", rc);
211 free(path);
212 return -1;
213 }
214
215 *dmDevPath = path;
216
217 return 0;
218 }
219
FsDmCreateDevice(char ** dmDevPath,const char * devName,DmVerityTarget * target)220 int FsDmCreateDevice(char **dmDevPath, const char *devName, DmVerityTarget *target)
221 {
222 int rc;
223 int fd = -1;
224
225 fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
226 if (fd < 0) {
227 BEGET_LOGE("error 0x%x, open %s", errno, DEVICE_MAPPER_PATH);
228 return -1;
229 }
230
231 rc = CreateDmDev(fd, devName);
232 if (rc != 0) {
233 BEGET_LOGE("error 0x%x, create dm device fail", rc);
234 close(fd);
235 return rc;
236 }
237
238 rc = LoadDmDeviceTable(fd, devName, target, VERIFY);
239 if (rc != 0) {
240 BEGET_LOGE("error 0x%x, load device table fail", rc);
241 close(fd);
242 return rc;
243 }
244
245 rc = ActiveDmDevice(fd, devName);
246 if (rc != 0) {
247 BEGET_LOGE("error 0x%x, active device fail", rc);
248 close(fd);
249 return rc;
250 }
251
252 rc = GetDmDevPath(fd, dmDevPath, devName);
253 if (rc != 0) {
254 BEGET_LOGE("error 0x%x, get dm dev fail", rc);
255 close(fd);
256 return rc;
257 }
258 close(fd);
259 return 0;
260 }
261
FsDmInitDmDev(char * devPath,bool useSocket)262 int FsDmInitDmDev(char *devPath, bool useSocket)
263 {
264 int rc;
265 char dmDevPath[PATH_MAX] = {0};
266 char *devName = NULL;
267
268 if (devPath == NULL) {
269 BEGET_LOGE("error, devPath is NULL");
270 return -1;
271 }
272
273 devName = basename(devPath);
274
275 rc = snprintf_s(&dmDevPath[0], sizeof(dmDevPath), sizeof(dmDevPath) - 1, "%s%s", "/sys/block/", devName);
276 if (rc < 0) {
277 BEGET_LOGE("error 0x%x, format dm dev", rc);
278 return rc;
279 }
280
281 int ueventSockFd = -1;
282 if (useSocket) {
283 ueventSockFd = UeventdSocketInit();
284 if (ueventSockFd < 0) {
285 BEGET_LOGE("error, Failed to create uevent socket");
286 return -1;
287 }
288 }
289 char **devices = (char **)calloc(1, sizeof(char *));
290 if (devices == NULL) {
291 BEGET_LOGE("Failed calloc err=%d", errno);
292 return -1;
293 }
294
295 devices[0] = strdup(devPath);
296 if (devices[0] == NULL) {
297 BEGET_LOGE("Failed to strdup devPath");
298 free(devices);
299 return -1;
300 }
301 BEGET_LOGI("FsDmInitDmDev dmDevPath %s devices %s", &dmDevPath[0], devices[0]);
302 RetriggerDmUeventByPath(ueventSockFd, &dmDevPath[0], devices, 1);
303 free(devices[0]);
304 free(devices);
305
306 close(ueventSockFd);
307
308 return 0;
309 }
310
FsDmRemoveDevice(const char * devName)311 int FsDmRemoveDevice(const char *devName)
312 {
313 int rc;
314 int fd = -1;
315 struct dm_ioctl io;
316
317 fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
318 if (fd < 0) {
319 BEGET_LOGE("error 0x%x, open %s", errno, DEVICE_MAPPER_PATH);
320 return -1;
321 }
322
323 rc = InitDmIo(&io, devName);
324 if (rc != 0) {
325 close(fd);
326 BEGET_LOGE("error 0x%x, init dm io", rc);
327 return -1;
328 }
329
330 io.flags |= DM_READONLY_FLAG;
331
332 rc = ioctl(fd, DM_DEV_REMOVE, &io);
333 if (rc != 0) {
334 close(fd);
335 BEGET_LOGE("error, DM_DEV_REMOVE failed for %s, ret=%d", devName, rc);
336 return -1;
337 }
338
339 close(fd);
340 return 0;
341 }
342
DmGetDeviceName(int fd,const char * devName,char * outDevName,const uint64_t outDevNameLen)343 int DmGetDeviceName(int fd, const char *devName, char *outDevName, const uint64_t outDevNameLen)
344 {
345 int rc;
346 char *path = NULL;
347 size_t pathLen = strlen(DM_DEVICE_PATH_PREFIX) + 32;
348 struct dm_ioctl io;
349 rc = InitDmIo(&io, devName);
350 if (rc != 0) {
351 BEGET_LOGE("init dm io failed");
352 return rc;
353 }
354
355 rc = ioctl(fd, DM_DEV_STATUS, &io);
356 if (rc != 0) {
357 BEGET_LOGE("get DM_DEV_STATUS failed");
358 return rc;
359 }
360
361 int devNum = (io.dev & 0xff) | ((io.dev >> 12) & 0xff00);
362 path = calloc(1, pathLen);
363 if (path == NULL) {
364 BEGET_LOGE("calloc path failed");
365 return -1;
366 }
367
368 rc = snprintf_s(path, pathLen, pathLen - 1, "%s%d", DM_DEVICE_PATH_PREFIX, devNum);
369 if (rc < 0) {
370 BEGET_LOGE("copy dm path failed");
371 free(path);
372 path = NULL;
373 return rc;
374 }
375
376 rc = memcpy_s(outDevName, outDevNameLen, path, pathLen);
377 if (rc < 0) {
378 BEGET_LOGE("copy dm path failed");
379 }
380 BEGET_LOGI("dm get device outDevName %s, devNum %d", path, devNum);
381 free(path);
382 path = NULL;
383 return rc;
384 }
385
FsDmCreateLinearDevice(const char * devName,char * dmBlkName,uint64_t dmBlkNameLen,DmVerityTarget * target)386 int FsDmCreateLinearDevice(const char *devName, char *dmBlkName, uint64_t dmBlkNameLen, DmVerityTarget *target)
387 {
388 int rc;
389 int fd = -1;
390 fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
391 if (fd < 0) {
392 BEGET_LOGE("open mapper path failed");
393 return -1;
394 }
395
396 rc = CreateDmDev(fd, devName);
397 if (rc) {
398 BEGET_LOGE("create dm device failed");
399 close(fd);
400 return -1;
401 }
402
403 rc = DmGetDeviceName(fd, devName, dmBlkName, dmBlkNameLen);
404 if (rc) {
405 BEGET_LOGE("get dm device name failed");
406 close(fd);
407 return -1;
408 }
409
410 rc = LoadDmDeviceTable(fd, devName, target, LINEAR);
411 if (rc) {
412 BEGET_LOGE("load dm device name failed");
413 close(fd);
414 return -1;
415 }
416
417 rc = ActiveDmDevice(fd, devName);
418 if (rc) {
419 BEGET_LOGE("active dm device name failed");
420 close(fd);
421 return -1;
422 }
423 close(fd);
424 BEGET_LOGI("fs create rofs linear device success, dev is [%s]", devName);
425 return 0;
426 }
427
GetDmStatusInfo(const char * name,struct dm_ioctl * io)428 bool GetDmStatusInfo(const char *name, struct dm_ioctl *io)
429 {
430 int fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
431 if (fd < 0) {
432 BEGET_LOGE("error 0x%x, open %s", errno, DEVICE_MAPPER_PATH);
433 return false;
434 }
435 int rc = InitDmIo(io, name);
436 if (rc != 0) {
437 close(fd);
438 return false;
439 }
440 if (ioctl(fd, DM_DEV_STATUS, io) != 0) {
441 BEGET_LOGE("DM_DEV_STATUS failed for %s\n", name);
442 close(fd);
443 return false;
444 }
445 close(fd);
446 return true;
447 }
448
449
450 #ifdef __cplusplus
451 #if __cplusplus
452 }
453 #endif
454 #endif
455