Apply requirement for gcov automation
[platform/core/system/libstorage.git] / src / storage-external.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 <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <sys/statvfs.h>
23 #include <vconf.h>
24 #include <tzplatform_config.h>
25 #include <libsyscommon/list.h>
26
27 #include "common.h"
28 #include "log.h"
29 #include "storage-external-dbus.h"
30
31 #define EXTERNAL_STORAGE_PATH  "/run/storaged/external-storage"
32 #define EXTENDED_INTERNAL_PATH "/run/storaged/extended-internal-sd"
33 #define PATH_LEN               55
34
35 #define LUKS_NAME "crypto_LUKS"
36
37 static GList *cb_list[STORAGE_CALLBACK_MAX];
38
39 static int storage_ext_get_dev_state(storage_ext_device *dev,
40                 enum storage_ext_state blk_state,
41                 storage_state_e *state)
42 {
43         if (!dev || !state)
44                 return -EINVAL;
45
46         switch (blk_state) {
47         case STORAGE_EXT_ADDED:
48                 *state = STORAGE_STATE_UNMOUNTABLE;
49                 return 0;
50         case STORAGE_EXT_REMOVED:
51                 *state = STORAGE_STATE_REMOVED;
52                 return 0;
53         case STORAGE_EXT_CHANGED:
54                 switch (dev->state) {
55                 case STORAGE_EXT_UNMOUNTED:
56                         *state = STORAGE_STATE_UNMOUNTABLE;
57                         return 0;
58                 case STORAGE_EXT_MOUNTED:
59                         if (dev->flags & MOUNT_READONLY)
60                                 *state = STORAGE_STATE_MOUNTED_READ_ONLY;
61                         else
62                                 *state = STORAGE_STATE_MOUNTED;
63                         return 0;
64                 default:
65                         return -EINVAL;
66                 }
67         case STORAGE_EXT_BLOCKED:
68                 *state = STORAGE_STATE_UNMOUNTABLE;
69                 return 0;
70         default:
71                 return -EINVAL;
72         }
73 }
74
75 int storage_ext_get_space(int storage_id,
76                 unsigned long long *total, unsigned long long *available)
77 {
78         storage_state_e state;
79         struct statvfs s;
80         int ret;
81         unsigned long long t = 0, a = 0;
82         storage_ext_device *dev;
83
84         if (storage_id < 0)
85                 return -ENODEV;
86
87         dev = calloc(1, sizeof(storage_ext_device));
88         if (!dev) {
89 //LCOV_EXCL_START System Error
90                 _E("calloc failed");
91                 return -ENOMEM;
92 //LCOV_EXCL_STOP
93         }
94
95         ret = storage_ext_get_device_info(storage_id, dev);
96         if (ret < 0) {
97                 _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
98                 goto out;
99         }
100
101         ret = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, &state);
102         if (ret < 0) {
103                 _E("Failed to get state of storage (id:%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
104                 goto out;
105         }
106
107         if (state >= STORAGE_STATE_MOUNTED) {
108 #ifdef __USE_FILE_OFFSET64
109                 ret = storage_get_external_memory_size64_with_path(dev->mount_point, &s);
110 #else
111                 ret = storage_get_external_memory_size_with_path(dev->mount_point, &s);
112 #endif
113                 if (ret < 0) {
114                         _E("Failed to get external memory size of (%s)(ret:%d)", dev->mount_point, ret); //LCOV_EXCL_LINE
115                         goto out;
116                 }
117
118                 t = (unsigned long long)s.f_frsize*s.f_blocks;
119                 a = (unsigned long long)s.f_bsize*s.f_bavail;
120         }
121
122         if (total)
123                 *total = t;
124         if (available)
125                 *available = a;
126
127         ret = 0;
128 out:
129         storage_ext_release_device(&dev);
130         return ret;
131 }
132
133 int storage_ext_foreach_device_list(storage_device_supported_cb callback, void *user_data)
134 {
135         int ret_val;
136         bool ret_cb;
137         GList *list = NULL, *elem;
138         storage_ext_device *dev;
139         storage_state_e state;
140
141         if (!callback)
142                 return -EINVAL;
143
144         ret_val = storage_ext_get_list(&list);
145         if (ret_val < 0) {
146                 _E("Failed to get external storage list from deviced (%d)", errno); //LCOV_EXCL_LINE
147                 return ret_val;
148         }
149
150         SYS_G_LIST_FOREACH(list, elem, dev) {
151                 ret_val = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, &state);
152                 if (ret_val < 0) {
153                         _E("Failed to get storage state (devnode:%s, ret_val:%d)", dev->devnode, ret_val); //LCOV_EXCL_LINE
154                         continue;
155                 }
156
157                 if (dev->type == STORAGE_EXT_MMC_EXTENDED_INTERNAL)
158                         ret_cb = callback(dev->storage_id,
159                                         STORAGE_TYPE_EXTENDED_INTERNAL,
160                                         state, dev->mount_point, user_data);
161                 else
162                         ret_cb = callback(dev->storage_id, STORAGE_TYPE_EXTERNAL,
163                                         state, dev->mount_point, user_data);
164                 if (!ret_cb)
165                         break;
166         }
167
168         if (list)
169                 storage_ext_release_list(&list);
170         return 0;
171 }
172
173 //LCOV_EXCL_START Not called Callback
174 static int storage_ext_id_changed(storage_ext_device *dev, enum storage_ext_state blk_state, void *data)
175 {
176         enum storage_cb_type type = (enum storage_cb_type)data;
177         struct storage_cb_info *cb_info;
178         GList *elem;
179         storage_state_e state;
180         int ret;
181
182         if (!dev)
183                 return -EINVAL;
184
185         if (type != STORAGE_CALLBACK_ID)
186                 return 0;
187
188         ret = storage_ext_get_dev_state(dev, blk_state, &state);
189         if (ret < 0) {
190                 _E("Failed to get storage state (devnode:%s, ret:%d)", dev->devnode, ret);
191                 return ret;
192         }
193
194         SYS_G_LIST_FOREACH(cb_list[STORAGE_CALLBACK_ID], elem, cb_info)
195                 cb_info->state_cb(cb_info->id, state, cb_info->user_data);
196
197         return 0;
198 }
199
200 static int storage_ext_type_changed(storage_ext_device *dev, enum storage_ext_state blk_state, void *data)
201 {
202         enum storage_cb_type type = (enum storage_cb_type)data;
203         struct storage_cb_info *cb_info;
204         GList *elem;
205         storage_state_e state;
206         int ret_val;
207         storage_dev_e strdev;
208         storage_type_e storage_type;
209         const char *fstype, *fsuuid, *mountpath;
210
211         if (!dev)
212                 return -EINVAL;
213
214         if (type != STORAGE_CALLBACK_TYPE)
215                 return -EINVAL;
216
217         ret_val = storage_ext_get_dev_state(dev, blk_state, &state);
218         if (ret_val < 0) {
219                 _E("Failed to get storage state (devnode:%s, ret_val:%d)", dev->devnode, ret_val);
220                 return ret_val;
221         }
222
223         if (dev->type == STORAGE_EXT_SCSI) {
224                 strdev = STORAGE_DEV_EXT_USB_MASS_STORAGE;
225                 storage_type = STORAGE_TYPE_EXTERNAL;
226         } else if (dev->type == STORAGE_EXT_MMC) {
227                 strdev = STORAGE_DEV_EXT_SDCARD;
228                 storage_type = STORAGE_TYPE_EXTERNAL;
229         } else if (dev->type == STORAGE_EXT_MMC_EXTENDED_INTERNAL) {
230                 strdev = STORAGE_DEV_EXTENDED_INTERNAL;
231                 storage_type = STORAGE_TYPE_EXTENDED_INTERNAL;
232         } else {
233                 _E("Invalid dev type (%d)", dev->type);
234                 return -EINVAL;
235         }
236
237         fstype = (dev->fs_type ? (const char *)dev->fs_type : "");
238         fsuuid = (dev->fs_uuid ? (const char *)dev->fs_uuid : "");
239         mountpath = (dev->mount_point ? (const char *)dev->mount_point : "");
240
241         if (!strncmp(fstype, LUKS_NAME, strlen(LUKS_NAME)))
242                 storage_type = STORAGE_TYPE_EXTENDED_INTERNAL;
243
244         SYS_G_LIST_FOREACH(cb_list[STORAGE_CALLBACK_TYPE], elem, cb_info) {
245                 if (cb_info->type != storage_type)
246                         continue;
247                 if (cb_info->type_cb)
248                         cb_info->type_cb(dev->storage_id, strdev, state,
249                                         fstype, fsuuid, mountpath, dev->primary,
250                                         dev->flags, cb_info->user_data);
251         }
252
253         return 0;
254 }
255
256 //LCOV_EXCL_STOP
257
258 static bool check_if_callback_exist(enum storage_cb_type type,
259                 struct storage_cb_info *info, struct storage_cb_info **cb_data)
260 {
261         struct storage_cb_info *cb_info;
262         GList *elem;
263
264         if (!info)
265                 return false;
266
267         if (type == STORAGE_CALLBACK_ID) {
268                 SYS_G_LIST_FOREACH(cb_list[type], elem, cb_info) {
269                         if (cb_info->id == info->id &&
270                             cb_info->state_cb == info->state_cb) {
271                                 goto out;
272                         }
273                 }
274         }
275
276         if (type == STORAGE_CALLBACK_TYPE) {
277                 SYS_G_LIST_FOREACH(cb_list[type], elem, cb_info) {
278                         if (cb_info->type == info->type &&
279                             cb_info->type_cb == info->type_cb)
280                                 goto out;
281                 }
282         }
283
284         return false;
285
286 out:
287         if (cb_data)
288                 *cb_data = cb_info;
289
290         return true;
291 }
292
293 int storage_ext_register_cb(enum storage_cb_type type, struct storage_cb_info *info)
294 {
295         struct storage_cb_info *cb_info;
296         int n, ret_val;
297         storage_ext_changed_cb callback;
298
299         if (!info)
300                 return -EINVAL;
301
302         switch (type) {
303         case STORAGE_CALLBACK_ID:
304                 callback = storage_ext_id_changed;
305                 break;
306         case STORAGE_CALLBACK_TYPE:
307                 callback = storage_ext_type_changed;
308                 break;
309         default:
310                 _E("Invalid callback type (%d)", type);
311                 return -EINVAL;
312         }
313
314         n = SYS_G_LIST_LENGTH(cb_list[type]);
315         if (n == 0) {
316                 ret_val = storage_ext_register_device_change(callback, (void *)type);
317                 if (ret_val < 0)
318                         return -EPERM;
319         }
320
321         if (check_if_callback_exist(type, info, NULL)) {
322                 _E("The callback is already registered");
323                 return 0;
324         }
325
326         /* add device changed callback to list (local) */
327         cb_info = malloc(sizeof(struct storage_cb_info));
328         if (!cb_info)
329                 return -errno;
330
331         memcpy(cb_info, info, sizeof(struct storage_cb_info));
332         SYS_G_LIST_APPEND(cb_list[type], cb_info);
333
334         return 0;
335 }
336
337 int storage_ext_unregister_cb(enum storage_cb_type type, struct storage_cb_info *info)
338 {
339         struct storage_cb_info *cb_info;
340         int n;
341         storage_ext_changed_cb callback;
342
343         if (!info)
344                 return -EINVAL;
345
346         switch (type) {
347         case STORAGE_CALLBACK_ID:
348                 callback = storage_ext_id_changed;
349                 break;
350         case STORAGE_CALLBACK_TYPE:
351                 callback = storage_ext_type_changed;
352                 break;
353         default:
354                 _E("Invalid callback type (%d)", type);
355                 return -EINVAL;
356         }
357
358         if (!check_if_callback_exist(type, info, &cb_info)) {
359                 _E("The callback is not registered");
360                 return 0;
361         }
362
363         /* remove device callback from list (local) */
364         if (cb_info) {
365                 SYS_G_LIST_REMOVE(cb_list[type], cb_info);
366                 free(cb_info);
367         }
368
369         /* check if this callback is last element */
370         n = SYS_G_LIST_LENGTH(cb_list[type]);
371         if (n == 0)
372                 storage_ext_unregister_device_change(callback);
373
374         return 0;
375 }
376
377 int storage_ext_get_root(int storage_id, char *path, size_t len, bool *extendedinternal)
378 {
379         FILE *fp;
380         storage_ext_device *dev;
381         char file_name[PATH_LEN];
382         char file_name2[PATH_LEN];
383         char *tmp;
384         int ret = 0;
385
386         if (storage_id < 0)
387                 return -ENODEV;
388
389         if (!path)
390                 return -EINVAL;
391         if (!extendedinternal)
392                 return -EINVAL;
393
394         snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", storage_id);
395         snprintf(file_name2, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", storage_id);
396
397         *extendedinternal = false;
398
399         if (access(file_name, R_OK) == 0) {
400                 fp = fopen(file_name, "r");
401                 if (!fp) {
402                         _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
403                         ret = -ENODEV;
404                         goto out;
405                 }
406
407                 tmp = fgets(path, len, fp);
408                 fclose(fp);
409                 if (!tmp) {
410                         ret = -ENODEV;
411                         _D("Failed to get path");
412                         goto out;
413                 }
414                 *extendedinternal = false;
415         } else if (access(file_name2, R_OK) == 0) {
416                 fp = fopen(file_name2, "r");
417                 if (!fp) {
418                         _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
419                         ret = -ENODEV;
420                         goto out;
421                 }
422
423                 tmp = fgets(path, len, fp);
424                 fclose(fp);
425                 if (!tmp) {
426                         ret = -ENODEV;
427                         _D("Failed to get path");
428                         goto out;
429                 }
430                 *extendedinternal = true;
431         } else {
432                 dev = calloc(1, sizeof(storage_ext_device));
433                 if (!dev) {
434 //LCOV_EXCL_START System Error
435                         _E("calloc failed");
436                         return -ENOMEM;
437 //LCOV_EXCL_STOP
438                 }
439
440                 ret = storage_ext_get_device_info(storage_id, dev);
441                 if (ret < 0) {
442                         _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
443                         storage_ext_release_device(&dev);
444                         goto out;
445                 }
446
447                 snprintf(path, len, "%s", dev->mount_point);
448                 if (dev->type == STORAGE_EXT_MMC_EXTENDED_INTERNAL)
449                         *extendedinternal = true;
450                 else
451                         *extendedinternal = false;
452                 storage_ext_release_device(&dev);
453         }
454
455         ret = 0;
456
457 out:
458         return ret;
459 }
460
461 int storage_ext_get_state(int storage_id, storage_state_e *state)
462 {
463         storage_ext_device *dev;
464         int ret;
465
466         if (storage_id < 0)
467                 return -ENODEV;
468
469         if (!state)
470                 return -EINVAL;
471
472         dev = calloc(1, sizeof(storage_ext_device));
473         if (!dev) {
474 //LCOV_EXCL_START System Error
475                 _E("calloc failed");
476                 return -ENOMEM;
477 //LCOV_EXCL_STOP
478         }
479
480         ret = storage_ext_get_device_info(storage_id, dev);
481         if (ret < 0) {
482                 _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
483                 goto out;
484         }
485
486         ret = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, state);
487         if (ret < 0)
488                 _E("Failed to get state of storage id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
489
490 out:
491         storage_ext_release_device(&dev);
492         return ret;
493 }
494
495 int storage_ext_get_primary_mmc_path(char *path, size_t len)
496 {
497         GList *list = NULL, *elem;
498         storage_ext_device *dev;
499         int ret;
500
501         ret = storage_ext_get_list(&list);
502         if (ret < 0) {
503                 _E("Failed to get external storage list from deviced (%d)", errno); //LCOV_EXCL_LINE
504                 return ret;
505         }
506
507         SYS_G_LIST_FOREACH(list, elem, dev) {
508                 if (dev->primary) {
509                         snprintf(path, len, "%s", dev->mount_point);
510                         ret = 0;
511                         goto out;
512                 }
513         }
514
515         ret = -ENODEV;
516
517 out:
518         if (list)
519                 storage_ext_release_list(&list);
520         return ret;
521 }