Increase line coverage using LCOV_EXCL
[platform/core/system/libstorage.git] / src / storage-inhouse.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <tzplatform_config.h>
25 #include <blkid.h>
26 #include <libsyscommon/libgdbus.h>
27 #include <libsyscommon/common.h>
28
29 #include "common.h"
30 #include "log.h"
31 #include "storage-internal.h"
32 #include "storage-external-dbus.h"
33
34 #define FORMAT_TIMEOUT  (120*1000)
35 #define USER_PARTITION "user"
36 #define CONTAINER_USER_PARTITION "contain-user"
37
38 /*
39         Get compat path from origin Multi-user path
40         from TZ_USER_CONTENT/.. to /opt/usr/media/..
41         Input should be normalized path like /opt/usr/home/owner/media (TODO: internal normalization)
42
43         Why this API should be provided?
44         In multi-user environment, each user has own compat content direcotry.(/opt/usr/media)
45         However, although system daemon operates real path,
46                 system daemon needs to provide compat path to App if the real path is converted.
47
48         Usage:
49                 #include <storage-internal.h>
50
51                 char dest[100];
52                 if(storage_get_compat_internal_path(src, sizeof(dest), dest) < 0)
53                         // cannot convert. use src path
54                 else
55                         // can convert. use dest path
56  */
57 //LCOV_EXCL_START Untested function
58 API int storage_get_compat_internal_path(const char* origin, int len, char* compat)
59 {
60         int r = -1;
61         int str_len;
62         const char* str;
63
64         if (!compat || !origin) {
65                 _E("Invalid parameter");
66                 return -1;
67         }
68
69         if (getuid() <= USER_UID_START) {
70                 //LCOV_EXCL_START System Error
71                 _E("Only apps and user session daemons are allowed "
72                                 "to use storage_get_compat_internal_path()");
73                 return -1;
74                 //LCOV_EXCL_STOP
75         }
76
77         // this API works on place where compat path is bind-mounted
78         if (!is_compat_bind_mount()) {
79                 //LCOV_EXCL_START System Error
80                 _E("No compat bind mount");
81                 return -1;
82                 //LCOV_EXCL_STOP
83         }
84
85         str = tzplatform_uid_getenv(getuid(), TZ_USER_CONTENT);
86         str_len = strlen(str);
87         if (strncmp(origin, str, str_len) != 0) {
88                 _E("Failed to match TZ_USER_CONTENT");
89                 return -1;
90         }
91
92         r = snprintf(compat, len, "%s%s", COMPAT_DIR, origin + str_len);
93         if (r < 0) {
94                 //LCOV_EXCL_START System Error
95                 _E("Failed to create new path");
96                 return -1;
97                 //LCOV_EXCL_STOP
98         }
99
100         return 0;
101 }
102 //LCOV_EXCL_STOP
103
104 /*
105         Get Multi-user path from compat path
106         from /opt/usr/media/.. to TZ_USER_CONTENT/..
107         Input should be normalized path like /opt/usr/media (TODO: internal normalization)
108
109         Why this API should be provided?
110         In multi-user environment, each user has own compat content direcotry.(/opt/usr/media)
111         However, although some APIs send the compat path to system daemon,
112                 system daemon should access real path.
113
114         Usage:
115                 #include <storage-internal.h>
116
117                 char dest[100];
118                 if(storage_get_origin_internal_path(src, sizeof(dest), dest) < 0)
119                         // cannot convert. use src path
120                 else
121                         // can convert. use dest path
122 */
123 API int storage_get_origin_internal_path(const char* compat, int len, char* origin)
124 {
125         int r;
126         int compat_len;
127
128         if (!compat || !origin) {
129                 _E("Invalid parameter");
130                 return -1;
131         }
132
133         if (getuid() <= USER_UID_START) {
134                 //LCOV_EXCL_START System Error
135                 _E("Only apps and user session daemons are allowed "
136                                 "to use storage_get_origin_internal_path()");
137                 return -1;
138                 //LCOV_EXCL_STOP
139         }
140
141         // this API works on place where compat path is bind-mounted
142         if (!is_compat_bind_mount()) {
143                 //LCOV_EXCL_START System Error
144                 _E("no compat bind mount");
145                 return -1;
146                 //LCOV_EXCL_STOP
147         }
148
149         compat_len = strlen(COMPAT_DIR);
150         if (strncmp(compat, COMPAT_DIR, compat_len) != 0) {
151                 _E("failed to match COMPAT_DIR");
152                 return -1;
153         }
154
155         r = snprintf(origin, len, "%s%s", tzplatform_uid_getenv(getuid(), TZ_USER_CONTENT), compat + compat_len);
156         if (r < 0) {
157                 //LCOV_EXCL_START System Error
158                 _E("failed to create new path");
159                 return -1;
160                 //LCOV_EXCL_STOP
161         }
162
163         return 0;
164 }
165
166 API int storage_get_primary_sdcard(int *storage_id, char **path)
167 {
168         GVariant *reply;
169         int ret, ret_dbus;
170         char *reply_mount_point = NULL;
171         int reply_id;
172
173         if (!storage_id || !path)
174                 return STORAGE_ERROR_INVALID_PARAMETER;
175
176         if (!storage_ext_is_supported())
177                 return STORAGE_ERROR_NOT_SUPPORTED;
178
179         dbus_handle_h dbus_handle = gdbus_get_connection(G_BUS_TYPE_SYSTEM, true);
180         if (dbus_handle == NULL) {
181                 //LCOV_EXCL_START Dbus error
182                 _E("Failed to get dbus connection");
183                 return STORAGE_ERROR_OPERATION_FAILED;
184                 //LCOV_EXCL_STOP
185         }
186
187         ret_dbus = gdbus_priv_call_sync_with_reply(dbus_handle,
188                         STORAGE_EXT_BUS_NAME,
189                         STORAGE_EXT_PATH_MANAGER,
190                         STORAGE_EXT_IFACE_MANAGER,
191                         "GetMmcPrimary",
192                         NULL,
193                         &reply);
194
195         gdbus_free_connection(dbus_handle);
196
197         if (ret_dbus < 0) {
198                 //LCOV_EXCL_START System Error
199                 _E("Failed to get primary sdcard partition"); //LCOV_EXCL_LINE
200                 return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
201                 //LCOV_EXCL_STOP
202         }
203
204         if (!g_variant_get_safe(reply, "(issssssisibii)",
205                         NULL, NULL, NULL,
206                         NULL, NULL,
207                         NULL, NULL,
208                         NULL, &reply_mount_point,
209                         NULL, NULL,
210                         NULL, &reply_id)) {
211                 //LCOV_EXCL_START Dbus error
212                 g_variant_unref(reply);
213                 return STORAGE_ERROR_OPERATION_FAILED;
214                 //LCOV_EXCL_STOP
215         }
216
217         g_variant_unref(reply);
218
219         if (reply_id < 0) {
220                 ret = STORAGE_ERROR_NO_DEVICE;
221                 goto out;
222         }
223
224         *path = strdup(reply_mount_point);
225         if (*path == NULL) {
226                 ret = STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
227                 goto out; //LCOV_EXCL_LINE System Error
228         }
229
230         *storage_id = reply_id;
231
232         ret = STORAGE_ERROR_NONE;
233 out:
234         g_free(reply_mount_point);
235
236         return ret;
237 }
238
239 //LCOV_EXCL_START Internal API
240 API int storage_get_storage_level(const char *path, char **level)
241 {
242         int ret_level;
243
244         if (!level || !path)
245                 return STORAGE_ERROR_INVALID_PARAMETER;
246
247         ret_level = storage_ext_get_storage_level(path, level);
248         if (ret_level == -ENOMEM)
249                 return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
250         else if (ret_level == -EINVAL)
251                 return STORAGE_ERROR_INVALID_PARAMETER;
252         else if (ret_level < 0)
253                 return STORAGE_ERROR_OPERATION_FAILED;
254
255         return STORAGE_ERROR_NONE;
256 }
257 //LCOV_EXCL_STOP Internal API
258
259 //LCOV_EXCL_START Not called callback
260 static void mount_mmc_cb(GVariant *var, void *user_data, GError *err)
261 {
262         struct mmc_contents *mmc_data = (struct mmc_contents*)user_data;
263         int mmc_ret = -1;
264
265         _D("mount_mmc_cb called");
266
267         if (!var) {
268                 _E("no message [%s]", err->message);
269                 mmc_ret = -EBADMSG;
270                 goto exit;
271         }
272
273         g_variant_get(var, "(i)", &mmc_ret);
274
275         _I("Mount State : %d", mmc_ret);
276
277 exit:
278         if (var)
279                 g_variant_unref(var);
280         (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
281 }
282 //LCOV_EXCL_STOP
283
284 //LCOV_EXCL_START Internal API
285 API int storage_request_mount_mmc(struct mmc_contents *mmc_data)
286 {
287         void (*mount_cb)(GVariant *, void *, GError *) = NULL;
288         void *data = NULL;
289         char *path;
290         int ret_val;
291         int id;
292
293         if (mmc_data && mmc_data->mmc_cb) {
294                 _I("Mount callback exists");
295                 mount_cb = mount_mmc_cb;
296                 data = mmc_data;
297         }
298
299         ret_val = storage_get_primary_sdcard(&id, &path);
300         if (ret_val != STORAGE_ERROR_NONE)
301                 return ret_val;
302         if (path)
303                 free(path);
304
305         ret_val = gdbus_call_async_with_reply(STORAGE_EXT_BUS_NAME,
306                         STORAGE_EXT_PATH_MANAGER,
307                         STORAGE_EXT_IFACE_MANAGER,
308                         "Mount",
309                         g_variant_new("(is)", id, ""),
310                         mount_cb,
311                         -1,
312                         data);
313
314         _I("Mount Request %s", ret_val == 0 ? "Success" : "Failed");
315
316         if (ret_val == -ENOMEM)
317                 return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
318         if (ret_val < 0)
319                 return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
320
321         return STORAGE_ERROR_NONE;
322 }
323 //LCOV_EXCL_STOP Internal API
324
325 //LCOV_EXCL_START Not called callback
326 static void unmount_mmc_cb(GVariant *var, void *user_data, GError *err)
327 {
328         struct mmc_contents *mmc_data = (struct mmc_contents*)user_data;
329         int mmc_ret;
330
331         _D("unmount_mmc_cb called");
332
333         if (!var) {
334                 _E("no message [%s]", err->message);
335                 mmc_ret = -EBADMSG;
336                 goto exit;
337         }
338
339         g_variant_get(var, "(i)", &mmc_ret);
340
341         _I("Unmount State : %d", mmc_ret);
342
343 exit:
344         if (var)
345                 g_variant_unref(var);
346         (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
347 }
348 //LCOV_EXCL_STOP
349
350 //LCOV_EXCL_START Internal API
351 API int storage_request_unmount_mmc(struct mmc_contents *mmc_data, int option)
352 {
353         void (*unmount_cb)(GVariant *, void *, GError *) = NULL;
354         void *data = NULL;
355         char *path;
356         int ret_val;
357         int id;
358
359         if (option < 0 || option > 1)
360                 return STORAGE_ERROR_INVALID_PARAMETER;
361
362         if (mmc_data && mmc_data->mmc_cb) {
363                 _I("Unmount callback exists");
364                 unmount_cb = unmount_mmc_cb;
365                 data = mmc_data;
366         }
367
368         ret_val = storage_get_primary_sdcard(&id, &path);
369         if (ret_val != STORAGE_ERROR_NONE)
370                 return ret_val;
371         if (path)
372                 free(path);
373
374         ret_val = gdbus_call_async_with_reply(STORAGE_EXT_BUS_NAME,
375                         STORAGE_EXT_PATH_MANAGER,
376                         STORAGE_EXT_IFACE_MANAGER,
377                         "Unmount",
378                         g_variant_new("(ii)", id, option),
379                         unmount_cb,
380                         -1,
381                         data);
382
383         _I("Unmount Request %s", ret_val == 0 ? "Success" : "Failed");
384
385         if (ret_val == -ENOMEM)
386                 return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
387         if (ret_val < 0)
388                 return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
389
390         return STORAGE_ERROR_NONE;
391 }
392 //LCOV_EXCL_STOP
393
394 //LCOV_EXCL_START Not called callback
395 static void format_mmc_cb(GVariant *var, void *user_data, GError *err)
396 {
397         struct mmc_contents *mmc_data = (struct mmc_contents*)user_data;
398         int mmc_ret;
399
400         _D("format_mmc_cb called");
401
402         if (!var) {
403                 _E("no message [%s]", err->message);
404                 mmc_ret = -EBADMSG;
405                 goto exit;
406         }
407
408         g_variant_get(var, "(i)", &mmc_ret);
409
410         _I("Format State : %d", mmc_ret);
411
412 exit:
413         if (var)
414                 g_variant_unref(var);
415         (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
416 }
417 //LCOV_EXCL_STOP
418
419 //LCOV_EXCL_START Internal API
420 API int storage_request_format_mmc(struct mmc_contents *mmc_data)
421 {
422         return storage_format_mmc(mmc_data, 1);
423 }
424 //LCOV_EXCL_STOP
425
426 //LCOV_EXCL_START Internal API
427 API int storage_format_mmc(struct mmc_contents *mmc_data, int option)
428 {
429         void (*format_cb)(GVariant *, void *, GError *) = NULL;
430         void *data = NULL;
431         char *path;
432         int ret_val;
433         int id;
434
435         if (option < 0 || option > 1)
436                 return STORAGE_ERROR_INVALID_PARAMETER;
437
438         if (mmc_data && mmc_data->mmc_cb) {
439                 _I("Format callback exists");
440                 format_cb = format_mmc_cb;
441                 data = mmc_data;
442         }
443
444         ret_val = storage_get_primary_sdcard(&id, &path);
445         if (ret_val != STORAGE_ERROR_NONE)
446                 return ret_val;
447         if (path)
448                 free(path);
449
450         ret_val = gdbus_call_async_with_reply(STORAGE_EXT_BUS_NAME,
451                         STORAGE_EXT_PATH_MANAGER,
452                         STORAGE_EXT_IFACE_MANAGER,
453                         "Format",
454                         g_variant_new("(ii)", id, option),
455                         format_cb,
456                         FORMAT_TIMEOUT,
457                         data);
458
459         _I("Format Request %s", ret_val == 0 ? "Success" : "Failed");
460
461         if (ret_val == -ENOMEM)
462                 return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE System Error
463         if (ret_val < 0)
464                 return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
465
466         return STORAGE_ERROR_NONE;
467 }
468 //LCOV_EXCL_STOP
469
470 //LCOV_EXCL_START Internal API
471 API int storage_is_mounted_opt_usr(storage_part_mount_e *mounted)
472 {
473         blkid_cache cache = NULL;
474         blkid_dev_iterate iter;
475         blkid_dev dev;
476         int ret_val;
477         bool found = false;
478         char *user_label = syscommon_is_container()? CONTAINER_USER_PARTITION: USER_PARTITION;
479
480         if (!mounted)
481                 return STORAGE_ERROR_INVALID_PARAMETER;
482
483         _D("Find user partition label: %s", user_label);
484         ret_val = blkid_get_cache(&cache, NULL);
485         if (ret_val < 0) {
486                 _E("Failed to get cache"); //LCOV_EXCL_LINE
487                 *mounted = STORAGE_PART_ERROR; //LCOV_EXCL_LINE
488                 return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
489         }
490
491         ret_val = blkid_probe_all(cache);
492         if (ret_val < 0) {
493                 _E("Failed to probe all block devices"); //LCOV_EXCL_LINE
494                 *mounted = STORAGE_PART_ERROR; //LCOV_EXCL_LINE
495                 return STORAGE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
496         }
497
498         iter = blkid_dev_iterate_begin(cache);
499         if (!iter) {
500                 _E("Failed to get iterate"); //LCOV_EXCL_LINE
501                 *mounted = STORAGE_PART_ERROR; //LCOV_EXCL_LINE
502                 return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
503         }
504
505         ret_val = blkid_dev_set_search(iter, "LABEL", user_label);
506         if (blkid_dev_next(iter, &dev) == 0) {
507                 dev = blkid_verify(cache, dev);
508                 if (dev) {
509                         found = true;
510                         _D("Partition for user data is found(LABEL=%s)", user_label);
511                 }
512         }
513         blkid_dev_iterate_end(iter);
514
515         if (!found) {
516                 iter = blkid_dev_iterate_begin(cache);
517                 if (!iter) {
518                         _E("Failed to get iterate"); //LCOV_EXCL_LINE
519                         *mounted = STORAGE_PART_ERROR; //LCOV_EXCL_LINE
520                         return STORAGE_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
521                 }
522
523                 ret_val = blkid_dev_set_search(iter, "PARTLABEL", user_label);
524                 if (blkid_dev_next(iter, &dev) == 0) {
525                         dev = blkid_verify(cache, dev);
526                         if (dev) {
527                                 found = true;
528                                 _D("Partition for user data is found(PARTLABEL=%s)", user_label);
529                         }
530                 }
531                 blkid_dev_iterate_end(iter);
532         }
533
534         blkid_put_cache(cache);
535
536         if (found) {
537                 ret_val = mount_check(tzplatform_getenv(TZ_SYS_USER));
538                 if (ret_val)
539                         *mounted = STORAGE_PART_MOUNTED;
540                 else
541                         *mounted = STORAGE_PART_NOT_MOUNTED;
542         } else
543                 *mounted = STORAGE_PART_NOT_SUPPORTED;
544
545         return STORAGE_ERROR_NONE;
546 }
547 //LCOV_EXCL_STOP