Revert "Remove TPCS and TWPServer features"
[platform/upstream/csf-framework.git] / framework / TPCSSerDaemon.c
1 /**
2  * Methods supported in TPCS (Tizen Plugin Control Service)
3  */
4
5 #include <dirent.h>
6 #include <dlfcn.h>
7 #include <errno.h>
8 #include <ftw.h>
9 #include <libxml/parser.h>
10 #include <libxml/tree.h>
11 #include <libxml/xmlreader.h>
12 #include <libxml/xmlwriter.h>
13 #include <libxml/xpath.h>
14 #include <libxml/xpathInternals.h>
15 #include <pthread.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22
23 #include "Debug.h"
24 #include "IpcServer.h"
25 #include "IpcForkDaemon.h"
26 #include "TPCSSerDaemon.h"
27
28 /**
29  * This daemon provides four services to manage plugins.
30  * InstallPlugin, UninstallPlugin, SetActivePlugin, GetInfoPlugin
31  *
32  * It maintains config.xml that has the plugin info.
33  * It will recover the config.xml if it is corrupted.
34  *
35  * During the services, the update config.xml and set up the symbolic link of the library is an
36  * atomic action.
37  * Daemon will store the config.xml in the buffer. When running each method, the buffer config.xml
38  * is copied to pData and being update inside the method.
39  * Except the GetInfoPlugin(), all other methods serializing when updating the config.xml.
40  */
41
42 /**
43  * Common Utils, TODO: move to Utils.c
44  *
45  */
46
47 typedef struct _ConfigBuf
48 {
49     xmlDoc *pConfigBuffer;
50     pthread_mutex_t configLock;
51 } ConfigBuf;
52
53 static void GetNSURI(xmlDoc *pXmlDoc, xmlChar **pns, xmlChar **uri);
54 static void GetConfigElements(xmlDoc **pXmlDoc, xmlChar *pXPath, int *size, char ***content);
55 static int WriteXmlToFile(xmlDoc *pXmlDoc, const char* filename);
56 static int UpdatePluglibList(const char *appPath, xmlDoc **pXmlDoc, const char *appId);
57 static int ActivePlugin(ConfigBuf *pBuf, xmlDoc **pXmlCp, const xmlChar *appId);
58 static void SetSuccessReturn(int *argc, char ***argv);
59 static void SetFailureReturn(int *argc, char ***argv);
60 static void CleanupArray(char*** pArr, int len);
61 static int EndsWith(char const *hay, char const *needle);
62
63 /**
64  * Local functions declaration.
65  */
66 static int HasTag(const char *pTag, const char *pFileName, const char *xpath);
67 int UpdateNode(const xmlChar* content, xmlDoc **pDoc, const xmlChar *xpathNodeParent,
68                const char* appID);
69
70 static void SetReturn(int *res_argc, char ***res_argv, char *val)
71 {
72     if (val)
73     {
74         *res_argv = calloc(1, sizeof(char*));
75         if (*res_argv)
76         {
77             (*res_argv)[0] = strdup((const char*) val);
78             if ((*res_argv)[0])
79             {
80                 *res_argc = 1;
81                 return;
82             }
83         }
84
85         free(*res_argv);
86         *res_argc = 0;
87     }
88 }
89
90 static void SetSuccessReturn(int *res_argc, char ***res_argv)
91 {
92     SetReturn(res_argc, res_argv, RETURN_SUCCESS);
93 }
94
95 static void SetFailureReturn(int *res_argc, char ***res_argv)
96 {
97     SetReturn(res_argc, res_argv, RETURN_FAILURE);
98 }
99
100 int SearchNodeN(const xmlChar *xpath, xmlDoc *pXmlDoc, xmlXPathObject **pXPathObj)
101 {
102     DDBG("searchNode :%s\n", xpath);
103     int result = -1;
104     xmlXPathContextPtr pXPathCtx;
105
106     pXPathCtx = xmlXPathNewContext(pXmlDoc);
107     if (pXPathCtx == NULL)
108         return result;
109
110     xmlChar *pns = NULL;
111     xmlChar *puri = NULL;
112     GetNSURI(pXmlDoc, &pns, &puri);
113
114     if (pns != NULL && puri != NULL)
115     {
116         if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0)
117             return result;
118     }
119
120     //Evaluate xpath expression
121     *pXPathObj = xmlXPathEvalExpression(xpath, pXPathCtx);
122     DDBG("============== XPATHobj address:%p\n", *pXPathObj);
123
124     if (*pXPathObj == NULL)
125     {
126         DDBG("Cannot find node:%s\n", xpath);
127         free(pns);
128         free(puri);
129         return result;
130     }
131
132     result = 0;
133
134     free(pns);
135     free(puri);
136
137     xmlXPathFreeContext(pXPathCtx);
138     return result;
139
140 }
141
142 // Dynamically load the library, get the product name, vendor name and version number, then
143 // update the xml file.
144 int InsertNode(xmlDoc **pDoc, const xmlChar *xpathNodeParent, const char *content)
145 {
146     DDBG("insert node :%s\n", "==============");
147     int result = -1;
148     xmlXPathContext *pXPathCtx;
149     xmlXPathObject *pXPathObj;
150
151     pXPathCtx = xmlXPathNewContext(*pDoc);
152     if (pXPathCtx != NULL)
153     {
154         xmlChar *pns = NULL;
155         xmlChar *puri = NULL;
156         GetNSURI(*pDoc, &pns, &puri);
157         if (pns != NULL && puri != NULL)
158         {
159             if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0)
160             {
161                 DDBG("Cannot register xpath :%s\n", "");
162                 return result;
163             }
164         }
165
166         // Evaluate xpath expression
167         pXPathObj = xmlXPathEvalExpression(xpathNodeParent, pXPathCtx);
168         if (pXPathObj != NULL)
169         {
170             xmlNodeSet *pNodeSet = pXPathObj->nodesetval;
171             int size;
172             size = pNodeSet ? pNodeSet->nodeNr : 0;
173             if (size == 1) // Should find only one node
174             {
175                 // Get xmlnode
176                 xmlDoc *pPlugDoc = xmlReadMemory(content, strlen(content), NULL, NULL, 0);
177                 DDBG("plugdoc :%s\n", content);
178
179                 if (pPlugDoc != NULL)
180                 {
181                     xmlNode *newnode = xmlDocCopyNode(xmlDocGetRootElement(pPlugDoc),
182                                                       pNodeSet->nodeTab[0]->doc,1);
183                     DDBG("=========== pplugdoc address:%p\n", pPlugDoc);
184
185                     xmlFreeDoc(pPlugDoc);
186                     //xmlNode *addNode = xmlAddChildList(pNodeSet->nodeTab[0], newnode->children);
187                     xmlNode *addNode = xmlAddChildList(pNodeSet->nodeTab[0], newnode->children);
188                     DDBG("=========== new node addr:%p\n", newnode);
189
190                     if (addNode != NULL)
191                     {
192                         result = 0;
193                         DDBG("FREE new node:%p\n", newnode);
194                         newnode->children = NULL;
195                         xmlFreeNode(newnode);
196                     }
197                 }
198             }
199         }
200         free(pns);
201         free(puri);
202         pns = NULL;
203         puri = NULL;
204
205         xmlXPathFreeObject(pXPathObj);
206         xmlXPathFreeContext(pXPathCtx);
207     }
208
209     return result;
210 }
211
212 int RemoveNodeParent(xmlDoc **pDoc, const xmlChar *path, const char* value)
213 {
214     int result = -1;
215     if (*pDoc != NULL)
216     {
217         xmlXPathContext *pXPathCtx;
218         xmlXPathObject *pXPathObj;
219
220         pXPathCtx = xmlXPathNewContext(*pDoc);
221
222         if (pXPathCtx != NULL)
223         {
224             xmlChar *pns = NULL;
225             xmlChar *puri = NULL;
226             GetNSURI(*pDoc, &pns, &puri);
227             if (pns != NULL && puri != NULL)
228             {
229                 if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0)
230                 {
231                     return result;
232                 }
233             }
234             pXPathObj = xmlXPathEvalExpression(path, pXPathCtx);
235             if (pXPathObj != NULL)
236             {
237                 xmlNodeSet *pNodeSet = pXPathObj->nodesetval;
238
239                 int size;
240                 size = pNodeSet ? pNodeSet->nodeNr : 0;
241                 int i = 0;
242                 xmlNode *cur;
243                 xmlNode *parent;
244                 for (; i < size; i++)
245                 {
246                     cur = pNodeSet->nodeTab[i]->children;
247                     if (strcmp((const char*)cur->content, value) == 0)
248                     {
249                         parent = cur->parent->parent;
250                         xmlUnlinkNode(parent);
251                         break;
252                     }
253                     else
254                         DDBG("THEY ARE NOT EQUAL:%s\n", value);
255
256                 }
257                 result = 0;
258                 xmlXPathFreeObject(pXPathObj);
259             }
260             free(pns);
261             free(puri);
262             pns = NULL;
263             puri = NULL;
264             xmlXPathFreeContext(pXPathCtx);
265         }
266     }
267     return result;
268 }
269
270 int PrintXmlDoc(xmlDocPtr pDoc)
271 {
272 #ifdef DEBUG
273     int result = 0;
274     int xmlSize;
275     xmlChar *xmlMem;
276     xmlDocDumpFormatMemory(pDoc, &xmlMem, &xmlSize, 0);
277     DDBG("pdoc content:%s\n", xmlMem);
278     free(xmlMem);
279     return result;
280 #else
281     return 0;
282 #endif
283 }
284
285 int UpdateConfigFile(ConfigBuf **pData, xmlDoc **pXmlCp)
286 {
287     int result = -1;
288
289     if (pData && *pData)
290     {
291         pthread_mutex_lock(&((*pData)->configLock));
292         if (pXmlCp && *pXmlCp)
293         {
294             result = WriteXmlToFile(*pXmlCp, CONFIG_FILE_NEW_W_PATH);
295             if (result == 0)
296             {
297                 DDBG("==============update config file%s\n", " ");
298                 PrintXmlDoc(*pXmlCp);
299                 result = WriteXmlToFile(*pXmlCp, CONFIG_FILE_W_PATH);
300                 if (result == 0)
301                 {
302                     //delete config new file
303                     DDBG("REMOVE file:%s\n", CONFIG_FILE_NEW_W_PATH);
304                     result = remove(CONFIG_FILE_NEW_W_PATH);
305
306                      if ((*pData)->pConfigBuffer != NULL)
307                          xmlFreeDoc((*pData)->pConfigBuffer);
308
309                     (*pData)->pConfigBuffer = xmlCopyDoc(*pXmlCp, DO_RECURSIVE_COPY);
310                 }
311             }
312         }
313         pthread_mutex_unlock(&((*pData)->configLock));
314     }
315     return result;
316 }
317
318 static int UpdatePlugin(const char *libname, xmlDoc **pXmlDoc, const char* appId)
319 {
320     DDBG("~~~~~ UPDATE plugin: libname:%s, appID:%s\n", libname, appId);
321     int result = -1;
322     void *pHandle = NULL;
323
324     pHandle = dlopen(libname, RTLD_LAZY);
325     if (pHandle == NULL)
326     {
327         char *error;
328         if ((error = dlerror()) != NULL)
329             DDBG("failed to open lib: %s, error:%s\n", libname, error);
330     }
331     else
332     {
333         char *pInfo = NULL;
334         char* (*getInfo)(void);
335
336         DDBG("open library:%s\n", libname);
337         getInfo = dlsym(pHandle, "TCSGetInfo");
338
339         if (getInfo == NULL)
340         {
341             char *error;
342             if ((error = dlerror()) != NULL)
343                 DDBG("SOMETHID :%s\n", error);
344         }
345         else
346         {
347             pInfo = strdup(getInfo());
348             if (pInfo != NULL)
349             {
350                 // Update node tree
351                 result = UpdateNode((const xmlChar*) pInfo, pXmlDoc, (const xmlChar*) XPATH_PLUGINS,
352                                     appId);
353                 free(pInfo);
354                 pInfo = NULL;
355             }
356         }
357
358         dlclose(pHandle);
359     }
360     return result;
361 }
362
363 /**
364  * Get plugins node, should only have one node. After that, Check if has the node with appId, if so,
365  * remove this node. otherwise, add the new node.
366  */
367 int UpdateNode(const xmlChar* content, xmlDoc **pDoc, const xmlChar *xpathNodeParent,
368                const char* appId)
369 {
370     int result = -1;
371
372     // Remove the plugin first if its appId same
373     char appidpath[GENERIC_STRING_SIZE];
374     strncpy(appidpath, (const char*) XPATH_PLUGINS_PLUG, sizeof(appidpath));
375     result = RemoveNodeParent(pDoc, (const xmlChar *)appidpath, appId);
376
377     result = InsertNode(pDoc, xpathNodeParent, (const char*)content);
378     return result;
379 }
380
381 static int ActivePlugin(ConfigBuf *pBuf, xmlDoc **pXmlCp, const xmlChar *appId)
382 {
383     int result = -1;
384
385     xmlXPathObject *pObj = NULL;
386     result = SearchNodeN((const xmlChar *)XPATH_ACTIVE_PLUGIN, *pXmlCp, &pObj);
387
388     PrintXmlDoc(*pXmlCp);
389
390     if (result == -1)
391         return result;
392
393     result = -1;
394     xmlNodeSet *pNodeSet = NULL;
395     if (pObj)
396     {
397         pNodeSet = pObj->nodesetval;
398     }
399
400     // If appId is empty, disable the active plugin, update activePlugin Node to None
401     if (strcmp((const char*)appId, APP_ID_NULL) == 0)
402     {
403         pthread_mutex_lock(&(pBuf->configLock));
404         result = unlink(SYSLINK_PLUG_PATH);
405         pthread_mutex_unlock(&(pBuf->configLock));
406
407                 if (pNodeSet)
408                 {
409                         if (pNodeSet->nodeTab[0])
410                         {
411                                 xmlNode *cur = pNodeSet->nodeTab[0];
412                                 xmlNodeSetContent(cur, (xmlChar*)ACTIVE_NONE);
413                                 DDBG("GET node content :%s\n", cur->content);
414                         }
415                 }
416                 result = 0;
417     }
418     else
419     {
420         // Get the plugin path from the appPath, set symbolic link for the plugin, update the xmlDoc
421         int count;
422         char **paths = NULL;
423         GetConfigElements(pXmlCp, (xmlChar *) XPATH_APP_PATHS, &count, &paths);
424         int i = 0;
425         for (; i < count; i++)
426         {
427             char appPath[FILE_NAME_MAX_SIZE];
428             snprintf(appPath, FILE_NAME_MAX_SIZE, "%s%s%s%s", paths[i], "/", appId,
429                      PLUGIN_DEFAULT_DIR_NAME);
430
431             //Found the app path
432             struct stat info;
433             if (stat(appPath, &info) != 0)
434                 continue;
435
436             pthread_mutex_lock(&(pBuf->configLock));
437             unlink(SYSLINK_PLUG_PATH);
438             result = symlink(appPath, SYSLINK_PLUG_PATH);
439             pthread_mutex_unlock(&(pBuf->configLock));
440
441             DDBG("set symbolic link result:from :%s to %s result:%d\n", appPath, SYSLINK_PLUG_PATH, result);
442             if (result == 0 && pNodeSet)
443             {
444                 //update active Id node
445                 xmlNode *cur = pNodeSet->nodeTab[0];
446                 xmlNodeSetContent(cur, appId);
447                 DDBG("GET NOde conten :%s\n", cur->content);
448
449                 //xmlFreeNode(cur);
450                 DDBG("RETURn from active plu g  0000:%d\n", result);
451                 PrintXmlDoc(*pXmlCp);
452
453             }
454             DDBG("RETURn from active plu g  0000  000000:%d\n", result);
455             //xmlXPathFreeNodeSet(pNodeSet);
456             break;
457         }
458         DDBG("RETURn from active plu g  0000  0111 :%d\n", result);
459         CleanupArray(&paths, count);
460         xmlXPathFreeObject(pObj);
461
462     }
463
464     DDBG("RETURn from active plug :%d\n", result);
465     return result;
466 }
467
468 /**
469  * @appPath: /opt/usr/app/appId
470  */
471 static int UpdatePluglibList(const char *appPath, xmlDoc **pXmlDoc, const char* appId)
472 {
473     DDBG("=========================update plugin lib path:%s\n", appPath);
474
475     int result = -1;
476     char plugPath[FILE_NAME_MAX_SIZE];
477
478     sprintf(plugPath, "%s%s", appPath, PLUGIN_DEFAULT_DIR_NAME);
479     DIR *pDir;
480     struct dirent *pDirEnt;
481
482     pDir = opendir(plugPath);
483     DDBG("OPEN DIR:%s\n", plugPath);
484     if (pDir)
485     {
486         //open directories
487         while ((pDirEnt = readdir(pDir)) != NULL)
488         {
489             if (strcmp(pDirEnt->d_name, ".") == 0 || strcmp(pDirEnt->d_name, "..") == 0)
490                 continue;
491
492             if (pDirEnt->d_type == DT_REG)
493             {
494                 // load the library, update xml node
495                 char libPath[FILE_NAME_MAX_SIZE];
496                 sprintf(libPath, "%s%s%s", plugPath, "/", pDirEnt->d_name);
497                 result = UpdatePlugin(libPath, pXmlDoc, appId);
498                 break;
499             }
500             else
501             {
502                 DDBG("IT IS NO regular file:%s\n", pDirEnt->d_name);
503                 continue;
504             }
505         }
506         closedir(pDir);
507
508     }
509     DDBG("RESTURN  from update pluglib list :%d\n", result);
510     return result;
511 }
512
513 /**
514  *
515  */
516 int GetInfoPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc,
517                   CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
518 {
519     // check data pass is valid xml
520     xmlDoc *pXml = (xmlDoc*) *((xmlDoc**) pData);
521     *res_argc = FN_GET_INFO_RTN_COUNT;
522     *res_argv = calloc(1, sizeof(char*) * FN_GET_INFO_RTN_COUNT);
523     if (*res_argv == NULL)
524         goto no_memory;
525
526     (*res_argv)[0] = strdup((const char*) RETURN_SUCCESS);
527     if ((*res_argv)[0] != NULL)
528     {
529         xmlChar *xmlMem;
530         int xmlSize;
531         xmlDocDumpFormatMemory(pXml, &xmlMem, &xmlSize, 0);
532         if (xmlMem != NULL)
533         {
534             DDBG("size is: %d, xmlmem is ** :%s\n", xmlSize, xmlMem);
535             (*res_argv)[1] = strdup((const char*) xmlMem);
536             if ((*res_argv)[1] == NULL)
537             {
538                 DDBG("Not enough memory in :%s\n", "set xmlmem in return");
539                 free((*res_argv)[0]);
540                 (*res_argv)[0] = NULL;
541                 goto invalid_xml;
542             }
543             xmlFree(xmlMem);
544             xmlMem = NULL;
545         }
546         else
547             goto invalid_xml;
548     }
549     else
550     {
551         DDBG("failed to copy return_successS:%s\n", "");
552         goto no_memory;
553     }
554     DDBG("successfully finished:%s\n", "GetInfoPlugin");
555     return 0;
556
557     invalid_xml:
558     // get recoverred config.xml and return
559     no_memory:
560     *res_argc = 0;
561     return 0;
562 }
563
564 /**
565  * pData is the buffer of config.xml,
566  * ** apply lock
567  *   if copy pData to pData.cp success,
568  *     if update pData.cp with the newly installed info
569  *       if successfully update the symbolic link,
570  *         if write pData.cp to config.xml.new
571  *           if switch config.xml.new to config.xml
572  *           else do nothing, wait for next time update
573  *         else do nothing, wait for next time udpate
574  *         copy pData.cp to pData, free pData.cp
575  *       else return failure update
576  *     ** unlock
577  *
578  *     @req_argc: 1
579  *     @req_argv: app installation path, i.e. /opt/usr/apps/appID
580  */
581 int InstallPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc,
582                   CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
583 {
584     DDBG("InstallPlugin for serverstub:%s\n", req_argv[0]);
585     int result = -1;
586     ConfigBuf *pBuf = *((ConfigBuf **) pData);
587     pthread_mutex_lock(&(pBuf->configLock));
588     xmlDoc *pXml = (*((ConfigBuf **) pData))->pConfigBuffer;
589     xmlDoc *pXmlCp = xmlCopyDoc(pXml, DO_RECURSIVE_COPY);
590     pthread_mutex_unlock(&(pBuf->configLock));
591
592     if (pXmlCp != NULL)
593     {
594         if (req_argc == 1 && req_argv != NULL)
595         {
596             // Get apppath list
597             int count;
598             char **paths = NULL;
599             GetConfigElements(&pXmlCp, (xmlChar *) XPATH_APP_PATHS, &count, &paths);
600             int i = 0;
601             for (; i < count; i++)
602             {
603                 char appPath[FILE_NAME_MAX_SIZE];
604                 sprintf(appPath, "%s%s%s", paths[i], "/", req_argv[0]);
605
606                 PrintXmlDoc(pXmlCp);
607                 if (UpdatePluglibList(appPath, &pXmlCp, req_argv[0]) == 0)
608                 {
609                     if (ActivePlugin(*((ConfigBuf**) pData), &pXmlCp, (const xmlChar *)req_argv[0]) == 0)
610                     {
611                         // Write to new file
612                         DDBG("Success cpy xml 2:%s\n", appPath);
613
614                         *res_argc = FN_INSTALL_PLUG_RTN_COUNT;
615                         *res_argv = calloc(1, sizeof(char*) * FN_INSTALL_PLUG_RTN_COUNT);
616                         if (*res_argv == NULL)
617                             goto no_memory;
618
619                         (*res_argv)[0] = strdup((const char*) RETURN_SUCCESS);
620                         if ((*res_argv)[0] == NULL)
621                             goto no_memory;
622
623                         xmlChar *xmlMem = NULL;
624                         int xmlSize;
625
626                         xmlDocDumpFormatMemory(pXmlCp, &xmlMem, &xmlSize, 0);
627                         DDBG("XMLmEM address: %p\n", xmlMem);
628                         if (xmlMem != NULL)
629                         {
630                             (*res_argv)[1] = strdup((const char*) xmlMem);
631                             DDBG("return from install plug:%s\n", (*res_argv)[1]);
632                             free(xmlMem);
633                             xmlMem = NULL;
634
635                             if ((*res_argv)[1] != NULL)
636                             {
637                                 result = UpdateConfigFile(pData, &pXmlCp);
638                                 break;
639                             }
640                         }
641                     }
642                 }
643             }
644             CleanupArray(&paths, count);
645         }
646     }
647     xmlFreeDoc(pXmlCp);
648
649     if (result == -1)
650         goto failure;
651     else
652     {
653         return result;
654     }
655
656 no_memory:
657     xmlFreeDoc(pXmlCp);
658
659 failure:
660     *res_argc = 1;
661     *res_argv = calloc(1, sizeof(char*));
662     (*res_argv)[0] = strdup((const char*) RETURN_FAILURE);
663     return result;
664 }
665
666 /**
667  * If it is active plugin, unlink the syslink, and update active element with AppId to None.
668  * If the request plugin is not active one, remove it from the plugin list
669  */
670 int UninstallPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc,
671                     CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
672 {
673     int result = -1;
674     xmlDoc *pXml = NULL;
675     xmlDoc *pXmlCp = NULL;
676     ConfigBuf *pBuf = NULL;
677     xmlXPathObject *pObj = NULL;
678
679     if (req_argc != 1 || req_argv == NULL)
680         goto failure;
681
682     pBuf = *((ConfigBuf **) pData);
683
684     pthread_mutex_lock(&(pBuf->configLock));
685     pXml = pBuf->pConfigBuffer;
686     pXmlCp = xmlCopyDoc(pXml, DO_RECURSIVE_COPY);
687     pthread_mutex_unlock(&(pBuf->configLock));
688
689     if (pXmlCp == NULL)
690         goto failure;
691
692     result = SearchNodeN((const xmlChar *)XPATH_ACTIVE_PLUGIN, pXmlCp, &pObj);
693     if (result != 0)
694         goto failure;
695
696     xmlNodeSet *pNodeSet = pObj->nodesetval;
697     xmlNode *pNode = pNodeSet->nodeTab[0];
698     if (pNode == NULL)
699     {
700         DDBG("not such node %s\n", XPATH_ACTIVE_PLUGIN);
701         goto failure;
702     }
703
704     if (pNode->type != XML_ELEMENT_NODE)
705         goto failure;
706
707     // Search for plugin. If found, unlink the plugin. Otherwise, the plugin was already
708     // unlinked and updated in the config file.
709     DDBG("node name:%s, activenode value: %s\n", pNode->name, pNode->children->content);
710     if (strcmp((const char *)pNode->children->content, req_argv[0]) == 0)
711     {
712         pthread_mutex_lock(&(pBuf->configLock));
713         result = unlink(SYSLINK_PLUG_PATH);
714         pthread_mutex_unlock(&(pBuf->configLock));
715
716         if (result != 0 && result != ENOENT)
717             goto failure;
718
719         xmlNodeSetContent(pNode, (const xmlChar *)ACTIVE_NONE);
720     }
721
722     // Remove the plugin node if it is in the plugin list
723     result = RemoveNodeParent(&pXmlCp, (const xmlChar *)XPATH_PLUGINS_PLUG, req_argv[0]);
724     result = UpdateConfigFile((ConfigBuf**) pData, &pXmlCp);
725     if (result != 0)
726     {
727         DDBG("Unable to update config file with uninstall info\n");
728         goto failure;
729     }
730     SetSuccessReturn(res_argc, res_argv);
731     goto cleanup;
732
733 failure:
734     SetFailureReturn(res_argc, res_argv);
735
736 cleanup:
737     if (pObj)
738         xmlXPathFreeObject(pObj);
739     if (pXmlCp)
740         xmlFreeDoc(pXmlCp);
741
742     return result;
743 }
744
745 /**
746  * Copy the xmlDoc
747  * Update the symbolic link if it is not the active plug
748  * Update xmlDoc, save to the tpcs_config.xml
749  */
750 int SetActivePlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc,
751                     CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
752 {
753     DDBG("SetActivePlugin :%s\n", req_argv[0]);
754
755     ConfigBuf *pBuf = NULL;
756     xmlDoc *pXml = NULL;
757     xmlDoc *pXmlCp = NULL;
758     int result = -1;
759
760     if (req_argc != 1 || req_argv == NULL)
761         return result;
762
763     pBuf = *((ConfigBuf **) pData);
764
765     pthread_mutex_lock(&(pBuf->configLock));
766     pXml = pBuf->pConfigBuffer;
767     pXmlCp = xmlCopyDoc(pXml, DO_RECURSIVE_COPY);
768     pthread_mutex_unlock(&(pBuf->configLock));
769
770     if (pXmlCp == NULL)
771         return result;
772
773     PrintXmlDoc(pXmlCp);
774     if ((ActivePlugin(pBuf, &pXmlCp, (const xmlChar *)req_argv[0]) == 0)
775             && UpdateConfigFile((ConfigBuf**) pData, &pXmlCp) == 0)
776     {
777         SetSuccessReturn(res_argc, res_argv);
778         DDBG("==== FINd tha ppid %s\n", req_argv[0]);
779     }
780     else
781     {
782         DDBG("==== **** FINd tha ppid %s\n", req_argv[0]);
783         SetFailureReturn(res_argc, res_argv);
784     }
785
786     xmlFreeDoc(pXmlCp);
787     return result;
788 }
789
790 static int WriteXmlToFile(xmlDoc *pXmlDoc, const char* filename)
791 {
792
793     DDBG("Write xml to file: %s\n", filename);
794     int result = -1;
795     FILE *pfConfig = fopen(filename, "w");
796     if (pfConfig != NULL)
797     {
798         xmlDocDump(pfConfig, pXmlDoc);
799         fclose(pfConfig);
800         result = 0;
801     }
802     return result;
803 }
804
805 static int InitConfigFile(xmlDoc **pXmlDoc)
806 {
807     int result = -1;
808     DDBG("Size of xml doc in memory :%d\n", sizeof(CONFIG_DEFAULT_STRING));
809
810     *pXmlDoc = xmlReadMemory(CONFIG_DEFAULT_STRING, sizeof(CONFIG_DEFAULT_STRING) + 1,
811                              CONFIG_FILE_NAME,
812                              NULL, 0);
813
814     if (*pXmlDoc != NULL)
815     {
816         result = 0;
817     }
818
819     return result;
820 }
821
822 static bool IsValidTPCSConfig(const char *pFileName, xmlDoc **ppXmlDoc)
823 {
824     // Create a parse context
825     bool ret = FALSE;
826     xmlParserCtxt *pParserCtxt = xmlNewParserCtxt();
827     xmlDoc *pXmlDoc;
828     if (pParserCtxt == NULL)
829     {
830         DDBG("%s\n", "======Failed to allocate parser context");
831         return ret;
832     }
833     else
834     {
835         // valid this config file
836             // Parse the file, activating the DTD validation option */
837                 DDBG("------------------ IS VALID config file :%s\n", "---------------------");
838                 pXmlDoc = xmlCtxtReadFile(pParserCtxt, pFileName, NULL, XML_PARSE_DTDVALID);
839                 DDBG("--- 1 pxmldoc address: %p\n", pXmlDoc);
840                 DDBG("file to read:%s\n", pFileName);
841                 PrintXmlDoc(pXmlDoc);
842                 if (pXmlDoc != NULL)
843                 {
844                         // Check if validation succeeded
845                         if (pParserCtxt->valid)
846                         {
847                                 *ppXmlDoc = pXmlDoc;
848                                 DDBG("address of ppxmldoc: %p\n", *ppXmlDoc);
849                                 ret = TRUE;
850                         }
851                 }
852                 else
853                 {
854                         DDBG("NOT VALID file: %s\n", pFileName);
855                 }
856
857         xmlFreeParserCtxt(pParserCtxt);
858         return ret;
859     }
860 }
861
862 /**
863  * Return directory list that has the specified directory within
864  */
865 static void GetDirsHasPath(const char *dir, const char *search_path, int *pCount,
866                            char ***name_w_path, char ***appId)
867 {
868     DIR *pDir = NULL;
869     struct dirent *pDirEnt = NULL;
870
871     if (!dir || !search_path || !pCount || !appId || !name_w_path)
872         return;
873
874     pDir = opendir(dir);
875     *pCount = 0;
876     if (pDir)
877     {
878         char plugPath[FILE_NAME_MAX_SIZE];
879         char appPath[FILE_NAME_MAX_SIZE];
880
881         struct stat info;
882         while ((pDirEnt = readdir(pDir)) != NULL)
883         {
884             if (strcmp(pDirEnt->d_name, ".") == 0 || strcmp(pDirEnt->d_name, "..") == 0)
885             {
886                 continue;
887             }
888             if (pDirEnt->d_type == DT_DIR)
889             {
890                 sprintf(appPath, "%s%s%s", dir, "/", pDirEnt->d_name);
891
892                 sprintf(plugPath, "%s%s", appPath, PLUGIN_DEFAULT_DIR_NAME);
893
894                 if (stat(plugPath, &info) == 0)
895                 {
896                     if (*pCount == 0)
897                     {
898                         *name_w_path = calloc(1, sizeof(char*));
899
900                         if (*name_w_path)
901                         {
902                             (*pCount)++;
903                             (*name_w_path)[0] = strdup((const char*) appPath);
904
905                             if ((*name_w_path)[0] == NULL)
906                                 goto clean_up;
907                         }
908                         else
909                             goto clean_up;
910
911                         *appId = calloc(1, sizeof(char*));
912                         if (*appId)
913                         {
914                             (*appId)[0] = strdup((const char*) pDirEnt->d_name);
915                             DDBG("COUNT 0, name: %s\n", pDirEnt->d_name);
916                             if ((*appId)[0] == NULL)
917                                 goto clean_up;
918                         }
919                     }
920                     else
921                     {
922                         //TODO: all the realloc * size, use chunk
923                         *name_w_path = realloc(*name_w_path, sizeof(char*) * (*pCount + 1));
924                         if (*name_w_path)
925                         {
926                             (*pCount)++;
927                             (*name_w_path)[(*pCount) - 1] = strdup((const char*) appPath);
928                             if ((*name_w_path)[(*pCount) - 1] == NULL)
929                                 goto clean_up;
930
931                             *appId = realloc(*appId, sizeof(char*) * (*pCount + 1));
932                             if (*appId)
933                             {
934                                 (*appId)[*pCount - 1] = strdup((const char*) pDirEnt->d_name);
935                                 if (((*appId)[*pCount - 1]) == NULL)
936                                 {
937                                     goto clean_up;
938                                 }
939                             }
940                             else
941                             {
942                                 goto clean_up;
943                             }
944                         }
945                         else
946                         {
947                             goto clean_up;
948                         }
949                     }
950                 }
951             }
952         }
953
954         goto success;
955     }
956
957 clean_up:
958     CleanupArray(name_w_path, *pCount);
959
960 success:
961     DDBG("CLOSE dir: %s\n", " " );
962     if (pDir)
963         closedir(pDir);
964
965     return;
966 }
967
968 /**
969  *
970  */
971 static void CleanupArray(char*** pArr, int len)
972 {
973     if (pArr)
974     {
975         while (len > 0)
976         {
977             len--;
978             if ((*pArr)[len])
979             {
980                 free((*pArr)[len]);
981                 (*pArr)[len] = NULL;
982             }
983         }
984
985         if (*pArr)
986         {
987             free(*pArr);
988             *pArr = NULL;
989         }
990     }
991 }
992
993 /*
994  * int ftw(const char *dir, int (*fn)(const char *file, const struct stat *sb, int flag), int nopenfd);
995  */
996 int FileTreeCallback(const char *pFile, const struct stat *pStat, int flag)
997 {
998     int result = 0;
999     if (pStat->st_mode & S_IFREG)
1000     {
1001         //DDBG(">>>>>file tree walk :%s, such substring:%s\n", pFile, MANIFEST_FILE_NAME);
1002         if (EndsWith(pFile, MANIFEST_FILE_NAME) == 0)
1003         {
1004             DDBG("FOUNd the file: %s\n", pFile);
1005             // check if it has the plugin tag
1006             if (HasTag(PLUGIN_ANTI_VIRUS_TAG, pFile, XPATH_PLUGIN_CATEGORY) == 0)
1007             {
1008                 // found the library
1009                 DDBG("this app is plugin app:%s\n", pFile);
1010                 result = 1;
1011             }
1012         }
1013     }
1014     return result;
1015 }
1016
1017 /**
1018  * Checks if str ends with needle. Return zero on success otherwise non-zero.
1019  */
1020 static int EndsWith(const char *hay, const char *needle)
1021 {
1022     size_t haylen, needlelen;
1023
1024     if (!hay || !needle)
1025         return -1;
1026
1027     needlelen = strlen(needle);
1028     haylen = strlen(hay);
1029
1030     if (needlelen > haylen)
1031         return -1;
1032
1033     return strncmp(hay + haylen - needlelen, needle, needlelen);
1034 }
1035
1036 static void GetNSURI(xmlDoc *pXmlDoc, xmlChar **pns, xmlChar **uri)
1037 {
1038     xmlNode *root_node = xmlDocGetRootElement(pXmlDoc);
1039
1040     if (root_node)
1041     {
1042         xmlNs *pXmlNS = root_node->ns;
1043         xmlNs *pXmlNSDef = root_node->nsDef;
1044
1045         if (pXmlNS != NULL)
1046         {
1047             if (pXmlNS->prefix != NULL)
1048             {
1049                 *pns = (xmlChar*) strdup((const char*) pXmlNS->prefix);
1050             }
1051             else
1052             {
1053                 DDBG("root node name:%s\n", root_node->name);
1054                 *pns = (xmlChar*) strdup((const char*) root_node->name);
1055             }
1056         }
1057
1058         if (pXmlNSDef != NULL)
1059         {
1060             if (pXmlNSDef->href != NULL)
1061             {
1062                 DDBG("nsdef :%s\n", pXmlNSDef->href);
1063                 *uri = (xmlChar*) strdup((const char*) pXmlNSDef->href);
1064             }
1065         }
1066     }
1067     return;
1068 }
1069
1070 /**
1071  * Get elements from xmlDoc, and output to the count and content
1072  */
1073 static void GetConfigElements(xmlDoc **pXmlDoc, xmlChar *pXPath, int *size, char ***content)
1074 {
1075     DDBG("GetConfigElements in xpath: %s\n", (char*)pXPath);
1076     // Scan all the directories that has av category, update its plugin element in config.xml
1077     xmlXPathContext *pXPathCtx;
1078     xmlXPathObject *pXPathObj;
1079
1080     pXPathCtx = xmlXPathNewContext(*pXmlDoc);
1081     if (pXPathCtx != NULL)
1082     {
1083         xmlChar *pns = NULL;
1084         xmlChar *puri = NULL;
1085         GetNSURI(*pXmlDoc, &pns, &puri);
1086         if (pns != NULL && puri != NULL)
1087         {
1088             if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0)
1089             {
1090                 DDBG("Cannot register xpath :%s\n", "");
1091                 return;
1092             }
1093         }
1094         // Evaluate xpath expression
1095         pXPathObj = xmlXPathEvalExpression(pXPath, pXPathCtx);
1096         if (pXPathObj != NULL)
1097         {
1098             xmlNode *cur;
1099             xmlNodeSet *pNodeSet = pXPathObj->nodesetval;
1100
1101             *size = pNodeSet ? pNodeSet->nodeNr : 0;
1102             if (*size > 0)
1103             {
1104                 int i = 0;
1105                 *content = calloc(1, sizeof(char*) * (*size));
1106                 DDBG("XAPTH OBJCT FOUND:%s, size:%d\n", "", *size);
1107                 if (*content)
1108                 {
1109                     for (; i < *size; i++)
1110                     {
1111                         if (pNodeSet->nodeTab[i]->type == XML_ELEMENT_NODE)
1112                         {
1113                             cur = pNodeSet->nodeTab[i];
1114
1115                             if (*content)
1116                             {
1117                                 DDBG("content; %s\n", cur->children->content);
1118                                 (*content)[i] = strdup((const char*) cur->children->content);
1119                             }
1120                         }
1121                     }
1122                 }
1123                 else
1124                 {
1125                     DDBG("CANNOT FOUND content:%s\n", "");
1126                 }
1127
1128             }
1129             xmlXPathFreeObject(pXPathObj);
1130         }
1131         if (pns)
1132         {
1133             free(pns);
1134             pns = NULL;
1135         }
1136
1137         if (puri)
1138         {
1139             free(puri);
1140             puri = NULL;
1141         }
1142
1143         xmlXPathFreeContext(pXPathCtx);
1144     }
1145 }
1146
1147 static int HasTag(const char *pTag, const char *pFileName, const char *xpath)
1148 {
1149     int result = 1;
1150     xmlDoc *pConfigXml = NULL;
1151
1152     if (!pTag)
1153         return result;
1154
1155     pConfigXml = xmlReadFile(pFileName, NULL, 0);
1156     if (pConfigXml != NULL)
1157     {
1158         int size;
1159         char **pCategory = NULL;
1160         GetConfigElements(&pConfigXml, (xmlChar*) xpath, &size, &pCategory);
1161         if (size > 0)
1162         {
1163             DDBG("size is: %d, category:%s\n", size, pCategory[0]);
1164             int i = 0;
1165             for (; i < size; i++)
1166             {
1167                 if (strcmp(pCategory[i], pTag) == 0)
1168                 {
1169                     result = 0;
1170                     break;
1171                 }
1172             }
1173         }
1174         CleanupArray(&pCategory, size);
1175     }
1176     xmlFreeDoc(pConfigXml);
1177     return result;
1178 }
1179
1180 /*
1181  * config.xml validation
1182  * If config.xml.new exists, and it is valid,
1183  *  if it is consistent with symbolic link, switch this to config.xml
1184  *  else if there is config.xml, and
1185  *   if it is valid
1186  *    if it is consistent with symbolic link, buffer the config.xml
1187  *    else based on the symbolic link, update config.xml, then buffer the config.xml
1188  *   else
1189  *    recover the config.xml by scan all the applications, checking symbolic link, create the
1190  *    config.xml, buffer it.
1191  * Pass the data address to the pData
1192  */
1193 int main(int argc, char **argv)
1194 {
1195     //TODO: make it a daemon
1196
1197 #ifndef DEBUG
1198     fork_daemon();
1199 #endif
1200
1201     //Add methods
1202     //Start TPCS daemon
1203     TSC_SERVER_HANDLE hServer = NULL;
1204     int ret = -1;
1205
1206
1207     fprintf(stderr, "TPCS Service Daemon Started%s\n", "");
1208     //TODO: rename TSC_DBUS_SERVER_PLUGIN_CHANNEL to TSC_DBUS_SERVER_PLUGIN_CHANNEL
1209     if ((hServer = IpcServerOpen(TSC_DBUS_SERVER_PLUGIN_CHANNEL)) != NULL)
1210     {
1211         DDBG("%s", "**** successfully opened server ****\n");
1212         // Write out the DTD validation file
1213         FILE *pDTD = fopen(CONFIG_DTD_FILE_W_PATH, "r");
1214         if (pDTD == NULL)
1215         {
1216             pDTD = fopen(CONFIG_DTD_FILE_W_PATH, "w");
1217             if (pDTD)
1218             {
1219                 fwrite(CONFIG_DEFAULT_DTD_STRING, strlen(CONFIG_DEFAULT_DTD_STRING), 1, pDTD);
1220                 fclose(pDTD);
1221             }
1222             else
1223             {
1224                 goto done;
1225             }
1226         }
1227         else
1228         {
1229             //TODO: close the file, check if the file exists lstat, signature of the file
1230         }
1231
1232         ConfigBuf *pConfigBuf = calloc(1, sizeof(ConfigBuf));
1233         if (pConfigBuf == NULL)
1234             return ret;
1235         ret = pthread_mutex_init(&(pConfigBuf->configLock), NULL);
1236         if (ret == -1)
1237         {
1238             //TODO: memory clean up
1239             free(pConfigBuf);
1240             pConfigBuf = NULL;
1241             return ret;
1242         }
1243
1244         if (IsValidTPCSConfig(CONFIG_FILE_NEW_W_PATH, &(pConfigBuf->pConfigBuffer)))
1245         {
1246             // switch to config.xml
1247             if (rename(CONFIG_FILE_NEW_W_PATH, CONFIG_FILE_W_PATH) == 0)
1248             {
1249                 DDBG("%s has been renamed to :%s\n", CONFIG_FILE_NEW_W_PATH, CONFIG_FILE_W_PATH);
1250             }
1251             //TODO: if failed, it will exist,
1252         }
1253         else
1254         {
1255             DDBG("=== check config.xml not valid config file: %s\n", CONFIG_FILE_NEW_W_PATH);
1256
1257
1258             // Buffer config.xml
1259             if (!IsValidTPCSConfig(CONFIG_FILE_W_PATH, &(pConfigBuf->pConfigBuffer)))
1260             {
1261                 //Recover config.xml from memory
1262                 InitConfigFile(&(pConfigBuf->pConfigBuffer));
1263                 DDBG("***************** initconfigfile: %p\n", pConfigBuf->pConfigBuffer);
1264
1265                 DDBG("Failed to parse file : %s\n", CONFIG_FILE_W_PATH);
1266
1267                 // Add plugins by scanning appPath directory
1268                 int count;
1269                 char **paths = NULL;
1270                 GetConfigElements(&(pConfigBuf->pConfigBuffer), (xmlChar*) XPATH_APP_PATHS, &count,
1271                                   &paths);
1272
1273                 int i;
1274                 int dirCount = 0;
1275                 char **app_path = NULL;
1276                 char **appId = NULL;
1277                 for (i = 0; i < count; i++)
1278                 {
1279                     // Get list of directories under the app path, if it has $appPath/lib/plugin/,
1280                     // search its manifest.xml for av tag, then recompose config.xml
1281
1282                     //TODO: if better way to get list of directory
1283                     GetDirsHasPath(paths[i], PLUGIN_DEFAULT_DIR_NAME, &dirCount, &app_path, &appId);
1284                     DDBG("fater get dirshas path:%s\n", PLUGIN_DEFAULT_DIR_NAME);
1285                     if (dirCount > 0)
1286                     {
1287                         // search manifest.xml within the app_path, if found, copy the appid to plugin element
1288                         int j;
1289                         for (j = 0; j < dirCount; j++)
1290                         {
1291                             //ftw return 0: tree exhausted, -1: error, others whatever the FileTreeCallback return
1292                             int result = ftw(app_path[j], FileTreeCallback, 12);
1293                             if (result == 1)
1294                             {
1295                                 DDBG("it found the plugin app dir:%s, appID:%s\n", app_path[j], appId[j]);
1296                                 //Update plugin element node
1297                                 UpdatePluglibList(app_path[j], &(pConfigBuf->pConfigBuffer),
1298                                                   appId[j]);
1299                             }
1300                         }
1301                     }
1302                     CleanupArray(&appId, dirCount);
1303                     CleanupArray(&app_path, dirCount);
1304                 }
1305
1306                 CleanupArray(&paths, count);
1307
1308                 // Recover config.xml from memory
1309                 WriteXmlToFile(pConfigBuf->pConfigBuffer, CONFIG_FILE_W_PATH);
1310                 DDBG("before clean up:%s, dircoutn:%d, pathCount:%d, \n", CONFIG_FILE_W_PATH, dirCount, count);
1311
1312             }
1313             else
1314             {
1315                 DDBG("Success in paring file: %s\n", CONFIG_FILE_W_PATH);
1316             }
1317         }
1318
1319         // Register methods for GetInfoPlugin
1320         IpcServerMethod method_getPlugin;
1321         snprintf(method_getPlugin.szMethod, sizeof(method_getPlugin.szMethod), "%s",
1322                  "TPCSGetInfoPlugin");
1323         method_getPlugin.method = (METHODFUNC) GetInfoPlugin;
1324         method_getPlugin.pData = &(pConfigBuf->pConfigBuffer);
1325
1326         if (IpcServerAddMethod(hServer, &method_getPlugin) != 0)
1327         {
1328             DDBG("%s", "unable to add method GetInfoPlugin\n");
1329             goto close_server;
1330         }
1331
1332         // Register methods for InstallPlugin
1333         IpcServerMethod method_installPlugin;
1334         snprintf(method_installPlugin.szMethod, sizeof(method_installPlugin.szMethod), "%s",
1335                  "TPCSInstallPlugin");
1336         method_installPlugin.method = (METHODFUNC) InstallPlugin;
1337         method_installPlugin.pData = &pConfigBuf;
1338
1339         if (IpcServerAddMethod(hServer, &method_installPlugin) != 0)
1340         {
1341             DDBG("%s", "unable to add method InstallPlugin\n");
1342             goto close_server;
1343         }
1344
1345         // Register methods for SetActivePlugin
1346         IpcServerMethod method_setActivePlugin;
1347         snprintf(method_setActivePlugin.szMethod, sizeof(method_setActivePlugin.szMethod), "%s",
1348                  "TPCSSetActivePlugin");
1349         method_setActivePlugin.method = (METHODFUNC) SetActivePlugin;
1350         method_setActivePlugin.pData = &pConfigBuf;
1351
1352         if (IpcServerAddMethod(hServer, &method_setActivePlugin) != 0)
1353         {
1354             DDBG("%s", "unable to add method SetActivePlugin\n");
1355             goto close_server;
1356         }
1357
1358         // Register methods for UnInstallPlugin
1359         IpcServerMethod method_uninstallPlugin;
1360         snprintf(method_uninstallPlugin.szMethod, sizeof(method_uninstallPlugin.szMethod), "%s",
1361                  "TPCSUninstallPlugin");
1362         method_uninstallPlugin.method = (METHODFUNC) UninstallPlugin;
1363         method_uninstallPlugin.pData = &pConfigBuf;
1364
1365         if (IpcServerAddMethod(hServer, &method_uninstallPlugin) != 0)
1366         {
1367             DDBG("%s", "unable to add method UninstallPlugin\n");
1368             goto close_server;
1369         }
1370
1371         DDBG("----------------- START method loop----------%s", "\n");
1372
1373         // Daemon waits here for request from clients.
1374         IpcServerMainLoop(hServer);
1375         DDBG("----------------- END method loop----------%s", "\n");
1376         // Clean up
1377         DDBG("======================= free xmldoc for isvalidConfig %s\n", "==============");
1378         DDBG("pconfigbuf address:%p\n", pConfigBuf->pConfigBuffer);
1379         xmlFreeDoc(pConfigBuf->pConfigBuffer);
1380         free(pConfigBuf);
1381
1382         IpcServerClose(&hServer);
1383     }
1384     else
1385     {
1386         DDBG("%s", "unable to open server connection \n");
1387         ret = -1;
1388         goto done;
1389     }
1390     xmlCleanupParser(); // clean up library for xml library for valgrind
1391     close_server:
1392     IpcServerClose(&hServer);
1393
1394     done:
1395     DDBG("%s", "Unable to start the Daemon \n");
1396
1397     return ret;
1398
1399 }