Tizen 2.1 base
[platform/framework/native/app-service.git] / src / FIo_MmcStorageManagerService.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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  * @file         FIo_MmcStorageManagerService.cpp
20  * @brief       This is the implementation for the _MmcStorageManagerService class.
21  */
22
23 #include <unistd.h>
24 #include <sys/mount.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <unique_ptr.h>
30 #include <sysman_managed.h>
31 #include <vconf.h>
32
33 #include <FIoFile.h>
34 #include <FIoDirectory.h>
35 #include <FIoMmcStorageManager.h>
36 #include <FBaseSysLog.h>
37 #include <FBaseInternalTypes.h>
38 #include <FBase_StringConverter.h>
39 #include <FAppTypes.h>
40 #include "FIo_MmcStorageManagerService.h"
41 #include "FIo_MmcStorageManagerStub.h"
42
43 #define VCONFKEY_APPSERVICE_MMC_STATUS  "memory/appservice/mmc"
44
45 using namespace Tizen::Base;
46 using namespace Tizen::Base::Collection;
47 using namespace Tizen::Io;
48 using namespace Tizen::App;
49
50 struct mmc_contents mmcContents;
51
52 namespace Tizen { namespace Io {
53
54 _MmcStorageManagerService* _MmcStorageManagerService::__pMmcStorageManagerService = null;
55 static const char _EXTERNAL_MOUNT_FLAG[] = "/tmp/osp-compat/mount/external";
56 static const int _MAX_PATH_LENGTH = 256;
57
58 result
59 _MmcStorageManagerService::ConvertNativeErrorToResult(int errNo)
60 {
61         SysLog(NID_IO, "ConvertNativeErrorToResult received : %d\n", errNo);
62         result r = E_SUCCESS;
63         //Covert the SLP response to Osp response
64         switch(errNo)
65         {
66                 case 0:
67                         r = E_SUCCESS;
68                         break;
69
70                 case EINVAL:
71                         // fall through
72                 case ENOENT:
73                         r = E_IO;
74                         break;
75
76                 case ENOMEM:
77                         r = E_OUT_OF_MEMORY;
78                         break;
79
80                 default:
81                         r = E_SYSTEM;
82         }
83         return r;
84 }
85
86 //Callbacks from SLP. Its a C function.
87 static void
88 MmcMountCb(int response, void* data)
89 {
90         SysLog(NID_IO, "MmcMountCb Called: %d\n", response);
91         result ospResult = E_SUCCESS;
92
93         ospResult = _MmcStorageManagerService::ConvertNativeErrorToResult(response);
94         SysTryLog(NID_IO, !IsFailed(ospResult), "[%s] Failed to mount MMC, errno: %d (%s)", GetErrorMessage(ospResult), response, strerror(response));
95         result r = ((_IMmcStorageServiceEventListener*)data)->OnMmcMountResponseReceived(ospResult);
96         SysTryReturnVoidResult(NID_IO, !IsFailed(r), r, "[%s] OnMmcMountResponseReceived failed.", GetErrorMessage(r));
97 }
98
99 static void
100 MmcUnmountCb(int response, void* data)
101 {
102         SysLog(NID_IO, "MmcUnmountCb Called: %d\n", response);
103         result ospResult = E_SUCCESS;
104
105         ospResult = _MmcStorageManagerService::ConvertNativeErrorToResult(response);
106         SysTryLog(NID_IO, !IsFailed(ospResult), "[%s] Failed to unmount MMC, errno: %d (%s)", GetErrorMessage(ospResult), response, strerror(response));
107         result r = ((_IMmcStorageServiceEventListener*)data)->OnMmcUnmountResponseReceived(ospResult);
108         SysTryReturnVoidResult(NID_IO, !IsFailed(r), r, "[%s] OnMmcUnmountResponseReceived failed.", GetErrorMessage(r));
109 }
110
111 static void
112 MmcFormatCb(int response, void* data)
113 {
114         SysLog(NID_IO, "MmcFormatCb Called: %d\n", response);
115         result ospResult = E_SUCCESS;
116
117         ospResult = _MmcStorageManagerService::ConvertNativeErrorToResult(response);
118         SysTryLog(NID_IO, !IsFailed(ospResult), "[%s] Failed to format MMC, errno: %d (%s)", GetErrorMessage(ospResult), response, strerror(response));
119         result r = ((_IMmcStorageServiceEventListener*)data)->OnMmcFormatResponseReceived(ospResult);
120         SysTryReturnVoidResult(NID_IO, !IsFailed(r), r, "[%s] OnMmcFormatResponseReceived failed.", GetErrorMessage(r));
121 }
122
123 _MmcStorageManagerService::_MmcStorageManagerService(void)
124         : __pStub(null)
125 {
126 }
127
128 _MmcStorageManagerService::~_MmcStorageManagerService(void)
129 {
130         int ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_MMC_STATUS, MmcEventVconfCallback);
131 }
132
133 _MmcStorageManagerService*
134 _MmcStorageManagerService::GetInstance(void)
135 {
136         if (__pMmcStorageManagerService == null)
137         {
138                 __pMmcStorageManagerService = new (std::nothrow) _MmcStorageManagerService();
139         }
140         return __pMmcStorageManagerService;
141 }
142
143 result
144 _MmcStorageManagerService::Construct(_IMmcStorageServiceEventListener* pStub)
145 {
146         __pStub = pStub;
147
148         int ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_MMC_STATUS, MmcEventVconfCallback, this);
149         SysTryReturnResult(NID_IO, ret == 0, E_SYSTEM, "Failed to register MMC event vconf callback.");
150
151         return E_SUCCESS;
152 }
153
154 result
155 _MmcStorageManagerService::Mount(void)
156 {
157         int slpResult = 0;
158
159         mmcContents.mmc_cb = MmcMountCb;
160         mmcContents.user_data = __pStub;
161
162         slpResult = sysman_request_mount_mmc(&mmcContents);
163         SysTryReturnResult(NID_IO, slpResult == 0, E_SYSTEM, "Mount Failed. Slp sync return value: %d", slpResult);
164
165         return E_SUCCESS;
166 }
167
168 result
169 _MmcStorageManagerService::Unmount(void)
170 {
171         int slpResult = 0;
172
173         mmcContents.mmc_cb = MmcUnmountCb;
174         mmcContents.user_data = __pStub;
175
176         slpResult = sysman_request_unmount_mmc(&mmcContents, 1);
177         SysTryReturnResult(NID_IO, slpResult == 0, E_SYSTEM, "Unmount Failed. Slp sync return value: %d", slpResult);
178
179         return E_SUCCESS;
180 }
181
182 result
183 _MmcStorageManagerService::Format(void)
184 {
185         int slpResult = 0;
186
187         mmcContents.mmc_cb = MmcFormatCb;
188         mmcContents.user_data = __pStub;
189
190         slpResult = sysman_request_format_mmc(&mmcContents);
191         SysTryReturnResult(NID_IO, slpResult == 0, E_SYSTEM, "Format Failed. Slp sync return value: %d", slpResult);
192
193         return E_SUCCESS;
194 }
195
196 void
197 _MmcStorageManagerService::MmcEventVconfCallback(keynode_t* node, void* userData)
198 {
199         static char mountList[][_MAX_PATH_LENGTH] =
200         {
201                 "/opt/storage/sdcard",
202                 "/Storagecard/Media"
203         };
204         char mountPoint[_MAX_PATH_LENGTH] = { 0, };
205
206         if (strcmp(VCONFKEY_SYSMAN_MMC_STATUS, vconf_keynode_get_name(node)) == 0)
207         {
208                 int value = 0;
209                 int res = vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &value);
210                 result r = E_SUCCESS;
211
212                 _MmcStorageManagerService* pMmcMgr = static_cast< _MmcStorageManagerService* >(userData);
213                 _AppList::const_iterator iter;
214                 for (iter = pMmcMgr->__appList.begin(); iter != pMmcMgr->__appList.end(); ++iter)
215                 {
216                         const String* pAppRoot = iter->second;
217                         if (pAppRoot != null)
218                         {
219                                 std::unique_ptr< char[] > pAppRootPath(_StringConverter::CopyToCharArrayN(*pAppRoot));
220                                 SysTryReturnVoidResult(NID_IO, pAppRootPath != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
221
222                                 char* pPkgId = strrchr(pAppRootPath.get(), '/');
223                                 char mountFlag[_MAX_PATH_LENGTH] = { 0, };
224                                 sprintf(mountFlag, "%s/%s", _EXTERNAL_MOUNT_FLAG, ++pPkgId);
225
226                                 if (value == 1)
227                                 {
228                                         SysLog(NID_IO, "MMC mount event for OSP compatible application.");
229
230                                         res = access(mountFlag, F_OK);
231                                         if (res == -1 && errno == ENOENT)
232                                         {
233                                                 r = _MmcStorageManagerService::CreateFlag(mountFlag);
234                                                 SysTryReturnVoidResult(NID_IO, !IsFailed(r), E_SYSTEM, "[%s] Failed to create mount flag (%s)",
235                                                                 GetErrorMessage(r), mountFlag);
236
237                                                 if (access(pAppRootPath.get(), F_OK) == 0)
238                                                 {
239                                                         for (int i = 0; i < sizeof(mountList)/_MAX_PATH_LENGTH; ++i)
240                                                         {
241                                                                 memset(mountPoint, 0, _MAX_PATH_LENGTH);
242                                                                 sprintf(mountPoint, "%ls%s", pAppRoot->GetPointer(), mountList[i]);
243 #ifdef _OSP_EMUL_
244                                                                 res = mount("/dev/emul_mmcblk0", mountPoint, "ext3", 0, "");
245 #else
246                                                                 res = mount("/dev/mmcblk1p1", mountPoint, "vfat", 0,
247                                                                                 "uid=0,gid=0,dmask=0000,fmask=0111,iocharset=iso8859-1,utf8,shortname=mixed,smackfsroot=*,smackfsdef=*");
248 #endif
249                                                                 if (res == -1)
250                                                                 {
251                                                                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to mount (%s), errno: %d (%s)",
252                                                                                         mountPoint, errno, strerror(errno));
253
254                                                                         res = unlink(mountFlag);
255                                                                         SysTryReturnVoidResult(NID_IO, res == 0, E_SYSTEM, "[E_SYSTEM] Failed to remove mount flag (%s), errno: %d (%s)",
256                                                                                         mountFlag, errno, strerror(errno));
257                                                                 }
258                                                         }
259
260                                                         r = _MmcStorageManagerService::CreateExternalDirectories(*pAppRoot, String(pPkgId));
261                                                         SysTryReturnVoidResult(NID_IO, !IsFailed(r), E_SYSTEM, "[%s] Failed to create external directories.",
262                                                                         GetErrorMessage(r));
263
264                                                         char mountSrc[_MAX_PATH_LENGTH] = { 0, };
265                                                         char mountDest[_MAX_PATH_LENGTH] = { 0, };
266                                                         sprintf(mountSrc, "/opt/storage/sdcard/osp/apps/%s", pPkgId);
267                                                         sprintf(mountDest, "%ls/HomeExt", pAppRoot->GetPointer());
268                                                         res = mount(mountSrc, mountDest, null, MS_BIND, null);
269                                                         if (res == -1)
270                                                         {
271                                                                 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to mount (%s), errno: %d (%s)",
272                                                                                 mountDest, errno, strerror(errno));
273
274                                                                 res = unlink(mountFlag);
275                                                                 SysTryReturnVoidResult(NID_IO, res == 0, E_SYSTEM, "[E_SYSTEM] Failed to remove mount flag (%s), errno: %d (%s)",
276                                                                                 mountFlag, errno, strerror(errno));
277                                                         }
278
279                                                         SysLog(NID_IO, "mount() succeeded, mount flag: %s", mountFlag);
280                                                 }
281                                         }
282                                         else if (res == -1)
283                                         {
284                                                 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to access mount flag (%s), errno: %d (%s)",
285                                                                 mountFlag, errno, strerror(errno));
286                                                 return;
287                                         }
288                                         else
289                                         {
290                                                 SysLog(NID_IO, "mount() was already done.");
291                                         }
292                                 }
293                                 else
294                                 {
295                                         SysLog(NID_IO, "MMC unmount event for OSP compatible application.");
296
297                                         for (int i = 0; i < sizeof(mountList)/_MAX_PATH_LENGTH; ++i)
298                                         {
299                                                 memset(mountPoint, 0, _MAX_PATH_LENGTH);
300                                                 sprintf(mountPoint, "%ls%s", pAppRoot->GetPointer(), mountList[i]);
301
302                                                 res = umount2(mountPoint, MNT_DETACH);
303                                                 SysTryLog(NID_IO, res == 0 || errno == ENOENT, "[E_SYSTEM] Failed to unmount (%s), errno: %d (%s)",
304                                                                 mountPoint, errno, strerror(errno));
305                                         }
306
307                                         char mountDest[_MAX_PATH_LENGTH] = { 0, };
308                                         sprintf(mountDest, "%ls/HomeExt", pAppRoot->GetPointer());
309                                         res = umount2(mountDest, MNT_DETACH);
310                                         SysTryLog(NID_IO, res == 0 || errno == ENOENT, "[E_SYSTEM] Failed to unmount (%s), errno: %d (%s)",
311                                                         mountDest, errno, strerror(errno));
312
313                                         if (access(mountFlag, F_OK) == 0)
314                                         {
315                                                 res = unlink(mountFlag);
316                                                 SysTryReturnVoidResult(NID_IO, res == 0, E_SYSTEM, "[E_SYSTEM] Failed to remove mount flag (%s), errno: %d (%s)",
317                                                                 mountFlag, errno, strerror(errno));
318                                         }
319
320                                         if (access(pAppRootPath.get(), F_OK) != 0 && errno == ENOENT)
321                                         {
322                                                 std::string key(pPkgId);
323                                                 String* pAppRoot = pMmcMgr->__appList[key];
324                                                 if (pAppRoot != null)
325                                                 {
326                                                         pMmcMgr->__appList.erase(key);
327                                                         SysLog(NID_IO, "OSP compatible application is unregistered.");
328                                                 }
329                                         }
330                                         SysLog(NID_IO, "unmount() succeeded, mount flag: %s", mountFlag);
331                 }
332             }
333         }
334                 res = vconf_set_int(VCONFKEY_APPSERVICE_MMC_STATUS, value);
335         }
336 }
337
338 result
339 _MmcStorageManagerService::CreateFlag(const String& path)
340 {
341         int index = 0;
342         result r = path.LastIndexOf(L'/', path.GetLength() - 1, index);
343         SysTryReturnResult(NID_IO, !IsFailed(r), E_SYSTEM, "The method cannot proceed due to a severe system error.");
344
345         String dirPath;
346         r = path.SubString(0, index, dirPath);
347         SysTryReturnResult(NID_IO, !IsFailed(r), E_SYSTEM, "The method cannot proceed due to a severe system error.");
348
349         if (!File::IsFileExist(dirPath) && GetLastResult() == E_SUCCESS)
350         {
351                 r = Directory::Create(dirPath, true);
352                 SysTryReturnResult(NID_IO, !IsFailed(r), r, "Failed to create parent directory.");
353         }
354
355         File file;
356         r = file.Construct(path, "w");
357         SysTryReturnResult(NID_IO, !IsFailed(r), r, "Failed to create mount flag.");
358
359         return E_SUCCESS;
360 }
361
362 result
363 _MmcStorageManagerService::CreateExternalDirectories(const String& appRoot, const PackageId& pkgId)
364 {
365         String appHomeExt(appRoot);
366         appHomeExt.Append("/HomeExt");
367         if (!File::IsFileExist(appHomeExt) && GetLastResult() == E_SUCCESS)
368         {
369                 result r = Directory::Create(appHomeExt, false);
370                 SysTryReturnResult(NID_IO, !IsFailed(r), r, "Failed to create application HomeExt directory.");
371         }
372
373         String mmcHomeExt(L"/opt/storage/sdcard/osp/apps/");
374         mmcHomeExt.Append(pkgId);
375         if (!File::IsFileExist(mmcHomeExt) && GetLastResult() == E_SUCCESS)
376         {
377                 result r = Directory::Create(mmcHomeExt, true);
378                 SysTryReturnResult(NID_IO, !IsFailed(r), r, "Failed to create MMC HomeExt directory.");
379         }
380
381         return E_SUCCESS;
382 }
383
384 }} // Tizen::Io
385