d33e6b9709cabadac54df58e21c1312c499da486
[profile/ivi/dlt-daemon.git] / src / system / dlt-system-filetransfer.c
1 /**
2  * @licence app begin@
3  * Copyright (C) 2012  BMW AG
4  *
5  * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps.
6  *
7  * Contributions are licensed to the GENIVI Alliance under one or more
8  * Contribution License Agreements.
9  *
10  * \copyright
11  * This Source Code Form is subject to the terms of the
12  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
13  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  *
16  * \author Lassi Marttala <lassi.lm.marttala@partner.bmw.de> BMW 2012
17  *
18  * \file dlt-system-filetransfer.c
19  * For further information see http://www.genivi.org/.
20  * @licence end@
21  */
22
23 /*******************************************************************************
24 **                                                                            **
25 **  SRC-MODULE: dlt-system-filetransfer.c                                                  **
26 **                                                                            **
27 **  TARGET    : linux                                                         **
28 **                                                                            **
29 **  PROJECT   : DLT                                                           **
30 **                                                                            **
31 **  AUTHOR    : Lassi Marttala <lassi.lm.marttala@partner.bmw.de>             **
32 **              Alexander Wenzel Alexander.AW.Wenzel@bmw.de                   **
33 **                                                                            **
34 **  PURPOSE   :                                                               **
35 **                                                                            **
36 **  REMARKS   :                                                               **
37 **                                                                            **
38 **  PLATFORM DEPENDANT [yes/no]: yes                                          **
39 **                                                                            **
40 **  TO BE CHANGED BY USER [yes/no]: no                                        **
41 **                                                                            **
42 *******************************************************************************/
43
44
45 #include <pthread.h>
46 #include <unistd.h>
47 #include <sys/inotify.h>
48 #include <libgen.h>
49 #include <dirent.h>
50 #include <zlib.h>
51 #include <time.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 #include "dlt-system.h"
56 #include "dlt.h"
57 #include "dlt_filetransfer.h"
58
59 #define INOTIFY_SZ (sizeof(struct inotify_event))
60 #define INOTIFY_LEN (INOTIFY_SZ + NAME_MAX + 1)
61 #define Z_CHUNK_SZ 1024*128
62 #define COMPRESS_EXTENSION ".gz"
63 #define SUBDIR_COMPRESS ".tocompress"
64 #define SUBDIR_TOSEND ".tosend"
65
66
67
68 extern DltSystemThreads threads;
69 // From dlt_filetransfer
70 extern unsigned long getFileSerialNumber(const char* file, int *ok);
71
72 DLT_IMPORT_CONTEXT(dltsystem);
73 DLT_DECLARE_CONTEXT(filetransferContext)
74
75 typedef struct {
76     int handle;
77     int fd[DLT_SYSTEM_LOG_DIRS_MAX];
78 } s_ft_inotify;
79
80 s_ft_inotify ino;
81
82
83 char *origin_name(char *src){
84     if (strlen( (char*) basename(src)) > 10 ){
85         return (char*)(basename(src)+10);
86     }
87     else{
88         DLT_LOG(dltsystem, DLT_LOG_ERROR,
89                 DLT_STRING("dlt-system-filetransfer, error in recreating origin name!"));
90         return NULL;
91     }
92 }
93
94 char *unique_name(char *src)
95 {
96     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
97             DLT_STRING("dlt-system-filetransfer, creating unique temporary file name."));
98     time_t t = time(NULL);
99     int ok;
100     unsigned long l = getFileSerialNumber(src, &ok) ^ t;
101     if (!ok){
102         return (char*) NULL;
103     }
104
105     char *basename_f = basename(src);
106     // Length of ULONG_MAX + 1
107     int len = 11+strlen(basename_f);
108     if (len > NAME_MAX){
109         DLT_LOG(dltsystem, DLT_LOG_WARN,
110                 DLT_STRING("dlt-system-filetransfer, unique name creation needs to shorten the filename:"),DLT_STRING(basename_f));
111         len = NAME_MAX;
112     }
113
114     char *ret = malloc(len);
115
116     MALLOC_ASSERT(ret);
117     snprintf(ret, len, "%010lu%s", l,basename_f);
118     return ret;
119 }
120
121 /**
122   * Function which only calls the relevant part to transfer the payload
123   */
124
125 void send_dumped_file(FiletransferOptions const *opts,char *dst_tosend)
126 {
127
128     char *fn = origin_name(dst_tosend);
129     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
130             DLT_STRING("dlt-system-filetransfer, sending dumped file:"),DLT_STRING(fn));
131     if(dlt_user_log_file_header_alias(&filetransferContext, dst_tosend, fn) == 0)
132     {
133         int pkgcount = dlt_user_log_file_packagesCount(&filetransferContext, dst_tosend);
134         int lastpkg = 0;
135         int success = 1;
136         while(lastpkg < pkgcount)
137         {
138             int total = 2;
139             int used = 2;
140             dlt_user_check_buffer(&total, &used);
141             while((total-used) < (total/2))
142             {
143                 struct timespec t;
144                 t.tv_sec = 0;
145                 t.tv_nsec = 1000000ul*opts->TimeoutBetweenLogs;
146                 nanosleep(&t, NULL);
147                 dlt_user_check_buffer(&total, &used);
148             }
149             lastpkg++;
150             if(dlt_user_log_file_data(&filetransferContext, dst_tosend, lastpkg, opts->TimeoutBetweenLogs) < 0)
151             {
152                 success = 0;
153                 break;
154             }
155         }
156         if (success)
157             dlt_user_log_file_end(&filetransferContext, dst_tosend, 1);
158     }
159     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
160             DLT_STRING("dlt-system-filetransfer, sent dumped file"));
161 }
162
163 /**
164  * compress file, delete the source file
165  * modification: compress into subdirectory
166  * File whis is compress will be deleted afterwards
167  *  @param src File to be sent
168  *  @param dst destination where to compress the file
169  * @param level of compression
170 **/
171 int compress_file_to(char *src, char *dst, int level)
172 {
173     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
174             DLT_STRING("dlt-system-filetransfer, compressing file from:"),DLT_STRING(src),DLT_STRING("to:"),DLT_STRING(dst));
175     char *buf;
176
177
178     char dst_mode[8];
179     snprintf(dst_mode,8, "wb%d", level);
180
181     gzFile dst_file;
182     FILE *src_file;
183
184     dst_file = gzopen(dst, dst_mode);
185     if(dst_file == Z_NULL)
186     {
187
188         return -1;
189     }
190
191     src_file = fopen(src, "r");
192
193     if(src_file == NULL)
194     {
195         gzclose(dst_file);
196
197         return -1;
198     }
199
200     buf = malloc(Z_CHUNK_SZ);
201     MALLOC_ASSERT(buf);
202
203     while(!feof(src_file))
204     {
205         int read = fread(buf, 1, Z_CHUNK_SZ, src_file);
206         if(ferror(src_file))
207         {
208             free(buf);
209
210             gzclose(dst_file);
211             fclose(src_file);
212             return -1;
213         }
214         gzwrite(dst_file, buf, read);
215     }
216
217     if(remove(src) < 0)
218         DLT_LOG(dltsystem, DLT_LOG_WARN, DLT_STRING("Could not remove file"), DLT_STRING(src));
219     free(buf);
220     fclose(src_file);
221     gzclose(dst_file);
222
223     return 0;
224 }
225
226 //!Sends one file over DLT.
227 /**
228  * If configured in opts, compresses it, then sends it.
229  * uses subdirecties for compressing and before sending, to avoid that those files get changed in the meanwhile
230  *
231  */
232 int send_one(char *src, FiletransferOptions const *opts, int which)
233 {
234     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
235             DLT_STRING("dlt-system-filetransfer, sending a file."));
236     sleep(opts->TimeDelay);
237
238     // Prepare all needed file names
239     char *fn = basename(src);
240
241     char *fdir = strndup(src,PATH_MAX);
242     MALLOC_ASSERT(fdir);
243     fdir = dirname(fdir);//dirname overwrites its argument anyway
244     char *dst_tosend;//file which is going to be sent
245
246     char *rn = unique_name(src);//new unique filename based on inode
247
248     MALLOC_ASSERT(fn);
249     MALLOC_ASSERT(rn);
250
251     // Compress if needed
252     if(opts->Compression[which] > 0)
253     {
254         DLT_LOG(dltsystem, DLT_LOG_DEBUG,
255                 DLT_STRING("dlt-system-filetransfer, Moving file to tmp directory for compressing it."));
256
257         char *dst_tocompress;//file which is going to be compressed, the compressed one is named dst_tosend
258
259
260         int len = strlen(fdir)+strlen(SUBDIR_COMPRESS)+strlen(rn)+3;//the filename in .tocompress +2 for 2*"/", +1 for \0
261         dst_tocompress = malloc(len);
262         MALLOC_ASSERT(dst_tocompress);
263
264         snprintf(dst_tocompress,len,"%s/%s/%s",fdir,SUBDIR_COMPRESS,rn);
265
266         //moving in subdir, from where it can be compressed
267         if(rename(src, dst_tocompress) < 0)
268         {
269             DLT_LOG(dltsystem, DLT_LOG_ERROR,
270                     DLT_STRING("Could not move file"),
271                     DLT_STRING(src),
272                     DLT_STRING(dst_tocompress));
273             free(rn);
274             free(dst_tocompress);
275             free(fdir);
276             return -1;
277         }
278         len = strlen(fdir)+strlen(SUBDIR_TOSEND)+strlen(rn)+strlen(COMPRESS_EXTENSION)+3;//the resulting filename in .tosend +2 for 2*"/", +1 for \0
279         dst_tosend = malloc(len);
280         MALLOC_ASSERT(dst_tosend);
281         snprintf(dst_tosend,len,"%s/%s/%s%s",fdir,SUBDIR_TOSEND,rn,COMPRESS_EXTENSION);
282
283         if (compress_file_to(dst_tocompress,dst_tosend, opts->CompressionLevel[which]) != 0){
284             free(rn);
285             free(dst_tosend);
286             free(dst_tocompress);
287             free(fdir);
288             return -1;
289         }
290         free(dst_tocompress);
291
292     }
293     else{
294         //move it directly into "tosend"
295         DLT_LOG(dltsystem, DLT_LOG_DEBUG,
296                 DLT_STRING("dlt-system-filetransfer, Moving file to tmp directory."));
297         int len = strlen(fdir)+strlen(SUBDIR_TOSEND)+strlen(rn)+3;
298         dst_tosend = malloc(len);//the resulting filename in .tosend +2 for 2*"/", +1 for \0
299
300         snprintf(dst_tosend,len,"%s/%s/%s",fdir,SUBDIR_TOSEND,rn);
301
302         DLT_LOG(dltsystem, DLT_LOG_DEBUG,
303                 DLT_STRING("dlt-system-filetransfer, Rename:"),DLT_STRING(src),DLT_STRING("to: "),DLT_STRING(dst_tosend));
304         //moving in subdir, from where it can be compressed
305         if(rename(src, dst_tosend) < 0)
306         {
307             DLT_LOG(dltsystem, DLT_LOG_ERROR,
308                     DLT_STRING("Could not move file"),
309                     DLT_STRING(src),
310                     DLT_STRING(dst_tosend));
311             free(rn);
312             free(dst_tosend);
313             free(fdir);
314             return -1;
315         }
316
317     }
318
319     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
320             DLT_STRING("dlt-system-filetransfer, File ready to send"));
321
322     send_dumped_file(opts,dst_tosend);
323
324
325     free(rn);
326     free(dst_tosend);
327     free(fdir);
328
329     return 0;
330 }
331
332
333 int flush_dir_send(FiletransferOptions const *opts, const char *compress_dir,  const char *send_dir){
334
335     struct dirent *dp;
336     DIR *dir;
337     dir = opendir(send_dir);
338
339     if(dir != NULL)
340     {
341         while((dp = readdir(dir)) != NULL)
342         {
343             if(dp->d_type != DT_REG)
344                 continue;
345             char *fn;
346             DLT_LOG(dltsystem, DLT_LOG_DEBUG,
347                     DLT_STRING("dlt-system-filetransfer, old compressed file found in send directory:"),DLT_STRING(dp->d_name));
348             int len = strlen(send_dir)+strlen(dp->d_name)+2;
349             fn = malloc(len);
350             MALLOC_ASSERT(fn);
351             snprintf(fn,len, "%s/%s", send_dir, dp->d_name);
352
353
354             //if we have a file here and in the to_compress dir, we delete the to_send file: we can not be sure, that it has been properly compressed!
355             if (!strncmp( dp->d_name+strlen(dp->d_name)-strlen(COMPRESS_EXTENSION),COMPRESS_EXTENSION,strlen(COMPRESS_EXTENSION)))
356             {
357
358                 //ends with ".gz"
359                 //old file name (not: path) would have been:
360                 char tmp[strlen(dp->d_name)-strlen(COMPRESS_EXTENSION)+1];
361                 strncpy(tmp,dp->d_name,strlen(dp->d_name)-strlen(COMPRESS_EXTENSION));
362                 tmp[strlen(dp->d_name)-3]='\0';
363
364                 int len = strlen(tmp)+strlen(compress_dir)+1+1;//2 sizes + 1*"/" + \0
365                 char *path_uncompressed = malloc(len);
366                 MALLOC_ASSERT(path_uncompressed);
367                 snprintf(path_uncompressed,len,"%s/%s",compress_dir,tmp);
368
369                 struct stat sb;
370                 if (stat(path_uncompressed,&sb)==-1)
371                 {
372                     //uncompressed equivalent does not exist. We can send it out.
373                     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
374                             DLT_STRING("dlt-system-filetransfer, sending file."));
375
376                     send_dumped_file(opts,fn);
377                 }
378                 else
379                 {
380                     //There is an uncompressed file. Compression seems to have been interrupted -> delete the compressed file instead of sending it!
381                     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
382                             DLT_STRING("dlt-system-filetransfer, uncompressed version exists. Deleting partially compressed version."));
383                     if (sb.st_mode & S_IFREG)
384                     {
385
386
387                         if( remove(fn ) != 0 )
388                         {
389                             //"Error deleting file". Continue? If we would cancel, maybe the dump is never sent! Deletion would again be tried in next LC.
390                             DLT_LOG(dltsystem, DLT_LOG_ERROR,
391                                     DLT_STRING("Error deleting file:"),DLT_STRING(fn));
392                         }
393                     }
394                     else
395                     {
396                         //"Oldfile is a not reg file. Is this possible? Can we compress a directory?: %s\n",path_uncompressed);
397                         DLT_LOG(dltsystem, DLT_LOG_DEBUG,
398                                 DLT_STRING("dlt-system-filetransfer, Oldfile is a not regular file! Do we have a problem?"),DLT_STRING(fn));
399                     }
400
401                 }
402                 free(path_uncompressed);//it is no more used. It would be transferred in next step.
403             }//it is a .gz file
404             else{
405                 //uncompressed file. We can just resend it, the action to put it here was a move action.
406                 DLT_LOG(dltsystem, DLT_LOG_DEBUG,
407                         DLT_STRING("dlt-system-filetransfer, Sending uncompressed file from previous LC."),DLT_STRING(fn));
408                 send_dumped_file(opts,fn);
409             }
410             free(fn);
411         }
412     }
413     else
414     {
415         DLT_LOG(dltsystem, DLT_LOG_ERROR,
416                 DLT_STRING("Could not open directory"),
417                 DLT_STRING(send_dir));
418         return -1;
419     }
420     closedir(dir);//end: send_dir
421     return 0;
422 }
423
424
425 int flush_dir_compress(FiletransferOptions const *opts, int which, const char *compress_dir, const char *send_dir){
426
427     //check for files in compress_dir. Assumption: a file which lies here, should have been compressed, but that action was interrupted.
428     //As it can arrive here only by a rename, it is most likely to be a complete file
429     struct dirent *dp;
430     DIR *dir;
431     dir = opendir(compress_dir);
432     if(dir != NULL)
433     {
434         while((dp = readdir(dir)) != NULL)
435         {
436             if(dp->d_type != DT_REG)
437                 continue;
438             DLT_LOG(dltsystem, DLT_LOG_DEBUG,
439                     DLT_STRING("dlt-system-filetransfer, old file found in compress-directory."));
440
441
442             //compress file into to_send dir
443             int len = strlen(compress_dir)+strlen(dp->d_name)+2;
444             char *cd_filename = malloc(len);
445             MALLOC_ASSERT(cd_filename);
446             snprintf(cd_filename,len,"%s/%s",compress_dir,dp->d_name);
447
448
449             len = strlen(send_dir)+strlen(dp->d_name)+strlen(COMPRESS_EXTENSION)+2;
450             char *dst_tosend = malloc(len);//the resulting filename in .tosend +2 for 1*"/", +1 for \0 + .gz
451             MALLOC_ASSERT(dst_tosend);
452             snprintf(dst_tosend,len,"%s/%s%s",send_dir,dp->d_name,COMPRESS_EXTENSION);
453
454             if (compress_file_to(cd_filename,dst_tosend, opts->CompressionLevel[which]) != 0){
455                 free(dst_tosend);
456                 free(cd_filename);
457                 closedir(dir);
458                 return -1;
459             }
460
461             //send file
462             send_dumped_file(opts,dst_tosend);
463             free(dst_tosend);
464             free(cd_filename);
465         }
466     }
467     else
468     {
469         DLT_LOG(dltsystem, DLT_LOG_ERROR,
470                 DLT_STRING("Could not open directory"),
471                 DLT_STRING(compress_dir));
472         return -1;
473     }
474     closedir(dir);//end: compress_dir
475
476     return 0;
477 }
478
479 int flush_dir_original(FiletransferOptions const *opts, int which){
480     struct dirent *dp;
481     DIR *dir;
482     const char *sdir = opts->Directory[which];
483     dir = opendir(sdir);
484     if(dir != NULL)
485     {
486         while((dp = readdir(dir)) != NULL)
487         {
488             if(dp->d_type != DT_REG){
489                 //we don't send directories
490                 continue;
491             }
492             DLT_LOG(dltsystem, DLT_LOG_DEBUG,
493                     DLT_STRING("dlt-system-filetransfer, old file found in directory."));
494             int len = strlen(sdir)+strlen(dp->d_name)+2;
495             char *fn = malloc(len);
496             MALLOC_ASSERT(fn);
497             snprintf(fn,len, "%s/%s", sdir, dp->d_name);
498             if(send_one(fn, opts, which) < 0)
499             {
500                 closedir(dir);
501                 free(fn);
502                 return -1;
503             }
504             free(fn);
505         }
506     }
507     else
508     {
509         DLT_LOG(dltsystem, DLT_LOG_ERROR,
510                 DLT_STRING("Could not open directory"),
511                 DLT_STRING(sdir));
512         return -1;
513     }
514     closedir(dir);
515     return 0;
516 }
517
518 //!Cleans the surveyed directories and subdirectories. Sends residing files into trace
519 /**
520  * @param opts FiletransferOptions
521  * @param which which directory is affected -> position in list of opts->Directory
522  * @return Returns 0 if everything was okay. If there was a failure a value < 0 will be returned.
523  */
524 int flush_dir(FiletransferOptions const *opts, int which)
525 {
526
527
528     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
529             DLT_STRING("dlt-system-filetransfer, flush directory of old files."));
530
531     char *compress_dir;
532     char *send_dir;
533     int len = strlen(opts->Directory[which])+strlen(SUBDIR_COMPRESS)+2;
534     compress_dir = malloc (len);
535     MALLOC_ASSERT(compress_dir);
536     snprintf(compress_dir,len,"%s/%s",opts->Directory[which],SUBDIR_COMPRESS);
537
538     len = strlen(opts->Directory[which])+strlen(SUBDIR_TOSEND)+2;
539     send_dir = malloc (len);
540     MALLOC_ASSERT(send_dir);
541     snprintf(send_dir,len,"%s/%s",opts->Directory[which],SUBDIR_TOSEND);
542
543     //1st: scan the tosend directory.
544     if ( 0 != flush_dir_send(opts, compress_dir, send_dir) ){
545         free(send_dir);
546         free(compress_dir);
547         return -1;
548     }
549
550     //1nd: scan the tocompress directory.
551     if (0 != flush_dir_compress(opts, which, compress_dir, send_dir)){
552         free(send_dir);
553         free(compress_dir);
554         return -1;
555     }
556
557     free(send_dir);//no more used
558     free(compress_dir);
559
560     //last step: scan the original directory - we can reuse the send_one function
561     if ( 0 != flush_dir_original(opts,which)){
562         return -1;
563     }
564
565     return 0;
566 }
567
568 //!Initializes the surveyed directories
569 /**On startup, the inotifiy handlers are created, and existing files shall be sent into DLT stream
570  * @param opts FiletransferOptions
571  * @return Returns 0 if everything was okay. If there was a failure a value < 0 will be returned.
572  */
573 int init_filetransfer_dirs(FiletransferOptions const *opts)
574 {
575     DLT_LOG(dltsystem, DLT_LOG_DEBUG,
576             DLT_STRING("dlt-system-filetransfer, initializing inotify on directories."));
577     ino.handle = inotify_init();
578     int i;
579
580     if(ino.handle < 0)
581     {
582         DLT_LOG(filetransferContext, DLT_LOG_FATAL,
583                 DLT_STRING("Failed to initialize inotify in dlt-system file transfer."));
584         return -1;
585     }
586
587     for(i = 0;i < opts->Count;i++)
588     {
589         //create subdirectories for processing the files
590
591         char *subdirpath;
592         int len = strlen(opts->Directory[i])+strlen(SUBDIR_COMPRESS)+2;
593         subdirpath= malloc (len);
594         MALLOC_ASSERT(subdirpath);
595         snprintf(subdirpath,len,"%s/%s",opts->Directory[i],SUBDIR_COMPRESS);
596         int ret = mkdir(subdirpath,0777);
597
598         if (0 != ret && EEXIST != errno){
599             DLT_LOG(dltsystem, DLT_LOG_ERROR,
600                     DLT_STRING("dlt-system-filetransfer, error creating subdirectory: "),DLT_STRING(subdirpath),DLT_STRING(" Errorcode: "),DLT_INT(errno));
601             free (subdirpath);
602             return -1;
603         }
604         free(subdirpath);
605
606         len = strlen(opts->Directory[i])+strlen(SUBDIR_TOSEND)+2;
607         subdirpath= malloc (len);
608         MALLOC_ASSERT(subdirpath);
609         snprintf(subdirpath,len,"%s/%s",opts->Directory[i],SUBDIR_TOSEND);
610         ret = mkdir(subdirpath,0777);
611         if (0 != ret && EEXIST != errno){
612             DLT_LOG(dltsystem, DLT_LOG_ERROR,
613                     DLT_STRING("dlt-system-filetransfer, error creating subdirectory: "),DLT_STRING(subdirpath),DLT_STRING(" Errorcode: "),DLT_INT(errno));
614             free (subdirpath);
615             return -1;
616         }
617         free(subdirpath);
618
619
620         ino.fd[i] = inotify_add_watch(ino.handle, opts->Directory[i],
621                                       IN_CLOSE_WRITE|IN_MOVED_TO);
622         if(ino.fd[i] < 0)
623         {
624             char buf[1024];
625             snprintf(buf, 1024, "Failed to add inotify watch to directory %s in dlt-system file transfer.",
626                      opts->Directory[i]);
627             DLT_LOG(filetransferContext, DLT_LOG_FATAL,
628                     DLT_STRING(buf));
629             return -1;
630         }
631
632
633         flush_dir(opts, i);
634
635     }
636     return 0;
637 }
638
639 int wait_for_files(FiletransferOptions const *opts)
640 {
641     DLT_LOG(dltsystem, DLT_LOG_DEBUG, DLT_STRING("dlt-system-filetransfer, waiting for files."));
642     static char buf[INOTIFY_LEN];
643     ssize_t len = read(ino.handle, buf, INOTIFY_LEN);
644     if(len < 0)
645     {
646         DLT_LOG(filetransferContext, DLT_LOG_ERROR,
647                 DLT_STRING("Error while waiting for files in dlt-system file transfer."));
648         return -1;
649     }
650
651     unsigned int i = 0;
652     while(i < (len-INOTIFY_SZ))
653     {
654         struct inotify_event *ie = (struct inotify_event *)&buf[i];
655         if(ie->len > 0)
656         {
657             if((ie->mask & IN_CLOSE_WRITE) || (ie->mask & IN_MOVED_TO))
658             {
659                 int j;
660                 for(j = 0;j < opts->Count;j++)
661                 {
662                     if(ie->wd == ino.fd[j])
663                     {
664                         DLT_LOG(dltsystem, DLT_LOG_DEBUG, DLT_STRING("dlt-system-filetransfer, found new file."));
665                         int length = strlen(opts->Directory[j])+ie->len+1;
666                         char *tosend = malloc(length);
667                         snprintf(tosend,length, "%s/%s", opts->Directory[j], ie->name);
668                         send_one(tosend, opts, j);
669                         free(tosend);
670                     }
671                 }
672             }
673         }
674         i += INOTIFY_SZ + ie->len;
675     }
676     return 0;
677 }
678
679 void filetransfer_thread(void *v_conf)
680 {
681     DLT_LOG(dltsystem, DLT_LOG_DEBUG, DLT_STRING("dlt-system-filetransfer, in thread."));
682     DltSystemConfiguration *conf = (DltSystemConfiguration *) v_conf;
683     DLT_REGISTER_CONTEXT(filetransferContext, conf->Filetransfer.ContextId,
684                          "File transfer manager.");
685
686     sleep(conf->Filetransfer.TimeStartup);
687
688     if(init_filetransfer_dirs(&(conf->Filetransfer)) < 0)
689         return;
690
691     while(!threads.shutdown)
692     {
693         if(wait_for_files(&(conf->Filetransfer)) < 0)
694         {
695             DLT_LOG(dltsystem, DLT_LOG_ERROR, DLT_STRING("Error while waiting files. File transfer shutdown."));
696             return;
697         }
698         sleep(conf->Filetransfer.TimeDelay);
699     }
700 }
701
702 void start_filetransfer(DltSystemConfiguration *conf)
703 {
704     DLT_LOG(dltsystem, DLT_LOG_DEBUG, DLT_STRING("dlt-system-filetransfer, start."));
705     static pthread_attr_t t_attr;
706     static pthread_t pt;
707     pthread_create(&pt, &t_attr, (void *)filetransfer_thread, conf);
708     threads.threads[threads.count++] = pt;
709 }