75c804d11ab9f9480b8eb46f2cf26fe18e13e2f1
[profile/ivi/persistence-client-library.git] / src / persistence_client_library_db_access.c
1 /******************************************************************************
2  * Project         Persistency
3  * (c) copyright   2012
4  * Company         XS Embedded GmbH
5  *****************************************************************************/
6 /******************************************************************************
7  * This Source Code Form is subject to the terms of the
8  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed
9  * with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 ******************************************************************************/
11  /**
12  * @file           persistence_client_library_data_access.c
13  * @ingroup        Persistence client library
14  * @author         Ingo Huerner
15  * @brief          Implementation of persistence database access
16  *                 Library provides an API to access persistent data
17  * @see            
18  */
19
20 #include "persistence_client_library_db_access.h"
21 #include "persistence_client_library_custom_loader.h"
22 #include "persistence_client_library_dbus_service.h"
23 #include "persistence_client_library_prct_access.h"
24
25 #include <persComErrors.h>
26 #include <persComDataOrg.h>
27 #include <persComDbAccess.h>
28
29 #include <dbus/dbus.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34
35
36
37 /// btree array
38 static int gHandlesDB[DbTableSize][PersistencePolicy_LastEntry];
39 static int gHandlesDBCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} };
40
41
42 // function prototype
43 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, unsigned int reason);
44
45
46 char* pers_get_raw_key(char *key)
47 {
48    char *temp = NULL;
49    char *rawKey = key;
50
51    temp = strrchr(key, (int)'/');
52    
53    if (NULL != temp)
54    {
55           rawKey = temp + 1;
56    }
57
58    return rawKey;
59 }
60
61
62 int pers_db_open_default(const char* dbPath, PersDefaultType_e DefaultType)
63 {
64    int ret = 0;
65    char path[DbPathMaxLen] = {0};
66
67    if (PersDefaultType_Configurable == DefaultType)
68    {
69       snprintf(path, DbPathMaxLen, "%s%s", dbPath, gLocalConfigurableDefault);
70    }
71    else if (PersDefaultType_Factory== DefaultType)
72    {
73       snprintf(path, DbPathMaxLen, "%s%s", dbPath, gLocalFactoryDefault);
74    }
75    else
76    {
77       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_open_default ==> unknown DefaultType"));
78       ret = EPERS_COMMON;
79    }
80
81    if (EPERS_COMMON != ret)
82    {
83       ret = persComDbOpen(path, 0);
84       if (ret < 0)
85       {
86          ret = EPERS_COMMON;
87          DLT_LOG(gPclDLTContext, DLT_LOG_WARN,
88                               DLT_STRING("pers_db_open_default() -> persComDbOpen() -> problem open db: "),
89                               DLT_STRING(path),
90                               DLT_STRING(" Code: "),
91                               DLT_INT(ret));
92       }
93    }
94
95    return ret;
96 }
97
98
99 int pers_get_defaults(char* dbPath, char* key, unsigned char* buffer, unsigned int buffer_size, PersGetDefault_e job)
100 {
101    PersDefaultType_e i = PersDefaultType_Configurable;
102    int handleDefaultDB = -1;
103    int read_size = EPERS_NOKEY;
104    char dltMessage[DbPathMaxLen] = {0};
105
106    key = pers_get_raw_key(key); /* We need only the raw key without a prefixed '/node/' or '/user/1/seat/0' etc... */
107
108    for(i=0; i<PersDefaultType_LastEntry; i++)
109    {
110       handleDefaultDB = pers_db_open_default(dbPath, i);
111       if(handleDefaultDB >= 0)
112       {
113          if (PersGetDefault_Data == job)
114          {
115                 read_size = persComDbReadKey(handleDefaultDB, key, (char*)buffer, buffer_size);
116          }
117          else if (PersGetDefault_Size == job)
118          {
119             read_size = persComDbGetKeySize(handleDefaultDB, key);
120          }
121          else
122          {
123             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_get_defaults ==> unknown job"));
124             break;
125          }
126
127          if (0 > persComDbClose(handleDefaultDB))
128          {
129             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_get_defaults ==> persComDbClose returned with error"));
130          }
131
132          if(read_size < 0) // check read_size
133          {
134             if(PERS_COM_ERR_NOT_FOUND == read_size)
135             {
136                read_size = EPERS_NOKEY;
137             }
138          }
139          else /* read_size >= 0 --> default value found */
140          {
141             if (PersDefaultType_Configurable == i)
142             {
143                snprintf(dltMessage, DbPathMaxLen, "%s%s", dbPath, gLocalConfigurableDefault);
144             }
145             if (PersDefaultType_Factory == i)
146             {
147                 snprintf(dltMessage, DbPathMaxLen, "%s%s", dbPath, gLocalFactoryDefault);
148             }
149             DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Default data will be used for Key"),
150                                                DLT_STRING(key),
151                                                DLT_STRING("from"),
152                                                DLT_STRING(dltMessage));
153             break;
154          }
155       }
156    }
157
158    if (read_size < 0)
159    {
160        DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Default data not available for Key"),
161                                           DLT_STRING(key),
162                                           DLT_STRING("Path:"),
163                                           DLT_STRING(dbPath));
164    }
165
166    return read_size;
167 }
168
169
170 int database_get(PersistenceInfo_s* info, const char* dbPath)
171 {
172    int arrayIdx = 0;
173    int handleDB = -1;
174
175    // create array index: index is a combination of resource config table type and group
176    arrayIdx = info->configKey.storage + info->context.ldbid ;
177
178    //if(arrayIdx <= DbTableSize)
179    if(arrayIdx < DbTableSize)
180    {
181       if(gHandlesDBCreated[arrayIdx][info->configKey.policy] == 0)
182       {
183
184          char path[DbPathMaxLen] = {0};
185
186          if(PersistencePolicy_wt == info->configKey.policy)
187          {
188             snprintf(path, DbPathMaxLen, "%s%s", dbPath, gLocalWt);
189          }
190          else if(PersistencePolicy_wc == info->configKey.policy)
191          {
192             snprintf(path, DbPathMaxLen, "%s%s", dbPath, gLocalCached);
193          }
194          else
195          {
196             handleDB = -2;
197          }
198
199          if (handleDB == -1)
200          {
201             handleDB = persComDbOpen(path, 0x01);
202             if(handleDB >= 0)
203             {
204                gHandlesDB[arrayIdx][info->configKey.policy] = handleDB ;
205                gHandlesDBCreated[arrayIdx][info->configKey.policy] = 1;
206             }
207             else
208             {
209                DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_get ==> persComDbOpen() failed"));
210             }
211          }
212          else
213          {
214             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_get ==> wrong policy! Cannot extend dbPath wit database."));
215          }
216       }
217       else
218       {
219          handleDB = gHandlesDB[arrayIdx][info->configKey.policy];
220       }
221    }
222    else
223    {
224       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_get ==> invalid storage type"), DLT_STRING(dbPath));
225    }
226
227
228
229    return handleDB;
230 }
231
232
233 void database_close(PersistenceInfo_s* info)
234 {
235    int arrayIdx = info->configKey.storage + info->context.ldbid;
236
237    if(info->configKey.storage <= PersistenceStorage_shared )
238    {
239       int iErrorCode = persComDbClose(gHandlesDB[arrayIdx][info->configKey.policy]) ;
240       if (iErrorCode < 0)
241       {
242          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_close ==> persComDbClose() failed"));
243       }
244       else
245       {
246         gHandlesDBCreated[arrayIdx][info->configKey.policy] = 0;
247       }
248    }
249    else
250    {
251       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_close ==> invalid storage type"), DLT_INT(info->context.ldbid ));
252    }
253 }
254
255 void database_close_all()
256 {
257    int i = 0;
258
259    for(i=0; i<DbTableSize; i++)
260    {
261       // close write cached database
262       if(gHandlesDBCreated[i][PersistencePolicy_wc] == 1)
263       {
264          int iErrorCode = persComDbClose(gHandlesDB[i][PersistencePolicy_wc]);
265          if (iErrorCode < 0)
266          {
267             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_close_all => failed to close db => persComDbClose"));
268          }
269          else
270          {
271              gHandlesDBCreated[i][PersistencePolicy_wc] = 0;
272          }
273       }
274
275       // close write through database
276       if(gHandlesDBCreated[i][PersistencePolicy_wt] == 1)
277       {
278          int iErrorCode = persComDbClose(gHandlesDB[i][PersistencePolicy_wt]);
279          if (iErrorCode < 0)
280          {
281             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_close_all => failed to close db => persComDbClose"));
282          }
283          else
284          {
285             gHandlesDBCreated[i][PersistencePolicy_wt] = 0;
286          }
287       }
288    }
289 }
290
291
292
293 int persistence_get_data(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
294 {
295    int read_size = -1;
296    int ret_defaults = -1;
297
298    if(   PersistenceStorage_shared == info->configKey.storage
299       || PersistenceStorage_local == info->configKey.storage)
300    {
301       int handleDB = database_get(info, dbPath);
302       if(handleDB >= 0)
303       {
304          read_size = persComDbReadKey(handleDB, key, (char*)buffer, buffer_size) ;
305          if(read_size < 0)
306          {
307             read_size = pers_get_defaults(dbPath, key, buffer, buffer_size, PersGetDefault_Data); /* 0 ==> Get data */
308          }
309       }
310    }
311    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
312    {
313       int idx =  custom_client_name_to_id(dbPath, 1);
314       char workaroundPath[128];  // workaround, because /sys/ can not be accessed on host!!!!
315       snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath  );
316
317       if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_get_data != NULL) )
318       {
319          char pathKeyString[128] = {0};
320          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
321          {
322             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
323          }
324          else
325          {
326             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
327          }
328          read_size = gPersCustomFuncs[idx].custom_plugin_get_data(pathKeyString, (char*)buffer, buffer_size);
329       }
330       else
331       {
332          read_size = EPERS_NOPLUGINFUNCT;
333       }
334
335       if (1 > read_size) /* Try to get default values */
336       {
337          info->configKey.policy = PersistencePolicy_wc;                 /* Set the policy */
338          info->configKey.type   = PersistenceResourceType_key;  /* Set the type */
339          (void)get_db_path_and_key(info, key, NULL, dbPath);
340          DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Plugin data not available. Try to get default data of key:"),
341                                             DLT_STRING(key));
342          ret_defaults = pers_get_defaults(dbPath, key, buffer, buffer_size, PersGetDefault_Data);
343          if (0 < ret_defaults)
344          {
345                  read_size = ret_defaults;
346          }
347       }
348    }
349    return read_size;
350 }
351
352
353
354 int persistence_set_data(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
355 {
356    int write_size = -1;
357
358    if(   PersistenceStorage_local == info->configKey.storage
359       || PersistenceStorage_shared == info->configKey.storage )
360    {
361       int handleDB = -1 ;
362
363
364       handleDB = database_get(info, dbPath);
365       if(handleDB >= 0)
366       {
367          write_size = persComDbWriteKey(handleDB, key, (char*)buffer, buffer_size) ;
368          if(write_size < 0)
369          {
370             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_set_data ==> persComDbWriteKey() failure"));
371          }
372          else
373          {
374             if(PersistenceStorage_shared == info->configKey.storage)
375             {
376                int rval = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
377                if(rval <= 0)
378                {
379                   DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_set_data ==> failed to send notification signal"));
380                   write_size = rval;
381                }
382             }
383          }
384
385       }
386       else
387       {
388          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_set_data ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
389          write_size = EPERS_NOPRCTABLE;
390       }
391    }
392    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
393    {
394       int idx = custom_client_name_to_id(dbPath, 1);
395       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_set_data != NULL) )
396       {
397          char pathKeyString[128] = {0};
398          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
399          {
400             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
401          }
402          else
403          {
404             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
405          }
406          write_size = gPersCustomFuncs[idx].custom_plugin_set_data(pathKeyString, (char*)buffer, buffer_size);
407
408          if ((0 < write_size) && ((unsigned int)write_size == buffer_size)) /* Check return value and send notification if OK */
409          {
410             int rval = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
411             if(rval <= 0)
412             {
413                DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_set_data ==> failed to send notification signal"));
414                write_size = rval;
415             }
416          }
417       }
418       else
419       {
420          write_size = EPERS_NOPLUGINFUNCT;
421       }
422    }
423    return write_size;
424 }
425
426
427
428 int persistence_get_data_size(char* dbPath, char* key, PersistenceInfo_s* info)
429 {
430    int read_size = -1;
431    int ret_defaults = -1;
432
433    if(   PersistenceStorage_shared == info->configKey.storage
434       || PersistenceStorage_local == info->configKey.storage)
435    {
436       int handleDB = database_get(info, dbPath);
437       if(handleDB >= 0)
438       {
439          read_size = persComDbGetKeySize(handleDB, key);
440          if(read_size < 0)
441          {
442             read_size = pers_get_defaults(dbPath, key, NULL, 0, PersGetDefault_Size);
443          }
444       }
445    }
446    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
447    {
448       int idx = custom_client_name_to_id(dbPath, 1);
449       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_get_size != NULL) )
450       {
451          char pathKeyString[128] = {0};
452          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
453          {
454             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
455          }
456          else
457          {
458             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
459          }
460          read_size = gPersCustomFuncs[idx].custom_plugin_get_size(pathKeyString);
461       }
462       else
463       {
464          read_size = EPERS_NOPLUGINFUNCT;
465       }
466
467       if (1 > read_size)
468       {
469          info->configKey.policy = PersistencePolicy_wc;                 /* Set the policy */
470          info->configKey.type   = PersistenceResourceType_key;  /* Set the type */
471          (void)get_db_path_and_key(info, key, NULL, dbPath);
472          DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Plugin data not available. Try to get size of default data for key:"),
473                                             DLT_STRING(key));
474          ret_defaults = pers_get_defaults(dbPath, key, NULL, 0, PersGetDefault_Size);
475          if (0 < ret_defaults)
476          {
477                  read_size = ret_defaults;
478          }
479       }
480    }
481    return read_size;
482 }
483
484
485
486 int persistence_delete_data(char* dbPath, char* key, PersistenceInfo_s* info)
487 {
488    int ret = 0;
489    if(PersistenceStorage_custom != info->configKey.storage)
490    {
491       int handleDB = database_get(info, dbPath);
492       if(handleDB >= 0)
493       {
494          ret = persComDbDeleteKey(handleDB, key) ;
495          if(ret < 0)
496          {
497             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_delete_data => persComDbDeleteKey failed: "), DLT_STRING(key));
498             if(PERS_COM_ERR_NOT_FOUND == ret)
499             {
500                 ret = EPERS_NOKEY ;
501             }
502             else
503             {
504                 ret = EPERS_DB_ERROR_INTERNAL ;
505             }
506          }
507
508          if(PersistenceStorage_shared == info->configKey.storage)
509          {
510             pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
511          }
512       }
513       else
514       {
515          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_delete_data ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
516          ret = EPERS_NOPRCTABLE;
517       }
518    }
519    else   // custom storage implementation via custom library
520    {
521       int idx = custom_client_name_to_id(dbPath, 1);
522       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_delete_data != NULL) )
523       {
524          char pathKeyString[128] = {0};
525          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
526          {
527             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
528          }
529          else
530          {
531             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
532          }
533          ret = gPersCustomFuncs[idx].custom_plugin_delete_data(pathKeyString);
534
535          if(0 <= ret) /* Check return value and send notification if OK */
536          {
537             pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
538          }
539       }
540       else
541       {
542          ret = EPERS_NOPLUGINFUNCT;
543       }
544    }
545    return ret;
546 }
547
548
549 int persistence_notify_on_change(const char* key, unsigned int ldbid, unsigned int user_no, unsigned int seat_no,
550                                  pclChangeNotifyCallback_t callback, PersNotifyRegPolicy_e regPolicy)
551 {
552    int rval = 0;
553
554    if(regPolicy < Notify_lastEntry)
555    {
556       snprintf(gNotifykey, DbKeyMaxLen, "%s", key);
557       gNotifyLdbid  = ldbid;     // to do: pass correct ==> JUST TESTING!!!!
558       gNotifyUserNo = user_no;
559       gNotifySeatNo = seat_no;
560       gNotifyReason = regPolicy;
561
562       if(regPolicy == Notify_register)
563       {
564          // assign callback
565          gChangeNotifyCallback = callback;
566       }
567       else if(regPolicy == Notify_unregister)
568       {
569          // remove callback
570          gChangeNotifyCallback = NULL;
571       }
572
573       if(-1 == deliverToMainloop(CMD_REG_NOTIFY_SIGNAL, 0, 0))
574       {
575          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_notify_on_change => failed to write to pipe"), DLT_INT(errno));
576          rval = -1;
577       }
578    }
579    else
580    {
581       rval = -1;
582    }
583
584    return rval;
585 }
586
587
588
589
590
591
592 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, pclNotifyStatus_e reason)
593 {
594    int rval = 1;
595    if(reason < pclNotifyStatus_lastEntry)
596    {
597       snprintf(gNotifykey,  DbKeyMaxLen,       "%s", key);
598
599       gNotifyLdbid  = context->ldbid;     // to do: pass correct ==> JUST TESTING!!!!
600       gNotifyUserNo = context->user_no;
601       gNotifySeatNo = context->seat_no;
602       gNotifyReason = reason;
603
604       if(-1 == deliverToMainloop(CMD_SEND_NOTIFY_SIGNAL, 0,0) )
605       {
606          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_send_Notification_Signal => failed to write to pipe"), DLT_INT(errno));
607          rval = EPERS_NOTIFY_SIG;
608       }
609    }
610    else
611    {
612       rval = EPERS_NOTIFY_SIG;
613    }
614
615    return rval;
616 }
617
618
619 void pers_rct_close_all()
620 {
621    int i = 0;
622
623    // close all open persistence resource configuration tables
624    for(i=0; i< PrctDbTableSize; i++)
625    {
626         if(gResource_table[i] != -1)
627         {
628                         if(persComRctClose(gResource_table[i]) != 0)
629                         {
630                                 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("process_prepare_shutdown => failed to close db => index:"), DLT_INT(i));
631                         }
632
633                         gResource_table[i] = -1;
634         }
635    }
636 }
637