fc02c6bf207421a8d84210e3302f84f5831ee38e
[platform/core/system/libstorage.git] / src / storage-sdcard.c
1 /*
2  * Copyright (c) 2011 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
25 #include "common.h"
26 #include "list.h"
27 #include "log.h"
28
29 #define SDCARD_PATH "/opt/storage/sdcard"
30
31 #ifndef __USE_FILE_OFFSET64
32 int __WEAK__ storage_get_external_memory_size(struct statvfs *buf);
33 #else
34 int __WEAK__ storage_get_external_memory_size64(struct statvfs *buf);
35 #endif
36
37 static dd_list *cb_list[STORAGE_CALLBACK_MAX];
38
39 static int sdcard_get_state(void)
40 {
41         int val, ret;
42
43         ret = vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &val);
44         if (ret < 0)
45                 return -EPERM;
46
47         switch (val) {
48         case VCONFKEY_SYSMAN_MMC_MOUNTED:
49                 return STORAGE_STATE_MOUNTED;
50         case VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED:
51                 return STORAGE_STATE_UNMOUNTABLE;
52         case VCONFKEY_SYSMAN_MMC_REMOVED:
53         default:
54                 break;
55         }
56
57         return STORAGE_STATE_REMOVED;
58 }
59
60 static int sdcard_get_space(unsigned long long *total, unsigned long long *available)
61 {
62         storage_state_e state;
63         struct statvfs s;
64         int ret, t, a;
65
66         state = sdcard_get_state();
67         if (state < STORAGE_STATE_MOUNTED) {
68                 t = 0;
69                 a = 0;
70         } else {        /* if sdcard is mounted */
71 #ifndef __USE_FILE_OFFSET64
72                 ret = storage_get_external_memory_size(&s);
73 #else
74                 ret = storage_get_external_memory_size64(&s);
75 #endif
76                 if (ret < 0)
77                         return -EPERM;
78
79                 t = (unsigned long long)s.f_frsize*s.f_blocks;
80                 a = (unsigned long long)s.f_bsize*s.f_bavail;
81         }
82
83         if (total)
84                 *total = t;
85         if (available)
86                 *available = a;
87
88         return 0;
89 }
90
91 static const char *sdcard_get_root(void)
92 {
93         return SDCARD_PATH;
94 }
95
96 static void sdcard_state_cb(keynode_t *key, void *data)
97 {
98         struct storage_cb_info *cb_info;
99         dd_list *elem;
100         storage_state_e state;
101
102         state = sdcard_get_state();
103
104         DD_LIST_FOREACH(cb_list[STORAGE_CALLBACK_STATE], elem, cb_info)
105                 cb_info->state_cb(cb_info->id, state, cb_info->user_data);
106 }
107
108 static int register_request(enum storage_cb_type type)
109 {
110         switch (type) {
111         case STORAGE_CALLBACK_STATE:
112                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_MMC_STATUS,
113                                 sdcard_state_cb, NULL);
114         default:
115                 break;
116         }
117
118         return -EINVAL;
119 }
120
121 static int release_request(enum storage_cb_type type)
122 {
123         switch (type) {
124         case STORAGE_CALLBACK_STATE:
125                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_MMC_STATUS,
126                                 sdcard_state_cb);
127         default:
128                 break;
129         }
130
131         return -EINVAL;
132 }
133
134 static int sdcard_register_cb(enum storage_cb_type type, struct storage_cb_info *info)
135 {
136         struct storage_cb_info *cb_info;
137         dd_list *elem;
138         int ret, n;
139
140         if (type < 0 || type >= STORAGE_CALLBACK_MAX)
141                 return -EINVAL;
142
143         if (!info)
144                 return -EINVAL;
145
146         /* check if it is the first request */
147         n = DD_LIST_LENGTH(cb_list[type]);
148         if (n == 0) {
149                 ret = register_request(type);
150                 if (ret < 0)
151                         return -EPERM;
152         }
153
154         /* check for the same request */
155         DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
156                 if (cb_info->id == info->id &&
157                     cb_info->state_cb == info->state_cb)
158                         return -EEXIST;
159         }
160
161         /* add device changed callback to list (local) */
162         cb_info = malloc(sizeof(struct storage_cb_info));
163         if (!cb_info)
164                 return -errno;
165
166         memcpy(cb_info, info, sizeof(struct storage_cb_info));
167         DD_LIST_APPEND(cb_list[type], cb_info);
168
169         return 0;
170 }
171
172 static int sdcard_unregister_cb(enum storage_cb_type type, struct storage_cb_info *info)
173 {
174         struct storage_cb_info *cb_info;
175         dd_list *elem;
176         int ret, n;
177
178         if (type < 0 || type >= STORAGE_CALLBACK_MAX)
179                 return -EINVAL;
180
181         if (!info)
182                 return -EINVAL;
183
184         /* search for the same element with callback */
185         DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
186                 if (cb_info->id == info->id &&
187                     cb_info->state_cb == info->state_cb)
188                         break;
189         }
190
191         if (!cb_info)
192                 return -EINVAL;
193
194         /* remove device callback from list (local) */
195         DD_LIST_REMOVE(cb_list[type], cb_info);
196         free(cb_info);
197
198         /* check if this callback is last element */
199         n = DD_LIST_LENGTH(cb_list[type]);
200         if (n == 0) {
201                 ret = release_request(type);
202                 if (ret < 0)
203                         return -EPERM;
204         }
205
206         return 0;
207 }
208
209 const struct storage_ops sdcard = {
210         .type = STORAGE_TYPE_EXTERNAL,
211         .root = sdcard_get_root,
212         .get_state = sdcard_get_state,
213         .get_space = sdcard_get_space,
214         .register_cb = sdcard_register_cb,
215         .unregister_cb = sdcard_unregister_cb,
216 };
217
218 STORAGE_OPS_REGISTER(&sdcard)