Add storage_is_mounted api
[platform/core/system/libstorage.git] / src / statvfs.c
1 /*
2  * storage
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <string.h>
23 #include <sys/statvfs.h>
24 #include <sys/stat.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <mntent.h>
28 #include <tzplatform_config.h>
29
30 #include "log.h"
31 #include "common.h"
32 #include "storage-external.h"
33
34 #define MEMORY_GIGABYTE_VALUE  1073741824
35 #define MEMORY_MEGABYTE_VALUE  1048576
36
37 #define EXTERNAL_MEMORY_NODE   "sdcard"
38 #define STORAGE_CONF_FILE      "/etc/storage/libstorage.conf"
39
40
41 #define MAX_LINE    128
42 #define MAX_SECTION 64
43 #define WHITESPACE  " \t"
44 #define NEWLINE     "\n\r"
45 #define COMMENT     '#'
46
47 #define MATCH(a, b)    (!strncmp(a, b, strlen(a)))
48 #define SET_CONF(a, b) (a = (b > 0.0 ? b : a))
49
50 struct parse_result {
51         char *section;
52         char *name;
53         char *value;
54 };
55
56 struct storage_config_info {
57         double total_size;
58         double check_size;
59         double reserved_size;
60 };
61
62 static struct storage_config_info storage_info;
63
64 static inline char *trim_str(char *s)
65 {
66         char *t;
67         /* left trim */
68         s += strspn(s, WHITESPACE);
69
70         /* right trim */
71         for (t = strchr(s, 0); t > s; t--)
72                 if (!strchr(WHITESPACE, t[-1]))
73                         break;
74         *t = 0;
75         return s;
76 }
77
78 static int config_parse(const char *file_name, int cb(struct parse_result *result,
79                         void *user_data), void *user_data)
80 {
81         FILE *f = NULL;
82         struct parse_result result;
83         /* use stack for parsing */
84         char line[MAX_LINE];
85         char section[MAX_SECTION];
86         char *start, *end, *name, *value;
87         int lineno = 0, ret = 0;
88
89         if (!file_name || !cb) {
90                 ret = -EINVAL;
91                 goto error;
92         }
93
94         /* open conf file */
95         f = fopen(file_name, "r");
96         if (!f) {
97                 _E("Failed to open file %s", file_name); //LCOV_EXCL_LINE
98                 ret = -EIO;
99                 goto error;
100         }
101
102         /* parsing line by line */
103         while (fgets(line, MAX_LINE, f) != NULL) {
104                 lineno++;
105
106                 start = line;
107                 start[strcspn(start, NEWLINE)] = '\0';
108                 start = trim_str(start);
109
110                 if (*start == COMMENT) {
111                         continue;
112                 } else if (*start == '[') {
113                         /* parse section */
114                         end = strchr(start, ']');
115                         if (!end || *end != ']') {
116                                 ret = -EBADMSG;
117                                 goto error;
118                         }
119
120                         *end = '\0';
121                         strncpy(section, start + 1, sizeof(section));
122                         section[MAX_SECTION-1] = '\0';
123                 } else if (*start) {
124                         /* parse name & value */
125                         end = strchr(start, '=');
126                         if (!end || *end != '=') {
127                                 ret = -EBADMSG;
128                                 goto error;
129                         }
130                         *end = '\0';
131                         name = trim_str(start);
132                         value = trim_str(end + 1);
133                         end = strchr(value, COMMENT);
134                         if (end && *end == COMMENT) {
135                                 *end = '\0';
136                                 value = trim_str(value);
137                         }
138
139                         result.section = section;
140                         result.name = name;
141                         result.value = value;
142                         /* callback with parse result */
143                         ret = cb(&result, user_data);
144                         if (ret < 0) {
145                                 ret = -EBADMSG;
146                                 goto error;
147                         }
148                 }
149         }
150         _D("Success to load %s", file_name);
151         fclose(f);
152         return 0;
153
154 error:
155         if (f)
156                 fclose(f);
157         _E("Failed to read %s:%d!", file_name, lineno); //LCOV_EXCL_LINE
158         return ret;
159 }
160
161 static int load_config(struct parse_result *result, void *user_data)
162 {
163         static int check_size = -1;
164         struct storage_config_info *info = (struct storage_config_info *)user_data;
165         char *name;
166         char *value;
167
168         if (!info)
169                 return -EINVAL;
170
171         if (!MATCH(result->section, "STORAGE"))
172                 return -EINVAL;
173
174         name = result->name;
175         value = result->value;
176
177         if (info->check_size > 0 && check_size < 0)
178                 check_size = (storage_info.total_size < info->check_size) ? 1 : 0;
179         if (MATCH(name, "CHECK_SIZE"))
180                 info->check_size = atoi(value);
181         else if (check_size == 0 && MATCH(name, "RESERVE"))
182                 info->reserved_size = atoi(value);
183         else if (check_size == 1 && MATCH(name, "RESERVE_LITE"))
184                 info->reserved_size = atoi(value);
185
186         return 0;
187 }
188
189 static void storage_config_load(struct storage_config_info *info)
190 {
191         int ret;
192
193         ret = config_parse(STORAGE_CONF_FILE, load_config, info);
194         if (ret < 0)
195                 _E("Failed to load %s, %d Use default value!", STORAGE_CONF_FILE, ret); //LCOV_EXCL_LINE
196 }
197
198 static int get_memory_size(const char *path, struct statvfs_32 *buf)
199 {
200         struct statvfs s;
201         int ret;
202
203         assert(buf);
204
205         ret = statvfs(path, &s);
206         if (ret)
207                 return -errno; //LCOV_EXCL_LINE System Error
208
209         memset(buf, 0, sizeof(struct statvfs_32));
210
211         buf->f_bsize  = s.f_bsize;
212         buf->f_frsize = s.f_frsize;
213         buf->f_blocks = (unsigned long)s.f_blocks;
214         buf->f_bfree  = (unsigned long)s.f_bfree;
215         buf->f_bavail = (unsigned long)s.f_bavail;
216         buf->f_files  = (unsigned long)s.f_files;
217         buf->f_ffree  = (unsigned long)s.f_ffree;
218         buf->f_favail = (unsigned long)s.f_favail;
219         buf->f_fsid = s.f_fsid;
220         buf->f_flag = s.f_flag;
221         buf->f_namemax = s.f_namemax;
222
223         return 0;
224 }
225
226 API int storage_get_internal_memory_size(struct statvfs *buf)
227 {
228         struct statvfs_32 temp;
229         static unsigned long reserved = 0;
230         int ret;
231
232         if (!buf) {
233                 _E("input param error");
234                 return -EINVAL;
235         }
236
237         ret = get_memory_size(tzplatform_getenv(TZ_SYS_USER), &temp);
238         if (ret || temp.f_bsize == 0) {
239                 _E("fail to get memory size %d", ret); //LCOV_EXCL_LINE
240                 return -errno; //LCOV_EXCL_LINE System Error
241         }
242
243         if (reserved == 0) {
244                 storage_info.total_size = (double)temp.f_frsize * temp.f_blocks;
245                 storage_config_load(&storage_info);
246                 reserved = (unsigned long)storage_info.reserved_size;
247                 reserved = reserved/temp.f_bsize;
248                 _I("total %4.4lf check %4.4lf reserved %4.4lf",
249                         storage_info.total_size, storage_info.check_size, storage_info.reserved_size);
250         }
251         if (temp.f_bavail < reserved)
252                 temp.f_bavail = 0;
253         else
254                 temp.f_bavail -= reserved;
255
256         memcpy(buf, &temp, sizeof(temp));
257         return 0;
258 }
259
260 API int storage_get_internal_memory_size64(struct statvfs *buf)
261 {
262         static unsigned long reserved = 0;
263         int ret;
264
265         if (!buf) {
266                 _E("input param error"); //LCOV_EXCL_LINE
267                 return -EINVAL;
268         }
269
270         ret = statvfs(tzplatform_getenv(TZ_SYS_USER), buf);
271         if (ret) {
272                 _E("fail to get memory size"); //LCOV_EXCL_LINE
273                 return -errno; //LCOV_EXCL_LINE System Error
274         }
275
276         if (reserved == 0) {
277                 storage_info.total_size = (double)(buf->f_frsize * buf->f_blocks);
278                 storage_config_load(&storage_info);
279                 reserved = (unsigned long)storage_info.reserved_size;
280                 reserved = reserved/buf->f_bsize;
281                 _I("total %4.4lf check %4.4lf reserved %4.4lf",
282                         storage_info.total_size, storage_info.check_size, storage_info.reserved_size);
283         }
284         if (buf->f_bavail < reserved)
285                 buf->f_bavail = 0;
286         else
287                 buf->f_bavail -= reserved;
288         return 0;
289 }
290
291 int mount_check(char *path)
292 {
293         int ret = false;
294         struct mntent *mnt;
295         const char *table = "/etc/mtab";
296         FILE *fp;
297
298         fp = setmntent(table, "r");
299         if (!fp)
300                 return ret;
301         while ((mnt = getmntent(fp))) {
302                 if (!strcmp(mnt->mnt_dir, path)) {
303                         ret = true;
304                         break;
305                 }
306         }
307         endmntent(fp);
308         return ret;
309 }
310
311 static int get_external_path(char *path, size_t len)
312 {
313         return storage_ext_get_primary_mmc_path(path, len);
314 }
315
316 int storage_get_external_memory_size_with_path(char *path, struct statvfs *buf)
317 {
318         struct statvfs_32 temp;
319         int ret;
320         char ext_path[32];
321
322         _D("storage_get_external_memory_size");
323         if (!buf) {
324                 _E("input param error");
325                 return -EINVAL;
326         }
327
328         if (path)
329                 snprintf(ext_path, sizeof(ext_path), "%s", path);
330         else {
331                 if (!storage_ext_is_supported()) {
332                         _D("Block module is not enabled");
333                         goto out_nodev;
334                 }
335                 ret = get_external_path(ext_path, sizeof(ext_path));
336                 if (ret == -ENODEV)
337                         goto out_nodev;
338                 if (ret < 0) {
339                         _E("Failed to get external path(%d)", ret); //LCOV_EXCL_LINE
340                         return ret;
341                 }
342         }
343
344         if (!mount_check(ext_path))
345                 goto out_nodev;
346
347         ret = storage_ext_get_statvfs(ext_path, &temp);
348         if (ret) {
349                 _E("fail to get memory size"); //LCOV_EXCL_LINE
350                 return ret; //LCOV_EXCL_LINE System Error
351         }
352
353         memcpy(buf, &temp, sizeof(temp));
354         return 0;
355
356 out_nodev:
357         memset(buf, 0, sizeof(struct statvfs_32));
358         return 0;
359 }
360
361 int storage_get_external_memory_size64_with_path(char *path, struct statvfs *buf)
362 {
363         int ret;
364         char ext_path[32];
365
366         _D("storage_get_external_memory_size64");
367         if (!buf) {
368                 _E("input param error");
369                 return -EINVAL;
370         }
371
372         if (path)
373                 snprintf(ext_path, sizeof(ext_path), "%s", path);
374         else {
375                 if (!storage_ext_is_supported()) {
376                         _D("Block module is not enabled");
377                         goto out_nodev;
378                 }
379                 ret = get_external_path(ext_path, sizeof(ext_path));
380                 if (ret == -ENODEV)
381                         goto out_nodev;
382                 if (ret < 0) {
383                         _E("Failed to get external path(%d)", ret);
384                         return ret;
385                 }
386         }
387
388         if (!mount_check(ext_path))
389                 goto out_nodev;
390
391         ret = storage_ext_get_statvfs_size64(ext_path, buf);
392         if (ret) {
393         //LCOV_EXCL_START System Error
394                 _E("fail to get memory size");
395                 return -errno;
396         //LCOV_EXCL_STOP
397         }
398
399         return 0;
400
401 out_nodev:
402         memset(buf, 0, sizeof(struct statvfs));
403         return 0;
404 }
405
406 API int storage_get_external_memory_size(struct statvfs *buf)
407 {
408         return storage_get_external_memory_size_with_path(NULL, buf);
409 }
410
411 API int storage_get_external_memory_size64(struct statvfs *buf)
412 {
413         return storage_get_external_memory_size64_with_path(NULL, buf);
414 }