2 * Methods supported in TPCS (Tizen Plugin Control Service)
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>
19 #include <sys/types.h>
24 #include "IpcServer.h"
25 #include "IpcForkDaemon.h"
26 #include "TPCSSerDaemon.h"
29 * This daemon provides four services to manage plugins.
30 * InstallPlugin, UninstallPlugin, SetActivePlugin, GetInfoPlugin
32 * It maintains config.xml that has the plugin info.
33 * It will recover the config.xml if it is corrupted.
35 * During the services, the update config.xml and set up the symbolic link of the library is an
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.
43 * Common Utils, TODO: move to Utils.c
47 typedef struct _ConfigBuf
49 xmlDoc *pConfigBuffer;
50 pthread_mutex_t configLock;
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);
64 * Local functions declaration.
66 static int HasTag(const char *pTag, const char *pFileName, const char *xpath);
67 int UpdateNode(const xmlChar* content, xmlDoc **pDoc, const xmlChar *xpathNodeParent,
70 static void SetReturn(int *res_argc, char ***res_argv, char *val)
74 *res_argv = calloc(1, sizeof(char*));
77 (*res_argv)[0] = strdup((const char*) val);
90 static void SetSuccessReturn(int *res_argc, char ***res_argv)
92 SetReturn(res_argc, res_argv, RETURN_SUCCESS);
95 static void SetFailureReturn(int *res_argc, char ***res_argv)
97 SetReturn(res_argc, res_argv, RETURN_FAILURE);
100 int SearchNodeN(const xmlChar *xpath, xmlDoc *pXmlDoc, xmlXPathObject **pXPathObj)
102 DDBG("searchNode :%s\n", xpath);
104 xmlXPathContextPtr pXPathCtx;
106 pXPathCtx = xmlXPathNewContext(pXmlDoc);
107 if (pXPathCtx == NULL)
111 xmlChar *puri = NULL;
112 GetNSURI(pXmlDoc, &pns, &puri);
114 if (pns != NULL && puri != NULL)
116 if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0)
120 //Evaluate xpath expression
121 *pXPathObj = xmlXPathEvalExpression(xpath, pXPathCtx);
122 DDBG("============== XPATHobj address:%p\n", *pXPathObj);
124 if (*pXPathObj == NULL)
126 DDBG("Cannot find node:%s\n", xpath);
137 xmlXPathFreeContext(pXPathCtx);
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)
146 DDBG("insert node :%s\n", "==============");
148 xmlXPathContext *pXPathCtx;
149 xmlXPathObject *pXPathObj;
151 pXPathCtx = xmlXPathNewContext(*pDoc);
152 if (pXPathCtx != NULL)
155 xmlChar *puri = NULL;
156 GetNSURI(*pDoc, &pns, &puri);
157 if (pns != NULL && puri != NULL)
159 if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0)
161 DDBG("Cannot register xpath :%s\n", "");
166 // Evaluate xpath expression
167 pXPathObj = xmlXPathEvalExpression(xpathNodeParent, pXPathCtx);
168 if (pXPathObj != NULL)
170 xmlNodeSet *pNodeSet = pXPathObj->nodesetval;
172 size = pNodeSet ? pNodeSet->nodeNr : 0;
173 if (size == 1) // Should find only one node
176 xmlDoc *pPlugDoc = xmlReadMemory(content, strlen(content), NULL, NULL, 0);
177 DDBG("plugdoc :%s\n", content);
179 if (pPlugDoc != NULL)
181 xmlNode *newnode = xmlDocCopyNode(xmlDocGetRootElement(pPlugDoc),
182 pNodeSet->nodeTab[0]->doc,1);
183 DDBG("=========== pplugdoc address:%p\n", pPlugDoc);
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);
193 DDBG("FREE new node:%p\n", newnode);
194 newnode->children = NULL;
195 xmlFreeNode(newnode);
205 xmlXPathFreeObject(pXPathObj);
206 xmlXPathFreeContext(pXPathCtx);
212 int RemoveNodeParent(xmlDoc **pDoc, const xmlChar *path, const char* value)
217 xmlXPathContext *pXPathCtx;
218 xmlXPathObject *pXPathObj;
220 pXPathCtx = xmlXPathNewContext(*pDoc);
222 if (pXPathCtx != NULL)
225 xmlChar *puri = NULL;
226 GetNSURI(*pDoc, &pns, &puri);
227 if (pns != NULL && puri != NULL)
229 if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0)
234 pXPathObj = xmlXPathEvalExpression(path, pXPathCtx);
235 if (pXPathObj != NULL)
237 xmlNodeSet *pNodeSet = pXPathObj->nodesetval;
240 size = pNodeSet ? pNodeSet->nodeNr : 0;
244 for (; i < size; i++)
246 cur = pNodeSet->nodeTab[i]->children;
247 if (strcmp((const char*)cur->content, value) == 0)
249 parent = cur->parent->parent;
250 xmlUnlinkNode(parent);
254 DDBG("THEY ARE NOT EQUAL:%s\n", value);
258 xmlXPathFreeObject(pXPathObj);
264 xmlXPathFreeContext(pXPathCtx);
270 int PrintXmlDoc(xmlDocPtr pDoc)
276 xmlDocDumpFormatMemory(pDoc, &xmlMem, &xmlSize, 0);
277 DDBG("pdoc content:%s\n", xmlMem);
285 int UpdateConfigFile(ConfigBuf **pData, xmlDoc **pXmlCp)
291 pthread_mutex_lock(&((*pData)->configLock));
292 if (pXmlCp && *pXmlCp)
294 result = WriteXmlToFile(*pXmlCp, CONFIG_FILE_NEW_W_PATH);
297 DDBG("==============update config file%s\n", " ");
298 PrintXmlDoc(*pXmlCp);
299 result = WriteXmlToFile(*pXmlCp, CONFIG_FILE_W_PATH);
302 //delete config new file
303 DDBG("REMOVE file:%s\n", CONFIG_FILE_NEW_W_PATH);
304 result = remove(CONFIG_FILE_NEW_W_PATH);
306 if ((*pData)->pConfigBuffer != NULL)
307 xmlFreeDoc((*pData)->pConfigBuffer);
309 (*pData)->pConfigBuffer = xmlCopyDoc(*pXmlCp, DO_RECURSIVE_COPY);
313 pthread_mutex_unlock(&((*pData)->configLock));
318 static int UpdatePlugin(const char *libname, xmlDoc **pXmlDoc, const char* appId)
320 DDBG("~~~~~ UPDATE plugin: libname:%s, appID:%s\n", libname, appId);
322 void *pHandle = NULL;
324 pHandle = dlopen(libname, RTLD_LAZY);
328 if ((error = dlerror()) != NULL)
329 DDBG("failed to open lib: %s, error:%s\n", libname, error);
334 char* (*getInfo)(void);
336 DDBG("open library:%s\n", libname);
337 getInfo = dlsym(pHandle, "TCSGetInfo");
342 if ((error = dlerror()) != NULL)
343 DDBG("SOMETHID :%s\n", error);
347 pInfo = strdup(getInfo());
351 result = UpdateNode((const xmlChar*) pInfo, pXmlDoc, (const xmlChar*) XPATH_PLUGINS,
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.
367 int UpdateNode(const xmlChar* content, xmlDoc **pDoc, const xmlChar *xpathNodeParent,
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);
377 result = InsertNode(pDoc, xpathNodeParent, (const char*)content);
381 static int ActivePlugin(ConfigBuf *pBuf, xmlDoc **pXmlCp, const xmlChar *appId)
385 xmlXPathObject *pObj = NULL;
386 result = SearchNodeN((const xmlChar *)XPATH_ACTIVE_PLUGIN, *pXmlCp, &pObj);
388 PrintXmlDoc(*pXmlCp);
394 xmlNodeSet *pNodeSet = NULL;
397 pNodeSet = pObj->nodesetval;
400 // If appId is empty, disable the active plugin, update activePlugin Node to None
401 if (strcmp((const char*)appId, APP_ID_NULL) == 0)
403 pthread_mutex_lock(&(pBuf->configLock));
404 result = unlink(SYSLINK_PLUG_PATH);
405 pthread_mutex_unlock(&(pBuf->configLock));
409 if (pNodeSet->nodeTab[0])
411 xmlNode *cur = pNodeSet->nodeTab[0];
412 xmlNodeSetContent(cur, (xmlChar*)ACTIVE_NONE);
413 DDBG("GET node content :%s\n", cur->content);
420 // Get the plugin path from the appPath, set symbolic link for the plugin, update the xmlDoc
423 GetConfigElements(pXmlCp, (xmlChar *) XPATH_APP_PATHS, &count, &paths);
425 for (; i < count; i++)
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);
433 if (stat(appPath, &info) != 0)
436 pthread_mutex_lock(&(pBuf->configLock));
437 unlink(SYSLINK_PLUG_PATH);
438 result = symlink(appPath, SYSLINK_PLUG_PATH);
439 pthread_mutex_unlock(&(pBuf->configLock));
441 DDBG("set symbolic link result:from :%s to %s result:%d\n", appPath, SYSLINK_PLUG_PATH, result);
442 if (result == 0 && pNodeSet)
444 //update active Id node
445 xmlNode *cur = pNodeSet->nodeTab[0];
446 xmlNodeSetContent(cur, appId);
447 DDBG("GET NOde conten :%s\n", cur->content);
450 DDBG("RETURn from active plu g 0000:%d\n", result);
451 PrintXmlDoc(*pXmlCp);
454 DDBG("RETURn from active plu g 0000 000000:%d\n", result);
455 //xmlXPathFreeNodeSet(pNodeSet);
458 DDBG("RETURn from active plu g 0000 0111 :%d\n", result);
459 CleanupArray(&paths, count);
460 xmlXPathFreeObject(pObj);
464 DDBG("RETURn from active plug :%d\n", result);
469 * @appPath: /opt/usr/app/appId
471 static int UpdatePluglibList(const char *appPath, xmlDoc **pXmlDoc, const char* appId)
473 DDBG("=========================update plugin lib path:%s\n", appPath);
476 char plugPath[FILE_NAME_MAX_SIZE];
478 sprintf(plugPath, "%s%s", appPath, PLUGIN_DEFAULT_DIR_NAME);
480 struct dirent *pDirEnt;
482 pDir = opendir(plugPath);
483 DDBG("OPEN DIR:%s\n", plugPath);
487 while ((pDirEnt = readdir(pDir)) != NULL)
489 if (strcmp(pDirEnt->d_name, ".") == 0 || strcmp(pDirEnt->d_name, "..") == 0)
492 if (pDirEnt->d_type == DT_REG)
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);
502 DDBG("IT IS NO regular file:%s\n", pDirEnt->d_name);
509 DDBG("RESTURN from update pluglib list :%d\n", result);
516 int GetInfoPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc,
517 CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
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)
526 (*res_argv)[0] = strdup((const char*) RETURN_SUCCESS);
527 if ((*res_argv)[0] != NULL)
531 xmlDocDumpFormatMemory(pXml, &xmlMem, &xmlSize, 0);
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)
538 DDBG("Not enough memory in :%s\n", "set xmlmem in return");
539 free((*res_argv)[0]);
540 (*res_argv)[0] = NULL;
551 DDBG("failed to copy return_successS:%s\n", "");
554 DDBG("successfully finished:%s\n", "GetInfoPlugin");
558 // get recoverred config.xml and return
565 * pData is the buffer of config.xml,
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
579 * @req_argv: app installation path, i.e. /opt/usr/apps/appID
581 int InstallPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc,
582 CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
584 DDBG("InstallPlugin for serverstub:%s\n", req_argv[0]);
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));
594 if (req_argc == 1 && req_argv != NULL)
599 GetConfigElements(&pXmlCp, (xmlChar *) XPATH_APP_PATHS, &count, &paths);
601 for (; i < count; i++)
603 char appPath[FILE_NAME_MAX_SIZE];
604 sprintf(appPath, "%s%s%s", paths[i], "/", req_argv[0]);
607 if (UpdatePluglibList(appPath, &pXmlCp, req_argv[0]) == 0)
609 if (ActivePlugin(*((ConfigBuf**) pData), &pXmlCp, (const xmlChar *)req_argv[0]) == 0)
612 DDBG("Success cpy xml 2:%s\n", appPath);
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)
619 (*res_argv)[0] = strdup((const char*) RETURN_SUCCESS);
620 if ((*res_argv)[0] == NULL)
623 xmlChar *xmlMem = NULL;
626 xmlDocDumpFormatMemory(pXmlCp, &xmlMem, &xmlSize, 0);
627 DDBG("XMLmEM address: %p\n", xmlMem);
630 (*res_argv)[1] = strdup((const char*) xmlMem);
631 DDBG("return from install plug:%s\n", (*res_argv)[1]);
635 if ((*res_argv)[1] != NULL)
637 result = UpdateConfigFile(pData, &pXmlCp);
644 CleanupArray(&paths, count);
661 *res_argv = calloc(1, sizeof(char*));
662 (*res_argv)[0] = strdup((const char*) RETURN_FAILURE);
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
670 int UninstallPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc,
671 CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
675 xmlDoc *pXmlCp = NULL;
676 ConfigBuf *pBuf = NULL;
677 xmlXPathObject *pObj = NULL;
679 if (req_argc != 1 || req_argv == NULL)
682 pBuf = *((ConfigBuf **) pData);
684 pthread_mutex_lock(&(pBuf->configLock));
685 pXml = pBuf->pConfigBuffer;
686 pXmlCp = xmlCopyDoc(pXml, DO_RECURSIVE_COPY);
687 pthread_mutex_unlock(&(pBuf->configLock));
692 result = SearchNodeN((const xmlChar *)XPATH_ACTIVE_PLUGIN, pXmlCp, &pObj);
696 xmlNodeSet *pNodeSet = pObj->nodesetval;
697 xmlNode *pNode = pNodeSet->nodeTab[0];
700 DDBG("not such node %s\n", XPATH_ACTIVE_PLUGIN);
704 if (pNode->type != XML_ELEMENT_NODE)
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)
712 pthread_mutex_lock(&(pBuf->configLock));
713 result = unlink(SYSLINK_PLUG_PATH);
714 pthread_mutex_unlock(&(pBuf->configLock));
716 if (result != 0 && result != ENOENT)
719 xmlNodeSetContent(pNode, (const xmlChar *)ACTIVE_NONE);
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);
727 DDBG("Unable to update config file with uninstall info\n");
730 SetSuccessReturn(res_argc, res_argv);
734 SetFailureReturn(res_argc, res_argv);
738 xmlXPathFreeObject(pObj);
747 * Update the symbolic link if it is not the active plug
748 * Update xmlDoc, save to the tpcs_config.xml
750 int SetActivePlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc,
751 CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
753 DDBG("SetActivePlugin :%s\n", req_argv[0]);
755 ConfigBuf *pBuf = NULL;
757 xmlDoc *pXmlCp = NULL;
760 if (req_argc != 1 || req_argv == NULL)
763 pBuf = *((ConfigBuf **) pData);
765 pthread_mutex_lock(&(pBuf->configLock));
766 pXml = pBuf->pConfigBuffer;
767 pXmlCp = xmlCopyDoc(pXml, DO_RECURSIVE_COPY);
768 pthread_mutex_unlock(&(pBuf->configLock));
774 if ((ActivePlugin(pBuf, &pXmlCp, (const xmlChar *)req_argv[0]) == 0)
775 && UpdateConfigFile((ConfigBuf**) pData, &pXmlCp) == 0)
777 SetSuccessReturn(res_argc, res_argv);
778 DDBG("==== FINd tha ppid %s\n", req_argv[0]);
782 DDBG("==== **** FINd tha ppid %s\n", req_argv[0]);
783 SetFailureReturn(res_argc, res_argv);
790 static int WriteXmlToFile(xmlDoc *pXmlDoc, const char* filename)
793 DDBG("Write xml to file: %s\n", filename);
795 FILE *pfConfig = fopen(filename, "w");
796 if (pfConfig != NULL)
798 xmlDocDump(pfConfig, pXmlDoc);
805 static int InitConfigFile(xmlDoc **pXmlDoc)
808 DDBG("Size of xml doc in memory :%d\n", sizeof(CONFIG_DEFAULT_STRING));
810 *pXmlDoc = xmlReadMemory(CONFIG_DEFAULT_STRING, sizeof(CONFIG_DEFAULT_STRING) + 1,
814 if (*pXmlDoc != NULL)
822 static bool IsValidTPCSConfig(const char *pFileName, xmlDoc **ppXmlDoc)
824 // Create a parse context
826 xmlParserCtxt *pParserCtxt = xmlNewParserCtxt();
828 if (pParserCtxt == NULL)
830 DDBG("%s\n", "======Failed to allocate parser context");
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);
844 // Check if validation succeeded
845 if (pParserCtxt->valid)
848 DDBG("address of ppxmldoc: %p\n", *ppXmlDoc);
854 DDBG("NOT VALID file: %s\n", pFileName);
857 xmlFreeParserCtxt(pParserCtxt);
863 * Return directory list that has the specified directory within
865 static void GetDirsHasPath(const char *dir, const char *search_path, int *pCount,
866 char ***name_w_path, char ***appId)
869 struct dirent *pDirEnt = NULL;
871 if (!dir || !search_path || !pCount || !appId || !name_w_path)
878 char plugPath[FILE_NAME_MAX_SIZE];
879 char appPath[FILE_NAME_MAX_SIZE];
882 while ((pDirEnt = readdir(pDir)) != NULL)
884 if (strcmp(pDirEnt->d_name, ".") == 0 || strcmp(pDirEnt->d_name, "..") == 0)
888 if (pDirEnt->d_type == DT_DIR)
890 sprintf(appPath, "%s%s%s", dir, "/", pDirEnt->d_name);
892 sprintf(plugPath, "%s%s", appPath, PLUGIN_DEFAULT_DIR_NAME);
894 if (stat(plugPath, &info) == 0)
898 *name_w_path = calloc(1, sizeof(char*));
903 (*name_w_path)[0] = strdup((const char*) appPath);
905 if ((*name_w_path)[0] == NULL)
911 *appId = calloc(1, sizeof(char*));
914 (*appId)[0] = strdup((const char*) pDirEnt->d_name);
915 DDBG("COUNT 0, name: %s\n", pDirEnt->d_name);
916 if ((*appId)[0] == NULL)
922 //TODO: all the realloc * size, use chunk
923 *name_w_path = realloc(*name_w_path, sizeof(char*) * (*pCount + 1));
927 (*name_w_path)[(*pCount) - 1] = strdup((const char*) appPath);
928 if ((*name_w_path)[(*pCount) - 1] == NULL)
931 *appId = realloc(*appId, sizeof(char*) * (*pCount + 1));
934 (*appId)[*pCount - 1] = strdup((const char*) pDirEnt->d_name);
935 if (((*appId)[*pCount - 1]) == NULL)
958 CleanupArray(name_w_path, *pCount);
961 DDBG("CLOSE dir: %s\n", " " );
971 static void CleanupArray(char*** pArr, int len)
994 * int ftw(const char *dir, int (*fn)(const char *file, const struct stat *sb, int flag), int nopenfd);
996 int FileTreeCallback(const char *pFile, const struct stat *pStat, int flag)
999 if (pStat->st_mode & S_IFREG)
1001 //DDBG(">>>>>file tree walk :%s, such substring:%s\n", pFile, MANIFEST_FILE_NAME);
1002 if (EndsWith(pFile, MANIFEST_FILE_NAME) == 0)
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)
1008 // found the library
1009 DDBG("this app is plugin app:%s\n", pFile);
1018 * Checks if str ends with needle. Return zero on success otherwise non-zero.
1020 static int EndsWith(const char *hay, const char *needle)
1022 size_t haylen, needlelen;
1024 if (!hay || !needle)
1027 needlelen = strlen(needle);
1028 haylen = strlen(hay);
1030 if (needlelen > haylen)
1033 return strncmp(hay + haylen - needlelen, needle, needlelen);
1036 static void GetNSURI(xmlDoc *pXmlDoc, xmlChar **pns, xmlChar **uri)
1038 xmlNode *root_node = xmlDocGetRootElement(pXmlDoc);
1042 xmlNs *pXmlNS = root_node->ns;
1043 xmlNs *pXmlNSDef = root_node->nsDef;
1047 if (pXmlNS->prefix != NULL)
1049 *pns = (xmlChar*) strdup((const char*) pXmlNS->prefix);
1053 DDBG("root node name:%s\n", root_node->name);
1054 *pns = (xmlChar*) strdup((const char*) root_node->name);
1058 if (pXmlNSDef != NULL)
1060 if (pXmlNSDef->href != NULL)
1062 DDBG("nsdef :%s\n", pXmlNSDef->href);
1063 *uri = (xmlChar*) strdup((const char*) pXmlNSDef->href);
1071 * Get elements from xmlDoc, and output to the count and content
1073 static void GetConfigElements(xmlDoc **pXmlDoc, xmlChar *pXPath, int *size, char ***content)
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;
1080 pXPathCtx = xmlXPathNewContext(*pXmlDoc);
1081 if (pXPathCtx != NULL)
1083 xmlChar *pns = NULL;
1084 xmlChar *puri = NULL;
1085 GetNSURI(*pXmlDoc, &pns, &puri);
1086 if (pns != NULL && puri != NULL)
1088 if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0)
1090 DDBG("Cannot register xpath :%s\n", "");
1094 // Evaluate xpath expression
1095 pXPathObj = xmlXPathEvalExpression(pXPath, pXPathCtx);
1096 if (pXPathObj != NULL)
1099 xmlNodeSet *pNodeSet = pXPathObj->nodesetval;
1101 *size = pNodeSet ? pNodeSet->nodeNr : 0;
1105 *content = calloc(1, sizeof(char*) * (*size));
1106 DDBG("XAPTH OBJCT FOUND:%s, size:%d\n", "", *size);
1109 for (; i < *size; i++)
1111 if (pNodeSet->nodeTab[i]->type == XML_ELEMENT_NODE)
1113 cur = pNodeSet->nodeTab[i];
1117 DDBG("content; %s\n", cur->children->content);
1118 (*content)[i] = strdup((const char*) cur->children->content);
1125 DDBG("CANNOT FOUND content:%s\n", "");
1129 xmlXPathFreeObject(pXPathObj);
1143 xmlXPathFreeContext(pXPathCtx);
1147 static int HasTag(const char *pTag, const char *pFileName, const char *xpath)
1150 xmlDoc *pConfigXml = NULL;
1155 pConfigXml = xmlReadFile(pFileName, NULL, 0);
1156 if (pConfigXml != NULL)
1159 char **pCategory = NULL;
1160 GetConfigElements(&pConfigXml, (xmlChar*) xpath, &size, &pCategory);
1163 DDBG("size is: %d, category:%s\n", size, pCategory[0]);
1165 for (; i < size; i++)
1167 if (strcmp(pCategory[i], pTag) == 0)
1174 CleanupArray(&pCategory, size);
1176 xmlFreeDoc(pConfigXml);
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
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
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
1193 int main(int argc, char **argv)
1195 //TODO: make it a daemon
1203 TSC_SERVER_HANDLE hServer = NULL;
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)
1211 DDBG("%s", "**** successfully opened server ****\n");
1212 // Write out the DTD validation file
1213 FILE *pDTD = fopen(CONFIG_DTD_FILE_W_PATH, "r");
1216 pDTD = fopen(CONFIG_DTD_FILE_W_PATH, "w");
1219 fwrite(CONFIG_DEFAULT_DTD_STRING, strlen(CONFIG_DEFAULT_DTD_STRING), 1, pDTD);
1229 //TODO: close the file, check if the file exists lstat, signature of the file
1232 ConfigBuf *pConfigBuf = calloc(1, sizeof(ConfigBuf));
1233 if (pConfigBuf == NULL)
1235 ret = pthread_mutex_init(&(pConfigBuf->configLock), NULL);
1238 //TODO: memory clean up
1244 if (IsValidTPCSConfig(CONFIG_FILE_NEW_W_PATH, &(pConfigBuf->pConfigBuffer)))
1246 // switch to config.xml
1247 if (rename(CONFIG_FILE_NEW_W_PATH, CONFIG_FILE_W_PATH) == 0)
1249 DDBG("%s has been renamed to :%s\n", CONFIG_FILE_NEW_W_PATH, CONFIG_FILE_W_PATH);
1251 //TODO: if failed, it will exist,
1255 DDBG("=== check config.xml not valid config file: %s\n", CONFIG_FILE_NEW_W_PATH);
1258 // Buffer config.xml
1259 if (!IsValidTPCSConfig(CONFIG_FILE_W_PATH, &(pConfigBuf->pConfigBuffer)))
1261 //Recover config.xml from memory
1262 InitConfigFile(&(pConfigBuf->pConfigBuffer));
1263 DDBG("***************** initconfigfile: %p\n", pConfigBuf->pConfigBuffer);
1265 DDBG("Failed to parse file : %s\n", CONFIG_FILE_W_PATH);
1267 // Add plugins by scanning appPath directory
1269 char **paths = NULL;
1270 GetConfigElements(&(pConfigBuf->pConfigBuffer), (xmlChar*) XPATH_APP_PATHS, &count,
1275 char **app_path = NULL;
1276 char **appId = NULL;
1277 for (i = 0; i < count; i++)
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
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);
1287 // search manifest.xml within the app_path, if found, copy the appid to plugin element
1289 for (j = 0; j < dirCount; j++)
1291 //ftw return 0: tree exhausted, -1: error, others whatever the FileTreeCallback return
1292 int result = ftw(app_path[j], FileTreeCallback, 12);
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),
1302 CleanupArray(&appId, dirCount);
1303 CleanupArray(&app_path, dirCount);
1306 CleanupArray(&paths, count);
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);
1315 DDBG("Success in paring file: %s\n", CONFIG_FILE_W_PATH);
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);
1326 if (IpcServerAddMethod(hServer, &method_getPlugin) != 0)
1328 DDBG("%s", "unable to add method GetInfoPlugin\n");
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;
1339 if (IpcServerAddMethod(hServer, &method_installPlugin) != 0)
1341 DDBG("%s", "unable to add method InstallPlugin\n");
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;
1352 if (IpcServerAddMethod(hServer, &method_setActivePlugin) != 0)
1354 DDBG("%s", "unable to add method SetActivePlugin\n");
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;
1365 if (IpcServerAddMethod(hServer, &method_uninstallPlugin) != 0)
1367 DDBG("%s", "unable to add method UninstallPlugin\n");
1371 DDBG("----------------- START method loop----------%s", "\n");
1373 // Daemon waits here for request from clients.
1374 IpcServerMainLoop(hServer);
1375 DDBG("----------------- END method loop----------%s", "\n");
1377 DDBG("======================= free xmldoc for isvalidConfig %s\n", "==============");
1378 DDBG("pconfigbuf address:%p\n", pConfigBuf->pConfigBuffer);
1379 xmlFreeDoc(pConfigBuf->pConfigBuffer);
1382 IpcServerClose(&hServer);
1386 DDBG("%s", "unable to open server connection \n");
1390 xmlCleanupParser(); // clean up library for xml library for valgrind
1392 IpcServerClose(&hServer);
1395 DDBG("%s", "Unable to start the Daemon \n");