1 /*
2  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *    * Redistributions of source code must retain the above copyright
8  *      notice, this list of conditions and the following disclaimer.
9  *    * Redistributions in binary form must reproduce the above
10  *      copyright notice, this list of conditions and the following
11  *      disclaimer in the documentation and/or other materials provided
12  *      with the distribution.
13  *    * Neither the name of The Linux Foundation nor the names of its
14  *      contributors may be used to endorse or promote products derived
15  *      from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef VERIFY_PRINT_ERROR
31 #define VERIFY_PRINT_ERROR
32 #endif // VERIFY_PRINT_ERROR
33 #include <pthread.h>
34 #include <unistd.h>
35 #include <sys/inotify.h>
36 #include <sys/eventfd.h>
37 #include <poll.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <limits.h>
43 
44 #include "apps_std.h"
45 #include "AEEstd.h"
46 #include "AEEStdErr.h"
47 #include "verify.h"
48 #include "remote_priv.h"
49 #include "adsp_current_process.h"
50 #include "adsp_current_process1.h"
51 #include "adspmsgd_adsp.h"
52 #include "adspmsgd_adsp1.h"
53 #include "rpcmem.h"
54 
55 #define EVENT_SIZE          ( sizeof (struct inotify_event) )
56 #define EVENT_BUF_LEN       ( 1024 * ( EVENT_SIZE + 16 ) )
57 #ifndef AEE_EUNSUPPORTED
58 #define AEE_EUNSUPPORTED         20 // API is not supported 	50
59 #endif
60 #define DEFAULT_ADSPMSGD_MEMORY_SIZE     8192
61 #define INVALID_HANDLE      (remote_handle64)(-1)
62 #define ERRNO (errno == 0 ? -1 : errno)
63 
64 struct log_config_watcher_params {
65     int fd;
66     int event_fd; // Duplicate fd to quit the poll
67     _cstring1_t* paths;
68     int* wd;
69     uint32 numPaths;
70     pthread_attr_t attr;
71     pthread_t thread;
72     unsigned char stopThread;
73     int asidToWatch;
74     char* fileToWatch;
75     char* asidFileToWatch;
76     char* pidFileToWatch;
77     boolean adspmsgdEnabled;
78 };
79 
80 static struct log_config_watcher_params log_config_watcher[NUM_DOMAINS_EXTEND];
81 extern const char* __progname;
82 
83 const char* get_domain_str(int domain);
84 remote_handle64 get_adsp_current_process1_handle(int domain);
85 remote_handle64 get_adspmsgd_adsp1_handle(int domain);
86 
parseLogConfig(int dom,unsigned short mask,char * filenames)87 static int parseLogConfig(int dom, unsigned short mask, char* filenames){
88     _cstring1_t* filesToLog = NULL;
89     int filesToLogLen = 0;
90     char* tempFiles = NULL;
91     int nErr = AEE_SUCCESS;
92     char *saveptr = NULL;
93     char* path = NULL;
94     char delim[] = {','};
95     int maxPathLen = 0;
96     int i = 0;
97     remote_handle64 handle;
98 
99     VERIFYC(filenames != NULL, AEE_EINVALIDFILENAME);
100 
101     VERIFYC(NULL!= (tempFiles = malloc(sizeof(char) * (std_strlen(filenames) + 1))), AEE_ENOMEMORY);
102     std_strlcpy(tempFiles,filenames,std_strlen(filenames) + 1);
103 
104     // Get the number of folders and max size needed
105     path = strtok_r (tempFiles, delim, &saveptr);
106     while (path != NULL){
107         maxPathLen = STD_MAX(maxPathLen, std_strlen(path)) + 1;
108         filesToLogLen++;
109         path = strtok_r (NULL, delim, &saveptr);
110     }
111 
112     VERIFY_IPRINTF("%s: #files: %d max_len: %d\n", log_config_watcher[dom].fileToWatch, filesToLogLen, maxPathLen);
113 
114     // Allocate memory
115     VERIFYC(NULL != (filesToLog = malloc(sizeof(_cstring1_t)*filesToLogLen)), AEE_ENOMEMORY);
116     for (i = 0; i < filesToLogLen; ++i){
117         VERIFYC(NULL != (filesToLog[i].data = malloc(sizeof(char) * maxPathLen)), AEE_ENOMEMORY);
118         filesToLog[i].dataLen = maxPathLen;
119     }
120 
121     // Get the number of folders and max size needed
122     std_strlcpy(tempFiles,filenames,std_strlen(filenames) + 1);
123     i = 0;
124     path = strtok_r (tempFiles, delim, &saveptr);
125     while (path != NULL){
126         VERIFYC((filesToLog != NULL) && (filesToLog[i].data != NULL) &&
127                filesToLog[i].dataLen >= (int)strlen(path), AEE_EBADSIZE);
128         std_strlcpy(filesToLog[i].data, path, filesToLog[i].dataLen);
129         VERIFY_IPRINTF("%s: %s\n", log_config_watcher[dom].fileToWatch, filesToLog[i].data);
130         path = strtok_r (NULL, delim, &saveptr);
131         i++;
132     }
133 
134     handle = get_adsp_current_process1_handle(dom);
135     if (handle != INVALID_HANDLE) {
136        VERIFY(AEE_SUCCESS == (nErr = adsp_current_process1_set_logging_params(handle, mask,filesToLog,filesToLogLen)));
137     } else {
138        VERIFY(AEE_SUCCESS == (nErr = adsp_current_process_set_logging_params(mask,filesToLog,filesToLogLen)));
139     }
140 
141 bail:
142     if (filesToLog){
143         for (i = 0; i < filesToLogLen; ++i){
144             if (filesToLog[i].data != NULL){
145                 free (filesToLog[i].data);
146                 filesToLog[i].data = NULL;
147             }
148         }
149         free(filesToLog);
150         filesToLog = NULL;
151     }
152 
153     if(tempFiles){
154         free(tempFiles);
155         tempFiles = NULL;
156     }
157     if(nErr != AEE_SUCCESS) {
158 	VERIFY_EPRINTF("Error %x: parse log config failed. domain %d, mask %x, filename %s\n", nErr, dom, mask, filenames);
159     }
160     return nErr;
161 }
162 // Read log config given the filename
readLogConfigFromPath(int dom,const char * base,const char * file)163 static int readLogConfigFromPath(int dom, const char* base, const char* file){
164     int nErr = 0;
165     apps_std_FILE fp = -1;
166     uint64 len;
167     byte* buf = NULL;
168     int readlen = 0, eof;
169     unsigned short mask = 0;
170     char* path = NULL;
171     char* filenames = NULL;
172     boolean fileExists = FALSE;
173     int buf_addr = 0;
174     remote_handle64 handle;
175 
176     len = std_snprintf(0, 0, "%s/%s", base, file) + 1;
177     VERIFYC(NULL != (path =  malloc(sizeof(char) * len)), AEE_ENOMEMORY);
178     std_snprintf(path, (int)len, "%s/%s", base, file);
179     VERIFY(AEE_SUCCESS == (nErr = apps_std_fileExists(path,&fileExists)));
180     if (fileExists == FALSE){
181         VERIFY_IPRINTF("%s: Couldn't find file: %s\n",log_config_watcher[dom].fileToWatch, path);
182         nErr = AEE_ENOSUCHFILE;
183         goto bail;
184     }
185     if (log_config_watcher[dom].adspmsgdEnabled == FALSE){
186         handle = get_adspmsgd_adsp1_handle(dom);
187         if(handle != INVALID_HANDLE) {
188            adspmsgd_adsp1_init2(handle);
189         } else if(AEE_EUNSUPPORTED == (nErr = adspmsgd_adsp_init2())) {
190             nErr = adspmsgd_adsp_init(0, RPCMEM_HEAP_DEFAULT, 0, DEFAULT_ADSPMSGD_MEMORY_SIZE, &buf_addr);
191         }
192         if (nErr != AEE_SUCCESS){
193             VERIFY_EPRINTF("adspmsgd not supported. nErr=%x\n", nErr);
194         }else{
195             log_config_watcher[dom].adspmsgdEnabled = TRUE;
196         }
197         VERIFY_EPRINTF("Found %s. adspmsgd enabled \n", log_config_watcher[dom].fileToWatch);
198     }
199 
200     VERIFY(AEE_SUCCESS == (nErr = apps_std_fopen(path, "r", &fp)));
201     VERIFY(AEE_SUCCESS == (nErr = apps_std_flen(fp, &len)));
202 
203     VERIFYC(len < 511, AEE_EBADSIZE);
204     VERIFYC(NULL != (buf = calloc(1, sizeof(byte) * (len + 1))), AEE_ENOMEMORY); // extra 1 byte for null character
205     VERIFYC(NULL != (filenames = malloc(sizeof(byte) * len)), AEE_ENOMEMORY);
206     VERIFY(AEE_SUCCESS == (nErr = apps_std_fread(fp, buf, len, &readlen, &eof)));
207     VERIFYC((int)len == readlen, AEE_EFREAD);
208 
209     VERIFY_IPRINTF("%s: Config file %s contents: %s\n", log_config_watcher[dom].fileToWatch, path, buf);
210 
211     len = sscanf((const char*)buf, "0x%hx %511s", &mask, filenames);
212     switch (len){
213         case 1:
214             VERIFY_IPRINTF("%s: Setting log mask:0x%x", log_config_watcher[dom].fileToWatch, mask);
215             handle = get_adsp_current_process1_handle(dom);
216             if (handle != INVALID_HANDLE) {
217                VERIFY(AEE_SUCCESS == (nErr = adsp_current_process1_set_logging_params(handle,mask,NULL,0)));
218             } else {
219                VERIFY(AEE_SUCCESS == (nErr = adsp_current_process_set_logging_params(mask,NULL,0)));
220             }
221             break;
222         case 2:
223             VERIFY(AEE_SUCCESS == (nErr = parseLogConfig(dom, mask,filenames)));
224             VERIFY_IPRINTF("%s: Setting log mask:0x%x, filename:%s", log_config_watcher[dom].fileToWatch, mask, filenames);
225             break;
226         default:
227             VERIFY_EPRINTF("%s: No valid data found in config file %s", log_config_watcher[dom].fileToWatch, path);
228             nErr = AEE_EUNSUPPORTED;
229             goto bail;
230     }
231 
232 bail:
233     if (buf != NULL){
234         free(buf);
235         buf = NULL;
236     }
237 
238     if (filenames != NULL){
239         free(filenames);
240         filenames = NULL;
241     }
242 
243     if (fp != -1){
244         apps_std_fclose(fp);
245     }
246 
247     if (path != NULL){
248         free(path);
249         path = NULL;
250     }
251 
252     if(nErr != AEE_SUCCESS) {
253 	VERIFY_IPRINTF("Error %x: fopen failed for %s/%s. (%s)\n", nErr, base, file, strerror(ERRNO));
254     }
255     return nErr;
256 }
257 
258 
259 // Read log config given the watch descriptor
readLogConfigFromEvent(int dom,struct inotify_event * event)260 static int readLogConfigFromEvent(int dom, struct inotify_event *event){
261     int i = 0;
262 
263     // Ensure we are looking at the right file
264     for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){
265         if (log_config_watcher[dom].wd[i] == event->wd ){
266             if(std_strcmp(log_config_watcher[dom].fileToWatch, event->name) == 0){
267                 return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, log_config_watcher[dom].fileToWatch);
268             }else if (std_strcmp(log_config_watcher[dom].asidFileToWatch, event->name) == 0) {
269                 return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, log_config_watcher[dom].asidFileToWatch);
270             }else if (std_strcmp(log_config_watcher[dom].pidFileToWatch, event->name) == 0){
271                 return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, log_config_watcher[dom].pidFileToWatch);
272             }
273         }
274     }
275     VERIFY_IPRINTF("%s: Watch descriptor %d not valid for current process", log_config_watcher[dom].fileToWatch, event->wd);
276     return AEE_SUCCESS;
277 }
278 
279 
280 // Read log config given the watch descriptor
resetLogConfigFromEvent(int dom,struct inotify_event * event)281 static int resetLogConfigFromEvent(int dom, struct inotify_event *event) {
282     int i = 0;
283     remote_handle64 handle;
284 
285     // Ensure we are looking at the right file
286     for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){
287         if (log_config_watcher[dom].wd[i] == event->wd ){
288             if( (std_strcmp(log_config_watcher[dom].fileToWatch, event->name) == 0)||
289                 (std_strcmp(log_config_watcher[dom].asidFileToWatch, event->name) == 0) ||
290                 (std_strcmp(log_config_watcher[dom].pidFileToWatch, event->name) == 0) ) {
291                 if (log_config_watcher[dom].adspmsgdEnabled == TRUE){
292                    handle = get_adspmsgd_adsp1_handle(dom);
293                    if(handle != INVALID_HANDLE) {
294                       adspmsgd_adsp1_deinit(handle);
295                    } else {
296                       adspmsgd_adsp_deinit();
297                    }
298                 }
299                 handle = get_adsp_current_process1_handle(dom);
300                 if (handle != INVALID_HANDLE) {
301                    return adsp_current_process1_set_logging_params(handle,0,NULL,0);
302                 } else {
303                    return adsp_current_process_set_logging_params(0,NULL,0);
304                 }
305             }
306         }
307     }
308     VERIFY_IPRINTF("%s: Watch descriptor %d not valid for current process", log_config_watcher[dom].fileToWatch, event->wd);
309     return AEE_SUCCESS;
310 }
311 
312 
file_watcher_thread(void * arg)313 static void* file_watcher_thread(void *arg) {
314     int dom = (int)(uintptr_t)arg;
315     int ret = 0;
316     int length = 0;
317     int nErr = AEE_SUCCESS;
318     int i = 0;
319     char buffer[EVENT_BUF_LEN];
320     struct pollfd pfd[] = {
321         {log_config_watcher[dom].fd,     POLLIN, 0},
322         {log_config_watcher[dom].event_fd, POLLIN, 0}
323      };
324     const char* fileExtension = ".farf";
325     int len = 0;
326     remote_handle64 handle;
327 
328     // Check for the presence of the <process_name>.farf file at bootup
329     for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){
330         if (0 == readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, log_config_watcher[dom].fileToWatch)){
331             VERIFY_IPRINTF("%s: Log config File %s found.\n", log_config_watcher[dom].fileToWatch, log_config_watcher[dom].paths[i].data );
332         }
333     }
334 
335     while(log_config_watcher[dom].stopThread == 0){
336         // Block forever
337         ret = poll(pfd, 2, -1);
338         if(ret < 0){
339             VERIFY_EPRINTF("%s: Error polling for file change. Runtime FARF will not work for this process. errno=%x !", log_config_watcher[dom].fileToWatch, errno);
340             break;
341         } else if (pfd[1].revents & POLLIN) { // Check for exit
342             VERIFY_IPRINTF("Received exit.\n");
343             break;
344         } else {
345             length = read( log_config_watcher[dom].fd, buffer, EVENT_BUF_LEN );
346             i = 0;
347             while ( i < length ) {
348                 struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
349                 if ( event->len ) {
350                     // Get the asiD for the current process
351                     // Do it once only
352                     if (log_config_watcher[dom].asidToWatch == -1){
353                         handle = get_adsp_current_process1_handle(dom);
354                         if (handle != INVALID_HANDLE) {
355                            VERIFY(AEE_SUCCESS == (nErr = adsp_current_process1_getASID(handle,(unsigned int*)&log_config_watcher[dom].asidToWatch )));
356                         } else {
357                            VERIFY(AEE_SUCCESS == (nErr = adsp_current_process_getASID((unsigned int*)&log_config_watcher[dom].asidToWatch )));
358                         }
359                         len = strlen(fileExtension) + strlen(__TOSTR__(INT_MAX));
360                         VERIFYC(NULL != (log_config_watcher[dom].asidFileToWatch = malloc(sizeof(char) * len)), AEE_ENOMEMORY);
361                         snprintf(log_config_watcher[dom].asidFileToWatch, len, "%d%s", log_config_watcher[dom].asidToWatch, fileExtension);
362                         VERIFY_IPRINTF("%s: Watching ASID file %s\n", log_config_watcher[dom].fileToWatch, log_config_watcher[dom].asidFileToWatch);
363                     }
364 
365                     VERIFY_IPRINTF("%s: %s %d.\n", log_config_watcher[dom].fileToWatch, event->name, event->mask );
366                     if ( (event->mask & IN_CREATE) || (event->mask & IN_MODIFY)) {
367                         VERIFY_IPRINTF("%s: File %s created.\n", log_config_watcher[dom].fileToWatch, event->name );
368                         if (0 != readLogConfigFromEvent(dom, event)){
369                             VERIFY_EPRINTF("%s: Error reading config file %s", log_config_watcher[dom].fileToWatch, log_config_watcher[dom].paths[i].data);
370                         }
371                     }
372                     else if ( event->mask & IN_DELETE ) {
373                         VERIFY_IPRINTF("%s: File %s deleted.\n", log_config_watcher[dom].fileToWatch, event->name );
374                         if (0 != resetLogConfigFromEvent(dom, event)){
375                             VERIFY_EPRINTF("%s: Error resetting FARF runtime log config" ,log_config_watcher[dom].fileToWatch);
376                         }
377                     }
378                 }
379 
380                 i += EVENT_SIZE + event->len;
381             }
382         }
383     }
384 bail:
385     if (nErr != AEE_SUCCESS){
386         VERIFY_EPRINTF("Error %x: file watcher thread exited. Runtime FARF will not work for this process. filename %s\n", nErr, log_config_watcher[dom].fileToWatch);
387     }
388     return NULL;
389 }
390 
deinitFileWatcher(int dom)391 void deinitFileWatcher(int dom) {
392     int i = 0;
393     uint64 stop = 10;
394     remote_handle64 handle;
395 
396     log_config_watcher[dom].stopThread = 1;
397     if (0 < log_config_watcher[dom].event_fd) {
398        if (write(log_config_watcher[dom].event_fd, &stop, sizeof(uint64)) != sizeof(uint64)) {
399          VERIFY_EPRINTF("Error: write failed: Cannot set exit flag to watcher thread.\n");
400 	}
401     }
402     if (log_config_watcher[dom].thread) {
403         pthread_join(log_config_watcher[dom].thread, NULL);
404 	log_config_watcher[dom].thread = 0;
405     }
406     if (log_config_watcher[dom].fileToWatch){
407         free (log_config_watcher[dom].fileToWatch);
408 	log_config_watcher[dom].fileToWatch = 0;
409     }
410     if (log_config_watcher[dom].asidFileToWatch){
411         free (log_config_watcher[dom].asidFileToWatch);
412 	log_config_watcher[dom].asidFileToWatch = 0;
413     }
414     if (log_config_watcher[dom].pidFileToWatch){
415         free (log_config_watcher[dom].pidFileToWatch);
416 	log_config_watcher[dom].pidFileToWatch = 0;
417     }
418     if (log_config_watcher[dom].wd){
419         for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){
420             if (log_config_watcher[dom].wd[i] != 0){
421                 inotify_rm_watch( log_config_watcher[dom].fd, log_config_watcher[dom].wd[i] );
422             }
423         }
424         free(log_config_watcher[dom].wd);
425         log_config_watcher[dom].wd = NULL;
426     }
427     if (log_config_watcher[dom].paths){
428         for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){
429             if (log_config_watcher[dom].paths[i].data){
430                 free(log_config_watcher[dom].paths[i].data);
431                 log_config_watcher[dom].paths[i].data = NULL;
432             }
433         }
434         free(log_config_watcher[dom].paths);
435         log_config_watcher[dom].paths = NULL;
436     }
437     if(log_config_watcher[dom].fd != 0){
438         close(log_config_watcher[dom].fd);
439         log_config_watcher[dom].fd = 0;
440     }
441     if (log_config_watcher[dom].adspmsgdEnabled == TRUE){
442         handle = get_adspmsgd_adsp1_handle(dom);
443         if (handle != INVALID_HANDLE) {
444            adspmsgd_adsp1_deinit(handle);
445         } else {
446            adspmsgd_adsp_deinit();
447         }
448 	log_config_watcher[dom].adspmsgdEnabled = FALSE;
449     }
450 
451     if(log_config_watcher[dom].event_fd != 0){
452 	close(log_config_watcher[dom].event_fd);
453 	log_config_watcher[dom].event_fd = 0;
454     }
455 
456     log_config_watcher[dom].numPaths = 0;
457 }
458 
initFileWatcher(int dom)459 int initFileWatcher(int dom) {
460     int nErr = AEE_SUCCESS;
461     const char* fileExtension = ".farf";
462     uint32 len = 0;
463     uint16 maxPathLen = 0;
464     int i = 0;
465     char* name = NULL;
466 
467     memset(&log_config_watcher[dom], 0, sizeof(struct log_config_watcher_params));
468     log_config_watcher[dom].asidToWatch = 0;
469 
470     VERIFYC(NULL != (name = std_basename(__progname)), AEE_EINVALIDPROCNAME);
471 
472     len = strlen(name) + strlen(fileExtension) + 1;
473     VERIFYC(NULL != (log_config_watcher[dom].fileToWatch = malloc(sizeof(char) * len)), AEE_ENOMEMORY);
474     snprintf(log_config_watcher[dom].fileToWatch, len, "%s%s", name, fileExtension);
475 
476     len = strlen(fileExtension) + strlen(__TOSTR__(INT_MAX));
477     VERIFYC(NULL != (log_config_watcher[dom].pidFileToWatch = malloc(sizeof(char) * len)), AEE_ENOMEMORY);
478     snprintf(log_config_watcher[dom].pidFileToWatch, len, "%d%s", getpid(), fileExtension);
479 
480     VERIFY_IPRINTF("%s: Watching PID file: %s\n", log_config_watcher[dom].fileToWatch, log_config_watcher[dom].pidFileToWatch);
481 
482     log_config_watcher[dom].fd = inotify_init();
483     if (log_config_watcher[dom].fd < 0){
484         nErr = AEE_EINVALIDFD;
485         VERIFY_EPRINTF("Error %x: inotify_init failed. errno = %s\n", nErr, strerror(errno));
486         goto bail;
487     }
488 
489     // Duplicate the fd, so we can use it to quit polling
490     log_config_watcher[dom].event_fd = eventfd(0, 0);
491     if (log_config_watcher[dom].event_fd < 0){
492         nErr = AEE_EINVALIDFD;
493         VERIFY_EPRINTF("Error %x: eventfd in dup failed. errno %s\n", nErr, strerror(errno));
494         goto bail;
495     }
496     VERIFY_IPRINTF("fd = %d dupfd=%d\n", log_config_watcher[dom].fd, log_config_watcher[dom].event_fd);
497 
498     // Get the required size
499     apps_std_get_search_paths_with_env("ADSP_LIBRARY_PATH", ";", NULL, 0,
500         &log_config_watcher[dom].numPaths, &maxPathLen);
501 
502     maxPathLen += + 1;
503 
504     // Allocate memory
505     VERIFYC(NULL != (log_config_watcher[dom].paths
506            = malloc(sizeof(_cstring1_t) * log_config_watcher[dom].numPaths)), AEE_ENOMEMORY);
507     VERIFYC(NULL != (log_config_watcher[dom].wd
508            = malloc(sizeof(int) * log_config_watcher[dom].numPaths)), AEE_ENOMEMORY);
509 
510     for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){
511         VERIFYC( NULL != (log_config_watcher[dom].paths[i].data
512                = malloc(sizeof(char) * maxPathLen)), AEE_ENOMEMORY);
513         log_config_watcher[dom].paths[i].dataLen = maxPathLen;
514     }
515 
516     // Get the paths
517     VERIFY(AEE_SUCCESS == (nErr = apps_std_get_search_paths_with_env("ADSP_LIBRARY_PATH", ";",
518            log_config_watcher[dom].paths, log_config_watcher[dom].numPaths, &len, &maxPathLen)));
519 
520     maxPathLen += 1;
521 
522     VERIFY_IPRINTF("%s: Watching folders:\n", log_config_watcher[dom].fileToWatch);
523     for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i){
524         // Watch for creation, deletion and modification of files in path
525 	VERIFY_IPRINTF("log file watcher: %s: %s\n",log_config_watcher[dom].fileToWatch, log_config_watcher[dom].paths[i].data);
526 	if((log_config_watcher[dom].wd[i] = inotify_add_watch (log_config_watcher[dom].fd,
527 				log_config_watcher[dom].paths[i].data,  IN_CREATE | IN_DELETE)) < 0) {
528 		VERIFY_EPRINTF("Unable to add watcher for folder %s : errno is %s\n", log_config_watcher[dom].paths[i].data, strerror(ERRNO));
529 	}
530     }
531 
532     // Create a thread to watch for file changes
533     log_config_watcher[dom].asidToWatch = -1;
534     log_config_watcher[dom].stopThread = 0;
535     pthread_create(&log_config_watcher[dom].thread, NULL, file_watcher_thread, (void*)(uintptr_t)dom);
536 bail:
537     if (nErr!=AEE_SUCCESS){
538         VERIFY_EPRINTF("Error %x: Failed to register with inotify file %s. Runtime FARF will not work for the process %s!", nErr, log_config_watcher[dom].fileToWatch, name);
539         deinitFileWatcher(dom);
540     }
541 
542     return nErr;
543 }
544