sync.c 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541
  1. /*
  2. clsync - file tree sync utility based on fanotify and inotify
  3. Copyright (C) 2013 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "common.h"
  16. #include "main.h"
  17. #include "output.h"
  18. #include "fileutils.h"
  19. #include "malloc.h"
  20. #include "cluster.h"
  21. #include "sync.h"
  22. #include <dlfcn.h>
  23. pthread_t pthread_sighandler;
  24. static inline int _exitcode_process(options_t *options_p, int exitcode) {
  25. if(options_p->isignoredexitcode[(unsigned char)exitcode])
  26. return 0;
  27. if(exitcode && !((options_p->flags[RSYNC]>=2) && (exitcode == 24))) {
  28. printf_e("Error: Got non-zero exitcode %i from __sync_exec().\n", exitcode);
  29. return exitcode;
  30. }
  31. return 0;
  32. }
  33. int exitcode_process(options_t *options_p, int exitcode) {
  34. int err = _exitcode_process(options_p, exitcode);
  35. if(err) printf_e("Error: Got error-report from exitcode_process().\nExitcode is %i, strerror(%i) returns \"%s\". However strerror() is not ensures compliance "
  36. "between exitcode and error description for every utility. So, e.g if you're using rsync, you should look for the error description "
  37. "into rsync's manpage (\"man 1 rsync\"). Also some advices about diagnostics can be found in clsync's manpage (\"man 1 clsync\", see DIAGNOSTICS)\n",
  38. exitcode, exitcode, strerror(exitcode));
  39. return err;
  40. }
  41. /**
  42. * @brief Checks file path by rules' expressions (parsed from file)
  43. *
  44. * @param[in] fpath Path to file of directory
  45. * @param[in] st_mode st_mode received via *stat() functions
  46. * @param[in] rules_p Pointer to start of rules array
  47. * @param[in] ruleaction Operaton ID (see ruleaction_t)
  48. * @param[i/o] rule_pp Pointer to pointer to rule, where the last search ended. Next search will be started from the specified rule. Can be "NULL" to disable this feature.
  49. *
  50. * @retval perm Permission bitmask
  51. *
  52. */
  53. // Checks file path by rules' expressions (parsed from file)
  54. // Return: RS_PERMIT or RS_REJECT for the "file path" and specified ruleaction
  55. ruleaction_t rules_search_getperm(const char *fpath, mode_t st_mode, rule_t *rules_p, ruleaction_t ruleaction, rule_t **rule_pp) {
  56. printf_ddd("Debug3: rules_search_getperm(\"%s\", %p, rules_p, %p, %p)\n",
  57. fpath, (void *)(unsigned long)st_mode,
  58. (void *)(long)ruleaction, (void *)(long)rule_pp
  59. );
  60. int i;
  61. i = 0;
  62. rule_t *rule_p = rules_p;
  63. mode_t ftype = st_mode & S_IFMT;
  64. if(rule_pp != NULL)
  65. if(*rule_pp != NULL) {
  66. if(rule_p->mask == RA_NONE)
  67. return rule_p->perm;
  68. rule_p = ++(*rule_pp);
  69. i = rule_p->num;
  70. }
  71. printf_ddd("Debug3: rules_search_getperm(): Starting from position %i\n", i);
  72. while(rule_p->mask != RA_NONE) {
  73. printf_ddd("Debug3: rules_search_getperm(): %i -> %p/%p: type compare: %p, %p -> %p\n",
  74. i,
  75. (void *)(long)rule_p->perm, (void *)(long)rule_p->mask,
  76. (void *)(unsigned long)ftype, (void *)(unsigned long)rule_p->objtype,
  77. (unsigned char)!(rule_p->objtype && (rule_p->objtype != ftype))
  78. );
  79. if(!(rule_p->mask & ruleaction)) { // Checking wrong operation type
  80. printf_ddd("Debug3: rules_search_getperm(): action-mask mismatch. Skipping.\n");
  81. rule_p++;i++;// = &rules_p[++i];
  82. continue;
  83. }
  84. if(rule_p->objtype && (rule_p->objtype != ftype)) {
  85. printf_ddd("Debug3: rules_search_getperm(): objtype mismatch. Skipping.\n");
  86. rule_p++;i++;// = &rules_p[++i];
  87. continue;
  88. }
  89. if(!regexec(&rule_p->expr, fpath, 0, NULL, 0))
  90. break;
  91. printf_ddd("Debug3: rules_search_getperm(): doesn't match regex. Skipping.\n");
  92. rule_p++;i++;// = &rules_p[++i];
  93. }
  94. printf_dd("Debug2: matched to rule #%u for \"%s\":\t%p/%p (queried: %p).\n", rule_p->mask==RA_NONE?-1:i, fpath,
  95. (void *)(long)rule_p->perm, (void *)(long)rule_p->mask,
  96. (void *)(long)ruleaction
  97. );
  98. if(rule_pp != NULL)
  99. *rule_pp = rule_p;
  100. return rule_p->perm;
  101. }
  102. static inline ruleaction_t rules_getperm(const char *fpath, mode_t st_mode, rule_t *rules_p, ruleaction_t ruleactions) {
  103. rule_t *rule_p = NULL;
  104. ruleaction_t gotpermto = 0;
  105. ruleaction_t resultperm = 0;
  106. while((gotpermto&ruleactions) != ruleactions) {
  107. rules_search_getperm(fpath, st_mode, rules_p, ruleactions, &rule_p);
  108. if(rule_p->mask == RA_NONE) { // End of rules' list
  109. resultperm |= rule_p->perm & (gotpermto^RA_ALL);
  110. break;
  111. }
  112. resultperm |= rule_p->perm & ((gotpermto^rule_p->mask)&rule_p->mask); // Adding perm bitmask of operations that was unknown before
  113. gotpermto |= rule_p->mask; // Adding the mask
  114. }
  115. printf_ddd("Debug3: rules_getperm(\"%s\", %i, rules_p, %p): result perm is %p\n",
  116. fpath, st_mode, (void *)(long)ruleactions, (void *)(long)resultperm);
  117. return resultperm;
  118. }
  119. // Removes necessary rows from hash_tables if some watching descriptor closed
  120. // Return: 0 on success, non-zero on fail
  121. static inline int indexes_remove_bywd(indexes_t *indexes_p, int wd) {
  122. int ret=0;
  123. char *fpath = g_hash_table_lookup(indexes_p->wd2fpath_ht, GINT_TO_POINTER(wd));
  124. ret |= g_hash_table_remove(indexes_p->wd2fpath_ht, GINT_TO_POINTER(wd));
  125. if(fpath == NULL) {
  126. printf_e("Error: Cannot remove from index \"fpath2wd\" by wd %i.\n", wd);
  127. return -1;
  128. }
  129. ret |= g_hash_table_remove(indexes_p->fpath2wd_ht, fpath);
  130. return ret;
  131. }
  132. // Adds necessary rows to hash_tables if some watching descriptor opened
  133. // Return: 0 on success, non-zero on fail
  134. static inline int indexes_add_wd(indexes_t *indexes_p, int wd, const char *fpath_const, size_t fpathlen) {
  135. printf_ddd("Debug3: indexes_add_wd(indexes_p, %i, \"%s\", %i)\n", wd, fpath_const, fpathlen);
  136. char *fpath = xmalloc(fpathlen+1);
  137. memcpy(fpath, fpath_const, fpathlen+1);
  138. g_hash_table_insert(indexes_p->wd2fpath_ht, GINT_TO_POINTER(wd), fpath);
  139. g_hash_table_insert(indexes_p->fpath2wd_ht, fpath, GINT_TO_POINTER(wd));
  140. return 0;
  141. }
  142. // Lookups file path by watching descriptor from hash_tables
  143. // Return: file path on success, NULL on fail
  144. static inline char *indexes_wd2fpath(indexes_t *indexes_p, int wd) {
  145. return g_hash_table_lookup(indexes_p->wd2fpath_ht, GINT_TO_POINTER(wd));
  146. }
  147. //
  148. static inline int indexes_fpath2wd(indexes_t *indexes_p, const char *fpath) {
  149. gpointer gint_p = g_hash_table_lookup(indexes_p->fpath2wd_ht, fpath);
  150. if(gint_p == NULL)
  151. return -1;
  152. return GPOINTER_TO_INT(gint_p);
  153. }
  154. static inline eventinfo_t *indexes_fpath2ei(indexes_t *indexes_p, const char *fpath) {
  155. return (eventinfo_t *)g_hash_table_lookup(indexes_p->fpath2ei_ht, fpath);
  156. }
  157. static inline int indexes_fpath2ei_add(indexes_t *indexes_p, char *fpath, eventinfo_t *evinfo) {
  158. g_hash_table_replace(indexes_p->fpath2ei_ht, fpath, evinfo);
  159. return 0;
  160. }
  161. static inline int indexes_queueevent(indexes_t *indexes_p, char *fpath, eventinfo_t *evinfo, queue_id_t queue_id) {
  162. g_hash_table_replace(indexes_p->fpath2ei_coll_ht[queue_id], fpath, evinfo);
  163. printf_ddd("Debug3: indexes_queueevent(indexes_p, \"%s\", evinfo, %i). It's now %i events collected in queue %i.\n", fpath, queue_id, g_hash_table_size(indexes_p->fpath2ei_coll_ht[queue_id]), queue_id);
  164. return 0;
  165. }
  166. static inline int indexes_removefromqueue(indexes_t *indexes_p, char *fpath, queue_id_t queue_id) {
  167. // printf_ddd("Debug3: indexes_removefromqueue(indexes_p, \"%s\", %i).\n", fpath, queue_id);
  168. g_hash_table_remove(indexes_p->fpath2ei_coll_ht[queue_id], fpath);
  169. printf_ddd("Debug3: indexes_removefromqueue(indexes_p, \"%s\", %i). It's now %i events collected in queue %i.\n", fpath, queue_id, g_hash_table_size(indexes_p->fpath2ei_coll_ht[queue_id]), queue_id);
  170. return 0;
  171. }
  172. static inline int indexes_addexclude(indexes_t *indexes_p, char *fpath, queue_id_t queue_id) {
  173. g_hash_table_replace(indexes_p->exc_fpath_coll_ht[queue_id], fpath, GINT_TO_POINTER(1));
  174. printf_ddd("Debug3: indexes_addexclude(indexes_p, \"%s\", %i). It's now %i events collected in queue %i.\n", fpath, queue_id, g_hash_table_size(indexes_p->exc_fpath_coll_ht[queue_id]), queue_id);
  175. return 0;
  176. }
  177. static inline int indexes_addexclude_aggr(indexes_t *indexes_p, char *fpath) {
  178. g_hash_table_replace(indexes_p->exc_fpath_ht, fpath, GINT_TO_POINTER(1));
  179. printf_ddd("Debug3: indexes_addexclude_aggr(indexes_p, \"%s\").\n", fpath);
  180. return 0;
  181. }
  182. static inline int indexes_outaggr_add(indexes_t *indexes_p, char *outline) {
  183. g_hash_table_replace(indexes_p->out_lines_aggr_ht, outline, GINT_TO_POINTER(1));
  184. printf_ddd("Debug3: indexes_outaggr_aggr(indexes_p, \"%s\").\n", outline);
  185. return 0;
  186. }
  187. static threadsinfo_t *thread_getinfo() { // TODO: optimize this
  188. static threadsinfo_t threadsinfo={{{{0}}},{{{0}}},0};
  189. if(!threadsinfo.mutex_init) {
  190. int i=0;
  191. while(i < PTHREAD_MUTEX_MAX) {
  192. if(pthread_mutex_init(&threadsinfo.mutex[i], NULL)) {
  193. printf_e("Error: Cannot pthread_mutex_init(): %s (errno: %i).\n", strerror(errno), errno);
  194. return NULL;
  195. }
  196. if(pthread_cond_init (&threadsinfo.cond [i], NULL)) {
  197. printf_e("Error: Cannot pthread_cond_init(): %s (errno: %i).\n", strerror(errno), errno);
  198. return NULL;
  199. }
  200. i++;
  201. }
  202. threadsinfo.mutex_init++;
  203. }
  204. // pthread_mutex_lock(&threadsinfo._mutex);
  205. return &threadsinfo;
  206. }
  207. time_t thread_nextexpiretime() {
  208. time_t nextexpiretime = 0;
  209. threadsinfo_t *threadsinfo_p = thread_getinfo();
  210. if(threadsinfo_p == NULL)
  211. return 0;
  212. int thread_num = threadsinfo_p->used;
  213. while(thread_num--) {
  214. threadinfo_t *threadinfo_p = &threadsinfo_p->threads[thread_num];
  215. printf_ddd("Debug3: threadsinfo_p->threads[%i].state == %i;\tthreadsinfo_p->threads[%i].pthread == %p;\tthreadsinfo_p->threads[%i].expiretime == %i\n",
  216. thread_num, threadinfo_p->state,thread_num, threadinfo_p->pthread, thread_num, threadinfo_p->expiretime);
  217. if(threadinfo_p->state == STATE_EXIT)
  218. continue;
  219. if(threadinfo_p->expiretime) {
  220. if(nextexpiretime)
  221. nextexpiretime = MIN(nextexpiretime, threadinfo_p->expiretime);
  222. else
  223. nextexpiretime = threadinfo_p->expiretime;
  224. }
  225. }
  226. printf_ddd("Debug3: thread_nextexpiretime(): nextexpiretime == %i\n", nextexpiretime);
  227. return nextexpiretime;
  228. }
  229. threadinfo_t *thread_new() {
  230. threadsinfo_t *threadsinfo_p = thread_getinfo();
  231. if(threadsinfo_p == NULL)
  232. return NULL;
  233. int thread_num;
  234. threadinfo_t *threadinfo_p;
  235. if(threadsinfo_p->stacklen) {
  236. threadinfo_p = threadsinfo_p->threadsstack[--threadsinfo_p->stacklen];
  237. thread_num = threadinfo_p->thread_num;
  238. } else {
  239. if(threadsinfo_p->used >= threadsinfo_p->allocated) {
  240. threadsinfo_p->allocated += ALLOC_PORTION;
  241. printf_dd("Debug2: Reallocated memory for threadsinfo -> %i.\n", threadsinfo_p->allocated);
  242. threadsinfo_p->threads = (threadinfo_t *) xrealloc((char *)threadsinfo_p->threads,
  243. sizeof(*threadsinfo_p->threads) *(threadsinfo_p->allocated+2));
  244. threadsinfo_p->threadsstack = (threadinfo_t **)xrealloc((char *)threadsinfo_p->threadsstack,
  245. sizeof(*threadsinfo_p->threadsstack)*(threadsinfo_p->allocated+2));
  246. }
  247. thread_num = threadsinfo_p->used++;
  248. threadinfo_p = &threadsinfo_p->threads[thread_num];
  249. }
  250. #ifdef PARANOID
  251. memset(threadinfo_p, 0, sizeof(*threadinfo_p));
  252. #else
  253. threadinfo_p->expiretime = 0;
  254. threadinfo_p->errcode = 0;
  255. threadinfo_p->exitcode = 0;
  256. #endif
  257. threadinfo_p->thread_num = thread_num;
  258. threadinfo_p->state = STATE_RUNNING;
  259. printf_dd("Debug2: thread_new -> thread_num: %i; used: %i\n", thread_num, threadsinfo_p->used);
  260. return threadinfo_p;
  261. }
  262. int thread_del_bynum(int thread_num) {
  263. printf_dd("Debug2: thread_del_bynum(%i)\n", thread_num);
  264. threadsinfo_t *threadsinfo_p = thread_getinfo();
  265. if(threadsinfo_p == NULL)
  266. return errno;
  267. if(thread_num >= threadsinfo_p->used)
  268. return EINVAL;
  269. threadinfo_t *threadinfo_p = &threadsinfo_p->threads[thread_num];
  270. threadinfo_p->state = STATE_EXIT;
  271. char **ptr = threadinfo_p->argv;
  272. if(ptr != NULL) {
  273. while(*ptr)
  274. free(*(ptr++));
  275. free(threadinfo_p->argv);
  276. }
  277. if(thread_num == (threadsinfo_p->used-1)) {
  278. threadsinfo_p->used--;
  279. printf_ddd("Debug3: thread_del_bynum(%i): there're %i threads left (#0).\n", thread_num, threadsinfo_p->used - threadsinfo_p->stacklen);
  280. return 0;
  281. }
  282. threadinfo_t *t = &threadsinfo_p->threads[threadsinfo_p->used-1];
  283. if(t->state == STATE_EXIT) {
  284. threadsinfo_p->used--;
  285. printf_ddd("Debug3: thread_del_bynum(): %i [%p] -> %i [%p]; left: %i\n",
  286. threadsinfo_p->used, t->pthread, thread_num, threadinfo_p->pthread, threadsinfo_p->used - threadsinfo_p->stacklen);
  287. memcpy(threadinfo_p, t, sizeof(*threadinfo_p));
  288. } else {
  289. #ifdef PARANOID
  290. if(threadsinfo_p->stacklen >= threadsinfo_p->allocated) {
  291. printf_e("Error: thread_del_bynum(): Threads metadata structures pointers stack overflowed!");
  292. return EINVAL;
  293. }
  294. #endif
  295. threadsinfo_p->threadsstack[threadsinfo_p->stacklen++] = threadinfo_p;
  296. }
  297. printf_ddd("Debug3: thread_del_bynum(%i): there're %i threads left (#1).\n", thread_num, threadsinfo_p->used - threadsinfo_p->stacklen);
  298. return 0;
  299. }
  300. int thread_gc(options_t *options_p) {
  301. int thread_num;
  302. time_t tm = time(NULL);
  303. printf_ddd("Debug3: thread_gc(): tm == %i; thread %p\n", tm, pthread_self());
  304. if(!options_p->flags[PTHREAD])
  305. return 0;
  306. threadsinfo_t *threadsinfo_p = thread_getinfo();
  307. if(threadsinfo_p == NULL)
  308. return errno;
  309. printf_dd("Debug2: thread_gc(): There're %i threads.\n", threadsinfo_p->used);
  310. thread_num=-1;
  311. while(++thread_num < threadsinfo_p->used) {
  312. int err;
  313. threadinfo_t *threadinfo_p = &threadsinfo_p->threads[thread_num];
  314. printf_ddd("Debug3: thread_gc(): Trying thread #%i (==%i) (state: %i; expire at: %i, now: %i, exitcode: %i, errcode: %i; i_p: %p; p: %p).\n",
  315. thread_num, threadinfo_p->thread_num, threadinfo_p->state, threadinfo_p->expiretime, tm, threadinfo_p->exitcode,
  316. threadinfo_p->errcode, threadinfo_p, threadinfo_p->pthread);
  317. if(threadinfo_p->state == STATE_EXIT)
  318. continue;
  319. if(threadinfo_p->expiretime && (threadinfo_p->expiretime <= tm)) {
  320. if(pthread_tryjoin_np(threadinfo_p->pthread, NULL)) { // TODO: check this pthread_tryjoin_np() on error returnings
  321. printf_e("Debug3: thread_gc(): Thread #%i is alive too long: %lu <= %lu (started at %lu)\n", thread_num, threadinfo_p->expiretime, tm, threadinfo_p->starttime);
  322. return ETIME;
  323. }
  324. }
  325. #ifndef VERYPARANOID
  326. if(threadinfo_p->state != STATE_TERM) {
  327. printf_ddd("Debug3: thread_gc(): Thread #%i is busy, skipping (#0).\n", thread_num);
  328. continue;
  329. }
  330. #endif
  331. printf_ddd("Debug3: thread_gc(): Trying to join thread #%i: %p\n", thread_num, threadinfo_p->pthread);
  332. #ifndef VERYPARANOID
  333. switch((err=pthread_join(threadinfo_p->pthread, NULL))) {
  334. #else
  335. switch((err=pthread_tryjoin_np(threadinfo_p->pthread, NULL))) {
  336. case EBUSY:
  337. printf_ddd("Debug3: thread_gc(): Thread #%i is busy, skipping (#1).\n", thread_num);
  338. continue;
  339. #endif
  340. case EDEADLK:
  341. case EINVAL:
  342. case 0:
  343. printf_ddd("Debug3: thread_gc(): Thread #%i is finished with exitcode %i (errcode %i), deleting. threadinfo_p == %p\n",
  344. thread_num, threadinfo_p->exitcode, threadinfo_p->errcode, threadinfo_p);
  345. break;
  346. default:
  347. printf_e("Error: Got error while pthread_join() or pthread_tryjoin_np(): %s (errno: %i).\n", strerror(err), err);
  348. return errno;
  349. }
  350. if(threadinfo_p->errcode) {
  351. printf_e("Error: Got error from thread #%i: errcode %i.\n", thread_num, threadinfo_p->errcode);
  352. thread_del_bynum(thread_num);
  353. return threadinfo_p->errcode;
  354. }
  355. if(thread_del_bynum(thread_num))
  356. return errno;
  357. }
  358. printf_ddd("Debug3: thread_gc(): There're %i threads left.\n", threadsinfo_p->used - threadsinfo_p->stacklen);
  359. return 0;
  360. }
  361. int thread_cleanup(options_t *options_p) {
  362. printf_ddd("Debug3: thread_cleanup(). Thread %p\n", pthread_self());
  363. threadsinfo_t *threadsinfo_p = thread_getinfo();
  364. if(threadsinfo_p == NULL)
  365. return errno;
  366. // Waiting for threads:
  367. printf_d("Debug: There're %i opened threads. Waiting.\n", threadsinfo_p->used);
  368. while(threadsinfo_p->used) {
  369. // int err;
  370. threadinfo_t *threadinfo_p = &threadsinfo_p->threads[--threadsinfo_p->used];
  371. if(threadinfo_p->state == STATE_EXIT)
  372. continue;
  373. //pthread_kill(threadinfo_p->pthread, SIGTERM);
  374. printf_d("Debug: killing pid %i with SIGTERM\n", threadinfo_p->child_pid);
  375. kill(threadinfo_p->child_pid, SIGTERM);
  376. pthread_join(threadinfo_p->pthread, NULL);
  377. printf_dd("Debug2: thread #%i exitcode: %i\n", threadsinfo_p->used, threadinfo_p->exitcode);
  378. /*
  379. if(threadinfo_p->callback)
  380. if((err=threadinfo_p->callback(options_p, threadinfo_p->argv)))
  381. printf_e("Warning: Got error from callback function: %s (errno: %i).\n", strerror(err), err);
  382. */
  383. char **ptr = threadinfo_p->argv;
  384. while(*ptr)
  385. free(*(ptr++));
  386. free(threadinfo_p->argv);
  387. }
  388. printf_ddd("Debug3: thread_cleanup(): All threads are closed.\n");
  389. // Freeing
  390. if(threadsinfo_p->allocated) {
  391. free(threadsinfo_p->threads);
  392. free(threadsinfo_p->threadsstack);
  393. }
  394. if(threadsinfo_p->mutex_init) {
  395. int i=0;
  396. while(i < PTHREAD_MUTEX_MAX) {
  397. pthread_mutex_destroy(&threadsinfo_p->mutex[i]);
  398. pthread_cond_destroy (&threadsinfo_p->cond [i]);
  399. i++;
  400. }
  401. }
  402. #ifdef PARANOID
  403. // Reseting
  404. memset(threadsinfo_p, 0, sizeof(*threadsinfo_p)); // Just in case;
  405. #endif
  406. printf_ddd("Debug3: thread_cleanup(): done.\n");
  407. return 0;
  408. }
  409. int *state_p = NULL;
  410. int exitcode = 0;
  411. int exec_argv(char **argv, int *child_pid DEBUGV(, int _rand)) {
  412. printf_ddd("Debug3: exec_argv(): Thread %p.\n", pthread_self());
  413. pid_t pid;
  414. int status;
  415. // Forking
  416. pid = fork();
  417. switch(pid) {
  418. case -1:
  419. printf_e("Error: Cannot fork(): %s (errno: %i).\n", strerror(errno), errno);
  420. return errno;
  421. case 0:
  422. execvp(argv[0], (char *const *)argv);
  423. return errno;
  424. }
  425. // printf_ddd("Debug3: exec_argv(): After fork thread %p"DEBUGV(" (%i)")".\n", pthread_self() DEBUGV(, _rand));
  426. // Setting *child_pid value
  427. if(child_pid)
  428. *child_pid = pid;
  429. // Waiting for process end
  430. #ifdef VERYPARANOID
  431. sigset_t sigset_exec, sigset_old;
  432. sigemptyset(&sigset_exec);
  433. sigaddset(&sigset_exec, SIGUSR_BLOPINT);
  434. pthread_sigmask(SIG_BLOCK, &sigset_exec, &sigset_old);
  435. #endif
  436. // printf_ddd("Debug3: exec_argv(): Pre-wait thread %p"DEBUGV(" (%i)")".\n", pthread_self() DEBUGV(, _rand));
  437. if(waitpid(pid, &status, 0) != pid) {
  438. printf_e("Error: Cannot waitid(): %s (errno: %i).\n", strerror(errno), errno);
  439. return errno;
  440. }
  441. // printf_ddd("Debug3: exec_argv(): After-wait thread %p"DEBUGV(" (%i)")".\n", pthread_self() DEBUGV(, _rand));
  442. #ifdef VERYPARANOID
  443. pthread_sigmask(SIG_SETMASK, &sigset_old, NULL);
  444. #endif
  445. // Return
  446. int exitcode = WEXITSTATUS(status);
  447. printf_ddd("Debug3: exec_argv(): execution completed with exitcode %i. Thread %p"DEBUGV(" (%i)")".\n", exitcode, pthread_self() DEBUGV(, _rand));
  448. return exitcode;
  449. }
  450. static inline int thread_exit(threadinfo_t *threadinfo_p, int exitcode DEBUGV(, int _rand)) {
  451. int err;
  452. threadinfo_p->exitcode = exitcode;
  453. #if _DEBUG | VERYPARANOID
  454. if(threadinfo_p->pthread != pthread_self()) {
  455. printf_e("Error: thread_exit(): pthread id mismatch! (i_p->p) %p != (p) %p"DEBUGV("; rand == %i")"\n", threadinfo_p->pthread, pthread_self() DEBUGV(, _rand));
  456. return EINVAL;
  457. }
  458. #endif
  459. if((err=exitcode_process(threadinfo_p->options_p, threadinfo_p->exitcode))) {
  460. printf_e("Error: thread_exit(): Bad exitcode %i (errcode %i)\n", exitcode, err);
  461. threadinfo_p->errcode = err;
  462. }
  463. if((threadinfo_p->callback) && !(err)) {
  464. if(threadinfo_p->options_p->flags[DEBUG]>2) {
  465. printf_ddd("Debug3: thread_exit(): thread %p, argv: \n", threadinfo_p->pthread);
  466. char **argv = threadinfo_p->argv;
  467. while(*argv) {
  468. printf_ddd("\t%p == %s\n", *argv, *argv);
  469. argv++;
  470. }
  471. }
  472. if((err=threadinfo_p->callback(threadinfo_p->options_p, threadinfo_p->argv))) {
  473. printf_e("Error: Got error from callback function: %s (errno: %i).\n", strerror(err), err);
  474. threadinfo_p->errcode = err;
  475. }
  476. }
  477. // Notifying the parent-thread, that it's time to collect garbage threads
  478. threadinfo_p->state = STATE_TERM;
  479. printf_ddd("Debug3: thread_exit(): thread %p is sending signal to sighandler to call GC\n", threadinfo_p->pthread);
  480. return pthread_kill(pthread_sighandler, SIGUSR_PTHREAD_GC);
  481. }
  482. static inline void so_call_sync_finished(int n, api_eventinfo_t *ei) {
  483. int i = 0;
  484. api_eventinfo_t *ei_i = ei;
  485. while(i < n) {
  486. #ifdef PARANOID
  487. if(ei_i->path == NULL) {
  488. printf_e("Warning: so_call_sync_finished(): ei_i->path == NULL\n");
  489. i++;
  490. continue;
  491. }
  492. #endif
  493. free((char *)ei_i->path);
  494. ei_i++;
  495. i++;
  496. }
  497. if(ei != NULL)
  498. free(ei);
  499. return;
  500. }
  501. int so_call_sync_thread(threadinfo_t *threadinfo_p) {
  502. printf_ddd("Debug3: so_call_exec_thread(): thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p\n",
  503. threadinfo_p->thread_num, threadinfo_p, threadinfo_p->pthread, pthread_self());
  504. options_t *options_p = threadinfo_p->options_p;
  505. int n = threadinfo_p->n;
  506. api_eventinfo_t *ei = threadinfo_p->ei;
  507. int ret = options_p->handler_funct.sync(n, ei);
  508. so_call_sync_finished(n, ei);
  509. int err;
  510. if((err=thread_exit(threadinfo_p, ret DEBUGV(, 0)))) {
  511. exitcode = err; // This's global variable "exitcode"
  512. pthread_kill(pthread_sighandler, SIGTERM);
  513. }
  514. return ret;
  515. }
  516. static inline int so_call_sync(options_t *options_p, int n, api_eventinfo_t *ei) {
  517. printf_dd("Debug2: so_call_exec(): n == %i\n", n);
  518. if(!options_p->flags[PTHREAD]) {
  519. int ret = options_p->handler_funct.sync(n, ei);
  520. so_call_sync_finished(n, ei);
  521. return ret;
  522. }
  523. threadinfo_t *threadinfo_p = thread_new();
  524. if(threadinfo_p == NULL)
  525. return errno;
  526. threadinfo_p->callback = NULL;
  527. threadinfo_p->argv = NULL;
  528. threadinfo_p->options_p = options_p;
  529. threadinfo_p->starttime = time(NULL);
  530. threadinfo_p->n = n;
  531. threadinfo_p->ei = ei;
  532. if(options_p->synctimeout)
  533. threadinfo_p->expiretime = threadinfo_p->starttime + options_p->synctimeout;
  534. if(pthread_create(&threadinfo_p->pthread, NULL, (void *(*)(void *))so_call_sync_thread, threadinfo_p)) {
  535. printf_e("Error: Cannot pthread_create(): %s (errno: %i).\n", strerror(errno), errno);
  536. return errno;
  537. }
  538. printf_ddd("Debug3: sync_exec_thread(): thread %p\n", threadinfo_p->pthread);
  539. return 0;
  540. }
  541. // === SYNC_EXEC() === {
  542. #define SYNC_EXEC(...) (options_p->flags[PTHREAD]?sync_exec_thread:sync_exec)(__VA_ARGS__)
  543. #define _sync_exec_getargv(argv, firstarg, COPYARG) {\
  544. va_list arglist;\
  545. va_start(arglist, firstarg);\
  546. \
  547. int i = 0;\
  548. do {\
  549. char *arg;\
  550. if(i >= MAXARGUMENTS) {\
  551. printf_e("Error: Too many arguments (%i >= %i).\n", i, MAXARGUMENTS);\
  552. return ENOMEM;\
  553. }\
  554. arg = (char *)va_arg(arglist, const char *const);\
  555. argv[i] = arg!=NULL ? COPYARG : NULL;\
  556. \
  557. printf_dd("Debug2: argv[%i] = %s\n", i, argv[i]);\
  558. } while(argv[i++] != NULL);\
  559. va_end(arglist);\
  560. }
  561. char *sync_path_abs2rel(options_t *options_p, const char *path_abs, size_t path_abs_len, size_t *path_rel_len_p, char *path_rel_oldptr) {
  562. if(path_abs == NULL)
  563. return NULL;
  564. if(path_abs_len == -1)
  565. path_abs_len = strlen(path_abs);
  566. size_t path_rel_len;
  567. char *path_rel;
  568. signed long path_rel_len_signed = path_abs_len - (options_p->watchdirlen+1);
  569. path_rel_len = (path_rel_len_signed > 0) ? path_rel_len_signed : 0;
  570. if(path_rel_oldptr == NULL) {
  571. path_rel = xmalloc(path_abs_len+1);
  572. } else {
  573. if(path_rel_len > *path_rel_len_p) {
  574. path_rel = xrealloc(path_rel_oldptr, path_rel_len+1);
  575. } else {
  576. path_rel = path_rel_oldptr;
  577. }
  578. }
  579. if(!path_rel_len) {
  580. path_rel[0] = 0;
  581. return path_rel;
  582. }
  583. memcpy(path_rel, &path_abs[options_p->watchdirlen+1], path_rel_len+1);
  584. #ifdef VERYPARANOID
  585. // Removing "/" on the end
  586. printf_ddd("Debug3: sync_path_abs2rel(): \"%s\" (len: %i) --%i--> \"%s\" (len: %i) + ",
  587. path_abs, path_abs_len, path_rel[path_rel_len - 1] == '/',
  588. options_p->watchdirwslash, options_p->watchdirlen+1);
  589. if(path_rel[path_rel_len - 1] == '/')
  590. path_rel[--path_rel_len] = 0x00;
  591. printf_ddd("\"%s\" (len: %i)\n", path_rel, path_rel_len);
  592. #endif
  593. if(path_rel_len_p != NULL)
  594. *path_rel_len_p = path_rel_len;
  595. return path_rel;
  596. }
  597. static inline int sync_exec(options_t *options_p, thread_callbackfunct_t callback, ...) {
  598. printf_dd("Debug2: sync_exec()\n");
  599. char **argv = (char **)xcalloc(sizeof(char *), MAXARGUMENTS);
  600. memset(argv, 0, sizeof(char *)*MAXARGUMENTS);
  601. _sync_exec_getargv(argv, callback, arg);
  602. alarm(options_p->synctimeout);
  603. int exitcode = exec_argv(argv, NULL DEBUGV(, 0));
  604. alarm(0);
  605. int ret;
  606. if((ret=exitcode_process(options_p, exitcode))) {
  607. printf_e("Error: sync_exec(): Bad exitcode %i\n", exitcode);
  608. goto l_sync_exec_end;
  609. }
  610. if(callback != NULL) {
  611. ret = callback(options_p, argv);
  612. if(ret) {
  613. printf_e("Error: Got error while callback(): %s (errno: %i).\n", strerror(ret), ret);
  614. goto l_sync_exec_end;
  615. }
  616. }
  617. l_sync_exec_end:
  618. free(argv);
  619. return ret;
  620. }
  621. int __sync_exec_thread(threadinfo_t *threadinfo_p) {
  622. char **argv = threadinfo_p->argv;
  623. #ifdef _DEBUG
  624. int _rand=rand();
  625. #endif
  626. printf_ddd("Debug3: __sync_exec_thread(): thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p"DEBUGV("; rand == %i")"\n",
  627. threadinfo_p->thread_num, threadinfo_p, threadinfo_p->pthread, pthread_self() DEBUGV(, _rand));
  628. int exec_exitcode = exec_argv(argv, &threadinfo_p->child_pid DEBUGV(, _rand));
  629. int err;
  630. if((err=thread_exit(threadinfo_p, exec_exitcode DEBUGV(, _rand)))) {
  631. exitcode = err; // This's global variable "exitcode"
  632. pthread_kill(pthread_sighandler, SIGTERM);
  633. }
  634. printf_ddd("Debug3: __sync_exec_thread(): thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p"DEBUGV("; rand == %i")"; errcode %i\n",
  635. threadinfo_p->thread_num, threadinfo_p, threadinfo_p->pthread, pthread_self(), DEBUGV(_rand,) threadinfo_p->errcode);
  636. return exec_exitcode;
  637. }
  638. static inline int sync_exec_thread(options_t *options_p, thread_callbackfunct_t callback, ...) {
  639. printf_dd("Debug2: sync_exec_thread()\n");
  640. char **argv = (char **)xcalloc(sizeof(char *), MAXARGUMENTS);
  641. memset(argv, 0, sizeof(char *)*MAXARGUMENTS);
  642. _sync_exec_getargv(argv, callback, strdup(arg));
  643. threadinfo_t *threadinfo_p = thread_new();
  644. if(threadinfo_p == NULL)
  645. return errno;
  646. threadinfo_p->callback = callback;
  647. threadinfo_p->argv = argv;
  648. threadinfo_p->options_p = options_p;
  649. threadinfo_p->starttime = time(NULL);
  650. if(options_p->synctimeout)
  651. threadinfo_p->expiretime = threadinfo_p->starttime + options_p->synctimeout;
  652. if(pthread_create(&threadinfo_p->pthread, NULL, (void *(*)(void *))__sync_exec_thread, threadinfo_p)) {
  653. printf_e("Error: Cannot pthread_create(): %s (errno: %i).\n", strerror(errno), errno);
  654. return errno;
  655. }
  656. printf_ddd("Debug3: sync_exec_thread(): thread %p\n", threadinfo_p->pthread);
  657. return 0;
  658. }
  659. // } === SYNC_EXEC() ===
  660. static int sync_queuesync(const char *fpath_rel, eventinfo_t *evinfo, options_t *options_p, indexes_t *indexes_p, queue_id_t queue_id) {
  661. printf_ddd("Debug3: sync_queuesync(\"%s\", ...): fsize == %lu; tres == %lu, queue_id == \n", fpath_rel, evinfo->fsize, options_p->bfilethreshold, queue_id);
  662. if(queue_id == QUEUE_AUTO)
  663. queue_id = (evinfo->fsize > options_p->bfilethreshold) ? QUEUE_BIGFILE : QUEUE_NORMAL;
  664. queueinfo_t *queueinfo = &options_p->_queues[queue_id];
  665. if(!queueinfo->stime)
  666. queueinfo->stime = time(NULL);
  667. // char *fpath_rel = sync_path_abs2rel(options_p, fpath, -1, NULL, NULL);
  668. // Filename can contain "\n" character that conflicts with event-row separator of list-files.
  669. if(strchr(fpath_rel, '\n')) {
  670. // At the moment, we will just ignore events of such files :(
  671. printf_ddd("Debug3: sync_queuesync(): There's \"\\n\" character in path \"%s\". Ignoring it :(. Feedback to: https://github.com/xaionaro/clsync/issues/12\n", fpath_rel);
  672. return 0;
  673. }
  674. eventinfo_t *evinfo_dup = (eventinfo_t *)xmalloc(sizeof(*evinfo_dup));
  675. memcpy(evinfo_dup, evinfo, sizeof(*evinfo_dup));
  676. #ifdef CLUSTER_SUPPORT
  677. if(options_p->cluster_iface)
  678. cluster_capture(fpath_rel);
  679. #endif
  680. return indexes_queueevent(indexes_p, strdup(fpath_rel), evinfo_dup, queue_id);
  681. }
  682. int sync_initialsync_walk(options_t *options_p, const char *dirpath, indexes_t *indexes_p, queue_id_t queue_id, initsync_t initsync) {
  683. int ret = 0;
  684. const char *rootpaths[] = {dirpath, NULL};
  685. eventinfo_t evinfo;
  686. FTS *tree;
  687. rule_t *rules_p = options_p->rules;
  688. printf_dd("Debug2: sync_initialsync_walk(options_p, \"%s\", indexes_p, %i, %i).\n", dirpath, queue_id, initsync);
  689. char skip_rules = (initsync==INITSYNC_FULL) && options_p->flags[INITFULL];
  690. char rsync_and_prefer_excludes = options_p->flags[RSYNC] && !options_p->flags[RSYNC_PREFERINCLUDE];
  691. if((!options_p->flags[RSYNC_PREFERINCLUDE]) && skip_rules)
  692. return 0;
  693. tree = fts_open((char *const *)&rootpaths, FTS_NOCHDIR|FTS_PHYSICAL, NULL);
  694. if(tree == NULL) {
  695. printf_e("Error: Cannot fts_open() on \"%s\": %s (errno: %i).\n", dirpath, strerror(errno), errno);
  696. return errno;
  697. }
  698. memset(&evinfo, 0, sizeof(evinfo));
  699. FTSENT *node;
  700. char *path_rel = NULL;
  701. size_t path_rel_len = 0;
  702. while((node = fts_read(tree))) {
  703. switch(node->fts_info) {
  704. // Duplicates:
  705. case FTS_DP:
  706. continue;
  707. // To sync:
  708. case FTS_DEFAULT:
  709. case FTS_SL:
  710. case FTS_SLNONE:
  711. case FTS_F:
  712. case FTS_D:
  713. case FTS_DOT:
  714. break;
  715. // Error cases:
  716. case FTS_ERR:
  717. case FTS_NS:
  718. case FTS_NSOK:
  719. case FTS_DNR:
  720. case FTS_DC:
  721. if(errno == ENOENT) {
  722. printf_d("Debug: Got error while fts_read(): %s (errno: %i; fts_info: %i).\n", strerror(errno), errno, node->fts_info);
  723. continue;
  724. } else {
  725. printf_e("Error: Got error while fts_read(): %s (errno: %i; fts_info: %i).\n", strerror(errno), errno, node->fts_info);
  726. ret = errno;
  727. goto l_sync_initialsync_walk_end;
  728. }
  729. default:
  730. printf_e("Error: Got unknown fts_info vlaue while fts_read(): %i.\n", node->fts_info);
  731. ret = EINVAL;
  732. goto l_sync_initialsync_walk_end;
  733. }
  734. path_rel = sync_path_abs2rel(options_p, node->fts_path, -1, &path_rel_len, path_rel);
  735. printf_ddd("Debug3: sync_initialsync_walk(): Pointing to \"%s\" (node->fts_info == %i)\n", path_rel, node->fts_info);
  736. if(!skip_rules) {
  737. ruleaction_t perm = rules_getperm(path_rel, node->fts_statp->st_mode, rules_p, RA_WALK|RA_MONITOR);
  738. if(!(perm&RA_WALK)) {
  739. printf_ddd("Debug3: sync_initialsync_walk(): Rejecting to walk into \"%s\".\n", path_rel);
  740. fts_set(tree, node, FTS_SKIP);
  741. }
  742. if(!(perm&RA_MONITOR)) {
  743. printf_ddd("Debug3: sync_initialsync_walk(): Excluding \"%s\".\n", path_rel);
  744. if(rsync_and_prefer_excludes) {
  745. if(queue_id == QUEUE_AUTO) {
  746. int i=0;
  747. while(i<QUEUE_MAX)
  748. indexes_addexclude(indexes_p, strdup(path_rel), i++);
  749. } else
  750. indexes_addexclude(indexes_p, strdup(path_rel), queue_id);
  751. }
  752. continue;
  753. }
  754. }
  755. evinfo.fsize = node->fts_statp->st_size;
  756. switch(options_p->notifyengine) {
  757. #ifdef FANOTIFY_SUPPORT
  758. case NE_FANOTIFY:
  759. break;
  760. #endif
  761. case NE_INOTIFY:
  762. evinfo.evmask = IN_CREATE_SELF;
  763. break;
  764. }
  765. if(!rsync_and_prefer_excludes) {
  766. printf_ddd("Debug2: sync_initialsync_walk(): queueing \"%s\" (depth: %i) with int-flags %p\n", node->fts_path, node->fts_level, (void *)(unsigned long)evinfo.flags);
  767. int _ret = sync_queuesync(path_rel, &evinfo, options_p, indexes_p, queue_id);
  768. if(_ret) {
  769. printf_e("Error: Got error while queueing \"%s\": %s (errno: %i).\n", node->fts_path, strerror(errno), errno);
  770. ret = errno;
  771. goto l_sync_initialsync_walk_end;
  772. }
  773. }
  774. }
  775. if(errno) {
  776. printf_e("Error: Got error while fts_read() and related routines: %s (errno: %i).\n", strerror(errno), errno);
  777. ret = errno;
  778. goto l_sync_initialsync_walk_end;
  779. }
  780. if(fts_close(tree)) {
  781. printf_e("Error: Got error while fts_close(): %s (errno: %i).\n", strerror(errno), errno);
  782. ret = errno;
  783. goto l_sync_initialsync_walk_end;
  784. }
  785. l_sync_initialsync_walk_end:
  786. if(path_rel != NULL)
  787. free(path_rel);
  788. return ret;
  789. }
  790. int sync_initialsync(const char *path, options_t *options_p, indexes_t *indexes_p, initsync_t initsync) {
  791. printf_ddd("Debug3: sync_initialsync(\"%s\", options_p, indexes_p, %i)\n", path, initsync);
  792. #ifdef CLUSTER_SUPPORT
  793. if(initsync == INITSYNC_FULL) {
  794. if(options_p->cluster_iface)
  795. return cluster_initialsync();
  796. }
  797. #endif
  798. queue_id_t queue_id = (initsync==INITSYNC_FULL) ? QUEUE_INSTANT : QUEUE_NORMAL;
  799. // non-RSYNC case:
  800. if(!options_p->flags[RSYNC]) {
  801. printf_ddd("Debug3: sync_initialsync(): syncing \"%s\"\n", path);
  802. /*
  803. if(options_p->flags[PTHREAD])
  804. return sync_exec_thread(options_p, NULL, options_p->handlerfpath, "initialsync", options_p->label, path, NULL);
  805. else
  806. return sync_exec (options_p, NULL, options_p->handlerfpath, "initialsync", options_p->label, path, NULL);*/
  807. if(options_p->flags[ENABLEINITIALSYNC]) {
  808. if(options_p->flags[SYNCHANDLERSO]) {
  809. api_eventinfo_t ei = {0};
  810. ei.evmask = IN_CREATE|IN_ISDIR;
  811. ei.flags = EVIF_RECURSIVELY;
  812. ei.path_len = strlen(path);
  813. ei.path = strdup(path);
  814. return so_call_sync(options_p, 1, &ei);
  815. } else {
  816. return SYNC_EXEC(
  817. options_p,
  818. NULL,
  819. options_p->handlerfpath,
  820. "initialsync",
  821. options_p->label,
  822. path,
  823. NULL
  824. );
  825. }
  826. }
  827. #ifdef DOXYGEN
  828. sync_exec(NULL, NULL); sync_exec_thread(NULL, NULL);
  829. #endif
  830. int ret = sync_initialsync_walk(options_p, path, indexes_p, queue_id, initsync);
  831. if(ret)
  832. printf_e("Error: sync_initialsync(): Cannot get synclist: %s (errno: %i)\n", strerror(ret), ret);
  833. return ret;
  834. }
  835. // RSYNC case:
  836. if(!options_p->flags[RSYNC_PREFERINCLUDE]) {
  837. queueinfo_t *queueinfo = &options_p->_queues[queue_id];
  838. if(!queueinfo->stime)
  839. queueinfo->stime = time(NULL); // Useful for debugging
  840. eventinfo_t *evinfo = (eventinfo_t *)xmalloc(sizeof(*evinfo));
  841. memset(evinfo, 0, sizeof(*evinfo));
  842. evinfo->flags |= EVIF_RECURSIVELY;
  843. // Searching for excludes
  844. int ret = sync_initialsync_walk(options_p, path, indexes_p, queue_id, initsync);
  845. if(ret) {
  846. printf_e("Error: sync_initialsync(): Cannot get exclude what to exclude: %s (errno: %i)\n", strerror(ret), ret);
  847. return ret;
  848. }
  849. printf_ddd("Debug3: sync_initialsync(): queueing \"%s\" with int-flags %p\n", path, (void *)(unsigned long)evinfo->flags);
  850. char *path_rel = sync_path_abs2rel(options_p, path, -1, NULL, NULL);
  851. return indexes_queueevent(indexes_p, path_rel, evinfo, queue_id);
  852. }
  853. // Searching for includes
  854. return sync_initialsync_walk(options_p, path, indexes_p, queue_id, initsync);
  855. }
  856. int sync_notify_mark(int notify_d, options_t *options_p, const char *accpath, const char *path, size_t pathlen, indexes_t *indexes_p) {
  857. printf_ddd("Debug3: sync_notify_mark(..., \"%s\", %i,...)\n", path, pathlen);
  858. int wd = indexes_fpath2wd(indexes_p, path);
  859. if(wd != -1) {
  860. printf_d("Debug: \"%s\" is already marked (wd: %i). Skipping.\n", path, wd);
  861. return wd;
  862. }
  863. switch(options_p->notifyengine) {
  864. #ifdef FANOTIFY_SUPPORT
  865. case NE_FANOTIFY: {
  866. int fanotify_d = notify_d;
  867. if((wd = fanotify_mark(fanotify_d, FAN_MARK_ADD | FAN_MARK_DONT_FOLLOW,
  868. FANOTIFY_MARKMASK, AT_FDCWD, accpath)) == -1)
  869. {
  870. if(errno == ENOENT)
  871. return -2;
  872. printf_e("Error: Cannot fanotify_mark() on \"%s\": %s (errno: %i).\n",
  873. path, strerror(errno), errno);
  874. return -1;
  875. }
  876. break;
  877. }
  878. #endif
  879. case NE_INOTIFY: {
  880. int inotify_d = notify_d;
  881. if((wd = inotify_add_watch(inotify_d, accpath, INOTIFY_MARKMASK)) == -1) {
  882. if(errno == ENOENT)
  883. return -2;
  884. printf_e("Error: Cannot inotify_add_watch() on \"%s\": %s (errno: %i).\n",
  885. path, strerror(errno), errno);
  886. return -1;
  887. }
  888. break;
  889. }
  890. default: {
  891. printf_e("Error: unknown notify-engine: %i\n", options_p->notifyengine);
  892. errno = EINVAL;
  893. return -1;
  894. }
  895. }
  896. indexes_add_wd(indexes_p, wd, path, pathlen);
  897. return wd;
  898. }
  899. #ifdef CLUSTER_SUPPORT
  900. static inline int sync_mark_walk_cluster_modtime_update(options_t *options_p, const char *path, short int dirlevel, mode_t st_mode) {
  901. if(options_p->cluster_iface) {
  902. int ret=cluster_modtime_update(path, dirlevel, st_mode);
  903. if(ret) printf_e("Error: sync_mark_walk() cannot cluster_modtime_update(): %s (errno %i)\n", strerror(ret), ret);
  904. return ret;
  905. }
  906. return 0;
  907. }
  908. #endif
  909. int sync_mark_walk(int notify_d, options_t *options_p, const char *dirpath, indexes_t *indexes_p) {
  910. int ret = 0;
  911. const char *rootpaths[] = {dirpath, NULL};
  912. FTS *tree;
  913. rule_t *rules_p = options_p->rules;
  914. printf_dd("Debug2: sync_mark_walk(%i, options_p, \"%s\", indexes_p).\n", notify_d, dirpath);
  915. printf_funct my_printf_e = STATE_STARTING(state_p) ? printf_e : _printf_dd;
  916. tree = fts_open((char *const *)&rootpaths, FTS_NOCHDIR|FTS_PHYSICAL|FTS_NOSTAT, NULL);
  917. if(tree == NULL) {
  918. my_printf_e("Error: Cannot fts_open() on \"%s\": %s (errno: %i).\n", dirpath, strerror(errno), errno);
  919. return errno;
  920. }
  921. FTSENT *node;
  922. char *path_rel = NULL;
  923. size_t path_rel_len = 0;
  924. while((node = fts_read(tree))) {
  925. #ifdef CLUSTER_SUPPORT
  926. int ret;
  927. #endif
  928. printf_dd("Debug3: walking: \"%s\" (depth %u): fts_info == %i\n", node->fts_path, node->fts_level, node->fts_info);
  929. switch(node->fts_info) {
  930. // Duplicates:
  931. case FTS_DP:
  932. continue;
  933. case FTS_DEFAULT:
  934. case FTS_SL:
  935. case FTS_SLNONE:
  936. case FTS_F:
  937. case FTS_NSOK:
  938. #ifdef CLUSTER_SUPPORT
  939. if((ret=sync_mark_walk_cluster_modtime_update(options_p, node->fts_path, node->fts_level, S_IFREG)))
  940. goto l_sync_mark_walk_end;
  941. #endif
  942. continue;
  943. // To mark:
  944. case FTS_D:
  945. case FTS_DOT:
  946. #ifdef CLUSTER_SUPPORT
  947. if((ret=sync_mark_walk_cluster_modtime_update(options_p, node->fts_path, node->fts_level, S_IFDIR)))
  948. goto l_sync_mark_walk_end;
  949. #endif
  950. break;
  951. // Error cases:
  952. case FTS_ERR:
  953. case FTS_NS:
  954. case FTS_DNR:
  955. case FTS_DC:
  956. if(errno == ENOENT) {
  957. printf_d("Debug: Got error while fts_read(): %s (errno: %i; fts_info: %i).\n", strerror(errno), errno, node->fts_info);
  958. continue;
  959. } else {
  960. my_printf_e("Error: Got error while fts_read(): %s (errno: %i; fts_info: %i).\n", strerror(errno), errno, node->fts_info);
  961. ret = errno;
  962. goto l_sync_mark_walk_end;
  963. }
  964. default:
  965. my_printf_e("Error: Got unknown fts_info vlaue while fts_read(): %i.\n", node->fts_info);
  966. ret = EINVAL;
  967. goto l_sync_mark_walk_end;
  968. }
  969. path_rel = sync_path_abs2rel(options_p, node->fts_path, -1, &path_rel_len, path_rel);
  970. ruleaction_t perm = rules_search_getperm(path_rel, S_IFDIR, rules_p, RA_WALK, NULL);
  971. if(!(perm&RA_WALK)) {
  972. fts_set(tree, node, FTS_SKIP);
  973. continue;
  974. }
  975. printf_dd("Debug2: marking \"%s\" (depth %u)\n", node->fts_path, node->fts_level);
  976. int wd = sync_notify_mark(notify_d, options_p, node->fts_accpath, node->fts_path, node->fts_pathlen, indexes_p);
  977. if(wd == -1) {
  978. my_printf_e("Error: Got error while notify-marking \"%s\": %s (errno: %i).\n", node->fts_path, strerror(errno), errno);
  979. ret = errno;
  980. goto l_sync_mark_walk_end;
  981. }
  982. printf_dd("Debug2: watching descriptor is %i.\n", wd);
  983. }
  984. if(errno) {
  985. my_printf_e("Error: Got error while fts_read() and related routines: %s (errno: %i).\n", strerror(errno), errno);
  986. ret = errno;
  987. goto l_sync_mark_walk_end;
  988. }
  989. if(fts_close(tree)) {
  990. my_printf_e("Error: Got error while fts_close(): %s (errno: %i).\n", strerror(errno), errno);
  991. ret = errno;
  992. goto l_sync_mark_walk_end;
  993. }
  994. l_sync_mark_walk_end:
  995. if(path_rel != NULL)
  996. free(path_rel);
  997. return ret;
  998. }
  999. int sync_notify_init(options_t *options_p) {
  1000. switch(options_p->notifyengine) {
  1001. #ifdef FANOTIFY_SUPPORT
  1002. case NE_FANOTIFY: {
  1003. int fanotify_d = fanotify_init(FANOTIFY_FLAGS, FANOTIFY_EVFLAGS);
  1004. if(fanotify_d == -1) {
  1005. printf_e("Error: cannot fanotify_init(%i, %i): %s (errno: %i).\n", FANOTIFY_FLAGS, FANOTIFY_EVFLAGS, strerror(errno), errno);
  1006. return -1;
  1007. }
  1008. return fanotify_d;
  1009. }
  1010. #endif
  1011. case NE_INOTIFY: {
  1012. #ifdef OLDSYSTEM
  1013. int inotify_d = inotify_init();
  1014. #else
  1015. int inotify_d = inotify_init1(INOTIFY_FLAGS);
  1016. #endif
  1017. if(inotify_d == -1) {
  1018. printf_e("Error: cannot inotify_init(%i): %s (errno: %i).\n", INOTIFY_FLAGS, strerror(errno), errno);
  1019. return -1;
  1020. }
  1021. return inotify_d;
  1022. }
  1023. }
  1024. printf_e("Error: unknown notify-engine: %i\n", options_p->notifyengine);
  1025. errno = EINVAL;
  1026. return -1;
  1027. }
  1028. static inline int sync_dosync_exec(options_t *options_p, const char *evmask_str, const char *fpath) {
  1029. /*
  1030. if(options_p->flags[PTHREAD])
  1031. return sync_exec_thread(options_p, NULL, options_p->handlerfpath, "sync", options_p->label, evmask_str, fpath, NULL);
  1032. else
  1033. return sync_exec (options_p, NULL, options_p->handlerfpath, "sync", options_p->label, evmask_str, fpath, NULL);*/
  1034. return SYNC_EXEC(options_p, NULL, options_p->handlerfpath, "sync", options_p->label, evmask_str, fpath, NULL);
  1035. #ifdef DOXYGEN
  1036. sync_exec(NULL, NULL); sync_exec_thread(NULL, NULL);
  1037. #endif
  1038. }
  1039. static int sync_dosync(const char *fpath, uint32_t evmask, options_t *options_p, indexes_t *indexes_p) {
  1040. int ret;
  1041. #ifdef CLUSTER_SUPPORT
  1042. ret = cluster_lock(fpath);
  1043. if(ret) return ret;
  1044. #endif
  1045. char *evmask_str = xmalloc(1<<8);
  1046. sprintf(evmask_str, "%u", evmask);
  1047. ret = sync_dosync_exec(options_p, evmask_str, fpath);
  1048. free(evmask_str);
  1049. #ifdef CLUSTER_SUPPORT
  1050. ret = cluster_unlock_all();
  1051. #endif
  1052. return ret;
  1053. }
  1054. void _sync_idle_dosync_collectedexcludes(gpointer fpath_gp, gpointer dummy, gpointer arg_gp) {
  1055. char *fpath = (char *)fpath_gp;
  1056. indexes_t *indexes_p = ((struct dosync_arg *)arg_gp)->indexes_p;
  1057. printf_ddd("Debug3: _sync_idle_dosync_collectedexcludes(): \"%s\".\n", fpath);
  1058. indexes_addexclude_aggr(indexes_p, strdup(fpath));
  1059. return;
  1060. }
  1061. void _sync_idle_dosync_collectedevents(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp) {
  1062. char *fpath = (char *)fpath_gp;
  1063. eventinfo_t *evinfo = (eventinfo_t *)evinfo_gp;
  1064. int *evcount_p =&((struct dosync_arg *)arg_gp)->evcount;
  1065. // FILE *outf = ((struct dosync_arg *)arg_gp)->outf;
  1066. options_t *options_p = ((struct dosync_arg *)arg_gp)->options_p;
  1067. indexes_t *indexes_p = ((struct dosync_arg *)arg_gp)->indexes_p;
  1068. queue_id_t queue_id = (queue_id_t)((struct dosync_arg *)arg_gp)->data;
  1069. printf_ddd("Debug3: _sync_idle_dosync_collectedevents(): queue_id == %i.\n", queue_id);
  1070. if(options_p->listoutdir == NULL) {
  1071. printf_ddd("Debug3: _sync_idle_dosync_collectedevents(): calling sync_dosync()\n");
  1072. int ret;
  1073. if((ret=sync_dosync(fpath, evinfo->evmask, options_p, indexes_p))) {
  1074. printf_e("Error: unable to sync \"%s\" (evmask %i): %s (errno: %i).\n", fpath, evinfo->evmask, strerror(ret), ret);
  1075. exit(ret); // TODO: remove this from here
  1076. }
  1077. }
  1078. int isnew = 0;
  1079. eventinfo_t *evinfo_idx = indexes_fpath2ei(indexes_p, fpath);
  1080. int _queue_id = 0;
  1081. while(_queue_id < QUEUE_MAX) {
  1082. if(_queue_id == queue_id) {
  1083. _queue_id++;
  1084. continue;
  1085. }
  1086. indexes_removefromqueue(indexes_p, fpath, _queue_id);
  1087. if(!g_hash_table_size(indexes_p->fpath2ei_coll_ht[_queue_id]))
  1088. options_p->_queues[_queue_id].stime = 0;
  1089. _queue_id++;
  1090. }
  1091. if(evinfo_idx == NULL) {
  1092. evinfo_idx = (eventinfo_t *)xmalloc(sizeof(*evinfo_idx));
  1093. memset(evinfo_idx, 0, sizeof(*evinfo_idx));
  1094. isnew++;
  1095. (*evcount_p)++;
  1096. }
  1097. evinfo_idx->evmask |= evinfo->evmask;
  1098. evinfo_idx->flags |= evinfo->flags;
  1099. if(isnew)
  1100. indexes_fpath2ei_add(indexes_p, strdup(fpath), evinfo_idx);
  1101. else
  1102. free(fpath);
  1103. return;
  1104. }
  1105. int sync_idle_dosync_collectedevents_cleanup(options_t *options_p, char **argv) {
  1106. if(options_p->flags[DONTUNLINK])
  1107. return 0;
  1108. printf_ddd("Debug3: sync_idle_dosync_collectedevents_cleanup(): thread %p\n", pthread_self());
  1109. if(options_p->flags[RSYNC] >= 2) {
  1110. int ret0, ret1;
  1111. if(argv[5] == NULL) {
  1112. printf_e("Error: Unexpected *argv[] end.");
  1113. return EINVAL;
  1114. }
  1115. printf_ddd("Debug3: unlink()-ing \"%s\"\n", argv[5]);
  1116. ret0 = unlink(argv[5]);
  1117. if(options_p->flags[RSYNC_PREFERINCLUDE])
  1118. return ret0;
  1119. if(argv[7] == NULL) {
  1120. printf_e("Error: Unexpected *argv[] end.");
  1121. return EINVAL;
  1122. }
  1123. printf_ddd("Debug3: unlink()-ing \"%s\"\n", argv[7]);
  1124. ret1 = unlink(argv[7]);
  1125. return ret0 == 0 ? ret1 : ret0;
  1126. }
  1127. if(argv[3] == NULL) {
  1128. printf_e("Error: Unexpected *argv[] end.");
  1129. return EINVAL;
  1130. }
  1131. int ret0;
  1132. printf_ddd("Debug3: unlink()-ing \"%s\"\n", argv[3]);
  1133. ret0 = unlink(argv[3]);
  1134. if(options_p->flags[RSYNC]) {
  1135. int ret1;
  1136. // There's no exclude file-list if "--rsyncpreferinclude" is enabled, so return
  1137. if(options_p->flags[RSYNC_PREFERINCLUDE])
  1138. return ret0;
  1139. if(argv[4] == NULL)
  1140. return ret0;
  1141. if(*argv[4] == 0x00)
  1142. return ret0;
  1143. printf_ddd("Debug3: unlink()-ing \"%s\"\n", argv[4]);
  1144. ret1 = unlink(argv[4]); // remove exclude list, too
  1145. return ret0 == 0 ? ret1 : ret0;
  1146. }
  1147. return ret0;
  1148. }
  1149. int sync_idle_dosync_collectedevents_aggrqueue(queue_id_t queue_id, options_t *options_p, indexes_t *indexes_p, struct dosync_arg *dosync_arg) {
  1150. // char *buf, *fpath;
  1151. time_t tm = time(NULL);
  1152. queueinfo_t *queueinfo = &options_p->_queues[queue_id];
  1153. if((queueinfo->stime + queueinfo->collectdelay > tm) && (queueinfo->collectdelay != COLLECTDELAY_INSTANT)) {
  1154. printf_ddd("Debug3: sync_idle_dosync_collectedevents_procqueue(%i, ...): too early (%i + %i > %i).\n", queue_id, queueinfo->stime, queueinfo->collectdelay, tm);
  1155. return 0;
  1156. }
  1157. queueinfo->stime = 0;
  1158. int evcount_real = g_hash_table_size(indexes_p->fpath2ei_coll_ht[queue_id]);
  1159. printf_ddd("Debug3: sync_idle_dosync_collectedevents_procqueue(%i, ...): evcount_real == %i\n", queue_id, evcount_real);
  1160. if(evcount_real<=0) {
  1161. printf_ddd("Debug3: sync_idle_dosync_collectedevents_procqueue(%i, ...): no events, return 0.\n", queue_id);
  1162. return 0;
  1163. }
  1164. g_hash_table_foreach(indexes_p->fpath2ei_coll_ht[queue_id], _sync_idle_dosync_collectedevents, dosync_arg);
  1165. g_hash_table_remove_all(indexes_p->fpath2ei_coll_ht[queue_id]);
  1166. if(!options_p->flags[RSYNC_PREFERINCLUDE]) {
  1167. g_hash_table_foreach(indexes_p->exc_fpath_coll_ht[queue_id], _sync_idle_dosync_collectedexcludes, dosync_arg);
  1168. g_hash_table_remove_all(indexes_p->exc_fpath_coll_ht[queue_id]);
  1169. }
  1170. return 0;
  1171. }
  1172. int sync_idle_dosync_collectedevents_uniqfname(options_t *options_p, char *fpath, char *name) {
  1173. pid_t pid = getpid();
  1174. time_t tm = time(NULL);
  1175. struct stat64 stat64;
  1176. int counter = 0;
  1177. do {
  1178. snprintf(fpath, PATH_MAX, "%s/.clsync-%s.%u.%lu.%lu.%u", options_p->listoutdir, name, pid, (long)pthread_self(), (unsigned long)tm, rand()); // To be unique
  1179. lstat64(fpath, &stat64);
  1180. if(counter++ > COUNTER_LIMIT) {
  1181. printf_e("Error: Cannot file unused filename for list-file. The last try was \"%s\".\n", fpath);
  1182. return ELOOP;
  1183. }
  1184. } while(errno != ENOENT); // TODO: find another way to check if the object exists
  1185. errno=0;
  1186. return 0;
  1187. }
  1188. int sync_idle_dosync_collectedevents_listcreate(struct dosync_arg *dosync_arg_p, char *name) {
  1189. printf_ddd("Debug3: Creating %s file\n", name);
  1190. char *fpath = dosync_arg_p->outf_path;
  1191. options_t *options_p = dosync_arg_p->options_p;
  1192. int ret;
  1193. if((ret=sync_idle_dosync_collectedevents_uniqfname(options_p, fpath, name))) {
  1194. printf_e("Error: sync_idle_dosync_collectedevents_listcreate: Cannot get unique file name.\n");
  1195. return ret;
  1196. }
  1197. dosync_arg_p->outf = fopen(fpath, "w");
  1198. if(dosync_arg_p->outf == NULL) {
  1199. printf_e("Error: Cannot open \"%s\" as file for writing: %s (errno: %i).\n", fpath, strerror(errno), errno);
  1200. return errno;
  1201. }
  1202. setbuffer(dosync_arg_p->outf, dosync_arg_p->buf, BUFSIZ);
  1203. printf_ddd("Debug3: Created list-file \"%s\"\n", fpath);
  1204. dosync_arg_p->linescount = 0;
  1205. return 0;
  1206. }
  1207. gboolean sync_idle_dosync_collectedevents_aggrout(gpointer outline_gp, gpointer evinfo_gp, gpointer arg_gp) {
  1208. struct dosync_arg *dosync_arg_p = (struct dosync_arg *)arg_gp;
  1209. char *outline = (char *)outline_gp;
  1210. FILE *outf = dosync_arg_p->outf;
  1211. // options_t *options_p = dosync_arg_p->options_p;
  1212. // indexes_t *indexes_p = dosync_arg_p->indexes_p;
  1213. printf_ddd("Debug3: sync_idle_dosync_collectedevents_aggrout(): \"%s\"\n", outline);
  1214. fprintf(outf, "%s\n", outline);
  1215. return TRUE;
  1216. }
  1217. gboolean sync_idle_dosync_collectedevents_rsync_exclistpush(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp) {
  1218. struct dosync_arg *dosync_arg_p = (struct dosync_arg *)arg_gp;
  1219. char *fpath = (char *)fpath_gp;
  1220. FILE *excf = dosync_arg_p->outf;
  1221. // options_t *options_p = dosync_arg_p->options_p;
  1222. // indexes_t *indexes_p = dosync_arg_p->indexes_p;
  1223. printf_ddd("Debug3: sync_idle_dosync_collectedevents_rsync_exclistpush(): \"%s\"\n", fpath);
  1224. size_t fpath_len = strlen(fpath);
  1225. char *fpathwslash;
  1226. if(fpath_len>0) {
  1227. // Prepending with the slash
  1228. fpathwslash = alloca(fpath_len+2);
  1229. fpathwslash[0] = '/';
  1230. memcpy(&fpathwslash[1], fpath, fpath_len+1);
  1231. } else {
  1232. // In this case slash is not required
  1233. fpathwslash = fpath;
  1234. }
  1235. printf_ddd("Debug3: Adding to exclude-file: \"%s\"\n", fpathwslash);
  1236. fprintf(excf, "%s\n", fpathwslash);
  1237. return TRUE;
  1238. }
  1239. int sync_idle_dosync_collectedevents_commitpart(struct dosync_arg *dosync_arg_p) {
  1240. options_t *options_p = dosync_arg_p->options_p;
  1241. printf_ddd("Debug3: Committing the file (flags[RSYNC] == %i; flags[SYNCHANDLERSO] == %i)\n", options_p->flags[RSYNC], options_p->flags[SYNCHANDLERSO]);
  1242. if(!options_p->flags[SYNCHANDLERSO]) {
  1243. fclose(dosync_arg_p->outf);
  1244. dosync_arg_p->outf = NULL;
  1245. }
  1246. if(dosync_arg_p->evcount > 0) {
  1247. /*
  1248. if(options_p->flags[PTHREAD])
  1249. return sync_exec_thread(options_p,
  1250. sync_idle_dosync_collectedevents_cleanup,
  1251. options_p->handlerfpath,
  1252. options_p->flags[RSYNC]?"rsynclist":"synclist",
  1253. options_p->label,
  1254. dosync_arg_p->outf_path,
  1255. *(dosync_arg_p->outf_path)?dosync_arg_p->outf_path:NULL,
  1256. NULL);
  1257. else
  1258. return sync_exec (options_p,
  1259. sync_idle_dosync_collectedevents_cleanup,
  1260. options_p->handlerfpath,
  1261. options_p->flags[RSYNC]?"rsynclist":"synclist",
  1262. options_p->label,
  1263. dosync_arg_p->outf_path,
  1264. *(dosync_arg_p->outf_path)?dosync_arg_p->outf_path:NULL,
  1265. NULL);*/
  1266. printf_ddd("Debug3: %s [%s] (%p) -> %s [%s]\n", options_p->watchdir, options_p->watchdirwslash, options_p->watchdirwslash,
  1267. options_p->destdir?options_p->destdir:"", options_p->destdirwslash?options_p->destdirwslash:"");
  1268. if(options_p->flags[SYNCHANDLERSO]) {
  1269. api_eventinfo_t *ei = dosync_arg_p->api_ei;
  1270. return so_call_sync(options_p, dosync_arg_p->evcount, ei);
  1271. }
  1272. if(options_p->flags[RSYNC] >= 2)
  1273. return SYNC_EXEC(options_p,
  1274. sync_idle_dosync_collectedevents_cleanup,
  1275. options_p->handlerfpath,
  1276. "--inplace",
  1277. "-aH",
  1278. "--delete-before",
  1279. *(dosync_arg_p->excf_path) ? "--exclude-from" : "--include-from",
  1280. *(dosync_arg_p->excf_path) ? dosync_arg_p->excf_path : dosync_arg_p->outf_path,
  1281. *(dosync_arg_p->excf_path) ? "--include-from" : "--exclude=*",
  1282. *(dosync_arg_p->excf_path) ? dosync_arg_p->outf_path : options_p->watchdirwslash,
  1283. *(dosync_arg_p->excf_path) ? "--exclude=*" : options_p->destdirwslash,
  1284. *(dosync_arg_p->excf_path) ? options_p->watchdirwslash : NULL,
  1285. *(dosync_arg_p->excf_path) ? options_p->destdirwslash : NULL,
  1286. NULL);
  1287. return SYNC_EXEC(options_p,
  1288. sync_idle_dosync_collectedevents_cleanup,
  1289. options_p->handlerfpath,
  1290. options_p->flags[RSYNC]?"rsynclist":"synclist",
  1291. options_p->label,
  1292. dosync_arg_p->outf_path,
  1293. *(dosync_arg_p->excf_path)?dosync_arg_p->excf_path:NULL,
  1294. NULL);
  1295. }
  1296. return 0;
  1297. #ifdef DOXYGEN
  1298. sync_exec(NULL, NULL); sync_exec_thread(NULL, NULL);
  1299. #endif
  1300. }
  1301. gboolean sync_idle_dosync_collectedevents_listpush(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp) {
  1302. struct dosync_arg *dosync_arg_p = (struct dosync_arg *)arg_gp;
  1303. char *fpath = (char *)fpath_gp;
  1304. eventinfo_t *evinfo = (eventinfo_t *)evinfo_gp;
  1305. //int *evcount_p =&dosync_arg_p->evcount;
  1306. FILE *outf = dosync_arg_p->outf;
  1307. options_t *options_p = dosync_arg_p->options_p;
  1308. int *linescount_p =&dosync_arg_p->linescount;
  1309. indexes_t *indexes_p = dosync_arg_p->indexes_p;
  1310. api_eventinfo_t **api_ei_p=&dosync_arg_p->api_ei;
  1311. int *api_ei_count_p =&dosync_arg_p->api_ei_count;
  1312. printf_ddd("Debug3: sync_idle_dosync_collectedevents_listpush(): \"%s\" with int-flags %p\n", fpath, (void *)(unsigned long)evinfo->flags);
  1313. // so-module case:
  1314. if(options_p->flags[SYNCHANDLERSO]) {
  1315. api_eventinfo_t *ei = &(*api_ei_p)[(*api_ei_count_p)++];
  1316. ei->evmask = evinfo->evmask;
  1317. ei->flags = evinfo->flags;
  1318. ei->path_len = strlen(fpath);
  1319. ei->path = strdup(fpath);
  1320. return TRUE;
  1321. }
  1322. if(!options_p->flags[RSYNC]) {
  1323. // non-RSYNC case
  1324. if(options_p->flags[SYNCLISTSIMPLIFY])
  1325. fprintf(outf, "%s\n", fpath);
  1326. else
  1327. fprintf(outf, "sync %s %i %s\n", options_p->label, evinfo->evmask, fpath);
  1328. return TRUE;
  1329. }
  1330. // RSYNC case
  1331. size_t fpath_len = strlen(fpath);
  1332. char *fpathwslash;
  1333. if(fpath_len>0) {
  1334. // Prepending with the slash
  1335. fpathwslash = alloca(fpath_len+2);
  1336. fpathwslash[0] = '/';
  1337. memcpy(&fpathwslash[1], fpath, fpath_len+1);
  1338. } else {
  1339. // In this case slash is not required
  1340. fpathwslash = fpath;
  1341. }
  1342. if(options_p->rsyncinclimit && (*linescount_p >= options_p->rsyncinclimit)) {
  1343. int ret;
  1344. // TODO: optimize this out {
  1345. char newexc_path[PATH_MAX+1];
  1346. if((ret=sync_idle_dosync_collectedevents_uniqfname(options_p, newexc_path, "exclist"))) {
  1347. printf_e("Error: sync_idle_dosync_collectedevents_listcreate: Cannot get unique file name.\n");
  1348. exit(ret);
  1349. }
  1350. if((ret=fileutils_copy(dosync_arg_p->excf_path, newexc_path))) {
  1351. printf_e("Error: sync_idle_dosync_collectedevents_listcreate: Cannot copy file \"%s\" to \"%s\".\n", dosync_arg_p->excf_path, newexc_path);
  1352. exit(ret);
  1353. }
  1354. // }
  1355. // That's required to copy excludes' list file for every rsync execution.
  1356. // The problem appears do to unlink()-ing the excludes' list file on callback function
  1357. // "sync_idle_dosync_collectedevents_cleanup()" of every execution.
  1358. if((ret=sync_idle_dosync_collectedevents_commitpart(dosync_arg_p))) {
  1359. printf_e("Error: sync_idle_dosync_collectedevents_listpush(): Cannot commit list-file \"%s\": %s (errno: %i)\n", dosync_arg_p->outf_path, strerror(ret), ret);
  1360. exit(ret); // TODO: replace with kill(0, ...);
  1361. }
  1362. strcpy(dosync_arg_p->excf_path, newexc_path); // TODO: optimize this out
  1363. if((ret=sync_idle_dosync_collectedevents_listcreate(dosync_arg_p, "list"))) {
  1364. printf_e("Error: sync_idle_dosync_collectedevents_listpush(): Cannot create new list-file: %s (errno: %i)\n", strerror(ret), ret);
  1365. exit(ret); // TODO: replace with kill(0, ...);
  1366. }
  1367. outf = dosync_arg_p->outf;
  1368. }
  1369. char *end=fpathwslash;
  1370. if(evinfo->flags & EVIF_RECURSIVELY) {
  1371. printf_ddd("Debug3: sync_idle_dosync_collectedevents_listpush(): Recursively \"%s\": Adding to rsynclist: \"%s/***\".\n", fpathwslash, fpathwslash);
  1372. fprintf(outf, "%s/***\n", fpathwslash);
  1373. (*linescount_p)++;
  1374. }
  1375. while(end != NULL) {
  1376. if(*fpathwslash == 0x00)
  1377. break;
  1378. printf_ddd("Debug3: sync_idle_dosync_collectedevents_listpush(): Non-recursively \"%s\": Adding to rsynclist: \"%s\".\n", fpathwslash, fpathwslash);
  1379. indexes_outaggr_add(indexes_p, strdup(fpathwslash));
  1380. (*linescount_p)++;
  1381. end = strrchr(fpathwslash, '/');
  1382. if(end == NULL)
  1383. break;
  1384. if(end - fpathwslash <= 0)
  1385. break;
  1386. *end = 0x00;
  1387. };
  1388. return TRUE;
  1389. }
  1390. int sync_idle_dosync_collectedevents(options_t *options_p, indexes_t *indexes_p) {
  1391. printf_ddd("Debug3: sync_idle_dosync_collectedevents()\n");
  1392. struct dosync_arg dosync_arg = {0};
  1393. dosync_arg.options_p = options_p;
  1394. dosync_arg.indexes_p = indexes_p;
  1395. char isrsyncpreferexclude = options_p->flags[RSYNC] && (!options_p->flags[RSYNC_PREFERINCLUDE]);
  1396. #ifdef PARANOID
  1397. if(options_p->listoutdir != NULL) {
  1398. g_hash_table_remove_all(indexes_p->fpath2ei_ht);
  1399. if(isrsyncpreferexclude)
  1400. g_hash_table_remove_all(indexes_p->exc_fpath_ht);
  1401. }
  1402. #endif
  1403. // Setting the time to sync not before it:
  1404. options_p->synctime = time(NULL) + options_p->syncdelay;
  1405. printf_ddd("Debug3: Next sync will be not before: %u\n", options_p->synctime);
  1406. int queue_id=0;
  1407. while(queue_id < QUEUE_MAX) {
  1408. int ret;
  1409. queue_id_t *queue_id_p = (queue_id_t *)&dosync_arg.data;
  1410. *queue_id_p = queue_id;
  1411. ret = sync_idle_dosync_collectedevents_aggrqueue(queue_id, options_p, indexes_p, &dosync_arg);
  1412. if(ret) {
  1413. printf_e("Error: Got error while processing queue #%i\n: %s (errno: %i).\n", queue_id, strerror(ret), ret);
  1414. g_hash_table_remove_all(indexes_p->fpath2ei_ht);
  1415. if(isrsyncpreferexclude)
  1416. g_hash_table_remove_all(indexes_p->exc_fpath_ht);
  1417. return ret;
  1418. }
  1419. queue_id++;
  1420. }
  1421. if(!dosync_arg.evcount) {
  1422. printf_ddd("Debug3: sync_idle_dosync_collectedevents(): Summary events' count is zero. Return 0.\n");
  1423. return 0;
  1424. }
  1425. if(options_p->flags[SYNCHANDLERSO]) {
  1426. //dosync_arg.evcount = g_hash_table_size(indexes_p->fpath2ei_ht);
  1427. printf_ddd("Debug3: sync_idle_dosync_collectedevents(): There's %i events. Processing.\n", dosync_arg.evcount);
  1428. dosync_arg.api_ei = (api_eventinfo_t *)xmalloc(dosync_arg.evcount * sizeof(*dosync_arg.api_ei));
  1429. }
  1430. if(options_p->listoutdir != NULL) {
  1431. int ret;
  1432. if(!options_p->flags[SYNCHANDLERSO]) {
  1433. *(dosync_arg.excf_path) = 0x00;
  1434. if(isrsyncpreferexclude) {
  1435. if((ret=sync_idle_dosync_collectedevents_listcreate(&dosync_arg, "exclist"))) {
  1436. printf_e("Error: Cannot create list-file: %s (errno: %i)\n", strerror(ret), ret);
  1437. return ret;
  1438. }
  1439. #ifdef PARANOID
  1440. g_hash_table_remove_all(indexes_p->out_lines_aggr_ht);
  1441. #endif
  1442. g_hash_table_foreach_remove(indexes_p->exc_fpath_ht, sync_idle_dosync_collectedevents_rsync_exclistpush, &dosync_arg);
  1443. g_hash_table_foreach_remove(indexes_p->out_lines_aggr_ht, sync_idle_dosync_collectedevents_aggrout, &dosync_arg);
  1444. fclose(dosync_arg.outf);
  1445. strcpy(dosync_arg.excf_path, dosync_arg.outf_path); // TODO: remove this strcpy()
  1446. }
  1447. if((ret=sync_idle_dosync_collectedevents_listcreate(&dosync_arg, "list"))) {
  1448. printf_e("Error: Cannot create list-file: %s (errno: %i)\n", strerror(ret), ret);
  1449. return ret;
  1450. }
  1451. }
  1452. #ifdef PARANOID
  1453. g_hash_table_remove_all(indexes_p->out_lines_aggr_ht);
  1454. #endif
  1455. g_hash_table_foreach_remove(indexes_p->fpath2ei_ht, sync_idle_dosync_collectedevents_listpush, &dosync_arg);
  1456. if(options_p->flags[RSYNC])
  1457. g_hash_table_foreach_remove(indexes_p->out_lines_aggr_ht, sync_idle_dosync_collectedevents_aggrout, &dosync_arg);
  1458. if((ret=sync_idle_dosync_collectedevents_commitpart(&dosync_arg))) {
  1459. printf_e("Error: Cannot submit to sync the list \"%s\": %s (errno: %i)\n", dosync_arg.outf_path, strerror(ret), ret);
  1460. // TODO: free dosync_arg.api_ei on case of error
  1461. return ret;
  1462. }
  1463. }
  1464. return 0;
  1465. }
  1466. int sync_idle(int notify_d, options_t *options_p, indexes_t *indexes_p) {
  1467. int ret=thread_gc(options_p);
  1468. if(ret) return ret;
  1469. printf_ddd("Debug3: sync_idle(): calling sync_idle_dosync_collectedevents()\n");
  1470. #ifdef CLUSTER_SUPPORT
  1471. ret = cluster_lock_byindexes();
  1472. if(ret) return ret;
  1473. #endif
  1474. ret = sync_idle_dosync_collectedevents(options_p, indexes_p);
  1475. if(ret) return ret;
  1476. #ifdef CLUSTER_SUPPORT
  1477. ret = cluster_unlock_all();
  1478. if(ret) return ret;
  1479. #endif
  1480. return 0;
  1481. }
  1482. #ifdef FANOTIFY_SUPPORT
  1483. int sync_fanotify_loop(int fanotify_d, options_t *options_p, indexes_t *indexes_p) {
  1484. struct fanotify_event_metadata buf[BUFSIZ/sizeof(struct fanotify_event_metadata) + 1];
  1485. int state = STATE_RUNNING;
  1486. state_p = &state;
  1487. while(state != STATE_EXIT) {
  1488. struct fanotify_event_metadata *metadata;
  1489. size_t len = read(fanotify_d, (void *)buf, sizeof(buf)-sizeof(*buf));
  1490. metadata=buf;
  1491. if(len == -1) {
  1492. printf_e("Error: cannot read(%i, &metadata, sizeof(metadata)): %s (errno: %i).\n", fanotify_d, strerror(errno), errno);
  1493. return errno;
  1494. }
  1495. while(FAN_EVENT_OK(metadata, len)) {
  1496. printf_dd("Debug2: metadata->pid: %i; metadata->fd: %i\n", metadata->pid, metadata->fd);
  1497. if (metadata->fd != FAN_NOFD) {
  1498. if (metadata->fd >= 0) {
  1499. char *fpath = fd2fpath_malloc(metadata->fd);
  1500. sync_queuesync(fpath_rel, 0, options_p, indexes_p, QUEUE_AUTO);
  1501. printf_dd("Debug2: Event %i on \"%s\".\n", metadata->mask, fpath);
  1502. free(fpath);
  1503. }
  1504. }
  1505. close(metadata->fd);
  1506. metadata = FAN_EVENT_NEXT(metadata, len);
  1507. }
  1508. int ret;
  1509. if((ret=sync_idle(fanotify_d, options_p, indexes_p))) {
  1510. printf_e("Error: got error while sync_idle(): %s (errno: %i).\n", strerror(ret), ret);
  1511. return ret;
  1512. }
  1513. }
  1514. return 0;
  1515. }
  1516. #endif
  1517. int sync_inotify_wait(int inotify_d, options_t *options_p, indexes_t *indexes_p) {
  1518. static struct timeval tv;
  1519. time_t tm = time(NULL);
  1520. long delay = ((unsigned long)~0 >> 1);
  1521. threadsinfo_t *threadsinfo_p = thread_getinfo();
  1522. pthread_cond_broadcast(&threadsinfo_p->cond[PTHREAD_MUTEX_STATE]);
  1523. pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);
  1524. printf_ddd("Debug3: sync_inotify_wait()\n");
  1525. fd_set rfds;
  1526. FD_ZERO(&rfds);
  1527. FD_SET(inotify_d, &rfds);
  1528. long queue_id = 0;
  1529. while(queue_id < QUEUE_MAX) {
  1530. queueinfo_t *queueinfo = &options_p->_queues[queue_id++];
  1531. if(!queueinfo->stime)
  1532. continue;
  1533. if(queueinfo->collectdelay == COLLECTDELAY_INSTANT) {
  1534. printf_ddd("Debug3: sync_inotify_wait(): There're events in instant queue (#%i), don't waiting.\n", queue_id-1);
  1535. return 0;
  1536. }
  1537. int qdelay = queueinfo->stime + queueinfo->collectdelay - tm;
  1538. printf_ddd("Debug3: sync_inotify_wait(): queue #%i: %i %i %i -> %i\n", queue_id-1, queueinfo->stime, queueinfo->collectdelay, tm, qdelay);
  1539. if(qdelay < -(long)options_p->syncdelay)
  1540. qdelay = -(long)options_p->syncdelay;
  1541. delay = MIN(delay, qdelay);
  1542. }
  1543. long synctime_delay = ((long)options_p->synctime) - ((long)tm);
  1544. synctime_delay = synctime_delay > 0 ? synctime_delay : 0;
  1545. printf_ddd("Debug3: delay = MAX(%li, %li)\n", delay, synctime_delay);
  1546. delay = MAX(delay, synctime_delay);
  1547. delay = delay > 0 ? delay : 0;
  1548. if(options_p->flags[PTHREAD]) {
  1549. time_t _thread_nextexpiretime = thread_nextexpiretime();
  1550. printf_ddd("Debug3: thread_nextexpiretime == %i\n", _thread_nextexpiretime);
  1551. if(_thread_nextexpiretime) {
  1552. long thread_expiredelay = (long)thread_nextexpiretime() - (long)tm + 1; // +1 is to make "tm>threadinfo_p->expiretime" after select() definitely TRUE
  1553. printf_ddd("Debug3: thread_expiredelay == %i\n", thread_expiredelay);
  1554. thread_expiredelay = thread_expiredelay > 0 ? thread_expiredelay : 0;
  1555. printf_ddd("Debug3: delay = MIN(%li, %li)\n", delay, thread_expiredelay);
  1556. delay = MIN(delay, thread_expiredelay);
  1557. }
  1558. }
  1559. if((!delay) || (*state_p != STATE_RUNNING))
  1560. return 0;
  1561. printf_ddd("Debug3: sync_inotify_wait(): sleeping for %li second(s).\n", SLEEP_SECONDS);
  1562. sleep(SLEEP_SECONDS);
  1563. delay = ((long)delay)>SLEEP_SECONDS ? delay-SLEEP_SECONDS : 0;
  1564. tv.tv_sec = delay;
  1565. tv.tv_usec = 0;
  1566. pthread_mutex_lock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);
  1567. if(*state_p != STATE_RUNNING)
  1568. return 0;
  1569. printf_ddd("Debug3: sync_inotify_wait(): select with timeout %li secs.\n", tv.tv_sec);
  1570. int ret = select(inotify_d+1, &rfds, NULL, NULL, &tv);
  1571. if((ret == -1) && (errno == EINTR)) {
  1572. errno = 0;
  1573. return 0;
  1574. }
  1575. return ret;
  1576. }
  1577. void sync_inotify_handle_dosync(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp) {
  1578. char *fpath_rel = (char *)fpath_gp;
  1579. eventinfo_t *evinfo = (eventinfo_t *)evinfo_gp;
  1580. options_t *options_p = ((struct dosync_arg *)arg_gp)->options_p;
  1581. indexes_t *indexes_p = ((struct dosync_arg *)arg_gp)->indexes_p;
  1582. sync_queuesync(fpath_rel, evinfo, options_p, indexes_p, QUEUE_AUTO);
  1583. return;
  1584. }
  1585. #define SYNC_INOTIFY_HANDLE_CONTINUE {\
  1586. ptr += sizeof(struct inotify_event) + event->len;\
  1587. count++;\
  1588. continue;\
  1589. }
  1590. int sync_inotify_handle(int inotify_d, options_t *options_p, indexes_t *indexes_p) {
  1591. static struct timeval tv={0};
  1592. int count = 0;
  1593. fd_set rfds;
  1594. FD_ZERO(&rfds);
  1595. FD_SET(inotify_d, &rfds);
  1596. char *path_rel = NULL;
  1597. size_t path_rel_len = 0;
  1598. char *path_full = 0;
  1599. size_t path_full_size = 0;
  1600. while(select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
  1601. char buf[BUFSIZ + 1];
  1602. size_t r = read(inotify_d, buf, BUFSIZ);
  1603. if(r <= 0) {
  1604. printf_e("Error: Got error while reading events from inotify with read(): %s (errno: %i).\n", strerror(errno), errno);
  1605. count = -1;
  1606. goto l_sync_inotify_handle_end;
  1607. }
  1608. #ifdef PARANOID
  1609. g_hash_table_remove_all(indexes_p->fpath2ei_ht);
  1610. #endif
  1611. char *ptr = buf;
  1612. char *end = &buf[r];
  1613. while(ptr < end) {
  1614. struct inotify_event *event = (struct inotify_event *)ptr;
  1615. // Removing stale wd-s
  1616. if(event->mask & IN_IGNORED) {
  1617. printf_dd("Debug2: Cleaning up info about watch descriptor %i.\n", event->wd);
  1618. indexes_remove_bywd(indexes_p, event->wd);
  1619. SYNC_INOTIFY_HANDLE_CONTINUE;
  1620. }
  1621. // Getting path
  1622. char *fpath = indexes_wd2fpath(indexes_p, event->wd);
  1623. if(fpath == NULL) {
  1624. printf_dd("Debug2: Event %p on stale watch (wd: %i).\n", (void *)(long)event->mask, event->wd);
  1625. SYNC_INOTIFY_HANDLE_CONTINUE;
  1626. }
  1627. printf_dd("Debug2: Event %p on \"%s\" (wd: %i; fpath: \"%s\").\n", (void *)(long)event->mask, event->len>0?event->name:"", event->wd, fpath);
  1628. // Getting full path
  1629. size_t path_full_memreq = strlen(fpath) + event->len + 2;
  1630. if(path_full_size < path_full_memreq) {
  1631. path_full = xrealloc(path_full, path_full_memreq);
  1632. path_full_size = path_full_memreq;
  1633. }
  1634. if(event->len>0)
  1635. sprintf(path_full, "%s/%s", fpath, event->name);
  1636. else
  1637. sprintf(path_full, "%s", fpath);
  1638. // Getting infomation about file/dir/etc
  1639. struct stat64 lstat;
  1640. mode_t st_mode;
  1641. size_t st_size;
  1642. if(lstat64(path_full, &lstat)) {
  1643. printf_dd("Debug2: Cannot lstat(\"%s\", lstat): %s (errno: %i). Seems, that the object disappeared.\n", path_full, strerror(errno), errno);
  1644. if(event->mask & IN_ISDIR)
  1645. st_mode = S_IFDIR;
  1646. else
  1647. st_mode = S_IFREG;
  1648. st_size = 0;
  1649. } else {
  1650. st_mode = lstat.st_mode;
  1651. st_size = lstat.st_size;
  1652. }
  1653. // Checking by filter rules
  1654. path_rel = sync_path_abs2rel(options_p, path_full, -1, &path_rel_len, path_rel);
  1655. ruleaction_t perm = rules_getperm(path_rel, st_mode, options_p->rules, RA_WALK|RA_MONITOR);
  1656. if(!(perm&(RA_MONITOR|RA_WALK))) {
  1657. SYNC_INOTIFY_HANDLE_CONTINUE;
  1658. }
  1659. // Handling different cases
  1660. if(event->mask & IN_ISDIR) {
  1661. if(event->mask & (IN_CREATE|IN_MOVED_TO)) { // Appeared
  1662. // If new dir is created
  1663. int ret;
  1664. if(perm & RA_WALK) {
  1665. ret = sync_mark_walk(inotify_d, options_p, path_full, indexes_p);
  1666. if(ret) {
  1667. printf_d("Debug: Seems, that directory \"%s\" disappeared, while trying to mark it.\n", path_full);
  1668. SYNC_INOTIFY_HANDLE_CONTINUE;
  1669. }
  1670. ret = sync_initialsync(path_full, options_p, indexes_p, INITSYNC_SUBDIR);
  1671. if(ret) {
  1672. printf_e("Error: Got error from sync_initialsync(): %s (errno %i)\n", strerror(ret), ret);
  1673. errno = ret;
  1674. count=-1;
  1675. goto l_sync_inotify_handle_end;
  1676. }
  1677. }
  1678. SYNC_INOTIFY_HANDLE_CONTINUE;
  1679. } else
  1680. if(event->mask & (IN_DELETE|IN_MOVED_FROM)) { // Disappered
  1681. printf_dd("Debug2: Disappeared \"%s\".\n", path_full);
  1682. }
  1683. }
  1684. if(!(perm&RA_WALK)) {
  1685. SYNC_INOTIFY_HANDLE_CONTINUE;
  1686. }
  1687. // Locally queueing the event
  1688. int isnew = 0;
  1689. eventinfo_t *evinfo = indexes_fpath2ei(indexes_p, path_rel);
  1690. if(evinfo == NULL) {
  1691. evinfo = (eventinfo_t *)xmalloc(sizeof(*evinfo));
  1692. memset(evinfo, 0, sizeof(*evinfo));
  1693. evinfo->fsize = st_size;
  1694. evinfo->wd = event->wd;
  1695. isnew++;
  1696. printf_ddd("Debug3: sync_inotify_handle(): new event: fsize == %i; wd == %i\n", evinfo->fsize, evinfo->wd);
  1697. }
  1698. evinfo->evmask |= event->mask;
  1699. if(isnew)
  1700. indexes_fpath2ei_add(indexes_p, strdup(path_rel), evinfo);
  1701. SYNC_INOTIFY_HANDLE_CONTINUE;
  1702. }
  1703. // Globally queueing captured events
  1704. struct dosync_arg dosync_arg;
  1705. dosync_arg.options_p = options_p;
  1706. dosync_arg.indexes_p = indexes_p;
  1707. printf_ddd("Debug3: sync_inotify_handle(): collected %i events per this time.\n", g_hash_table_size(indexes_p->fpath2ei_ht));
  1708. g_hash_table_foreach(indexes_p->fpath2ei_ht, sync_inotify_handle_dosync, &dosync_arg);
  1709. g_hash_table_remove_all(indexes_p->fpath2ei_ht);
  1710. }
  1711. l_sync_inotify_handle_end:
  1712. if(path_full != NULL)
  1713. free(path_full);
  1714. if(path_rel != NULL)
  1715. free(path_rel);
  1716. return count;
  1717. }
  1718. #define SYNC_INOTIFY_LOOP_IDLE {\
  1719. int ret;\
  1720. if((ret=sync_idle(inotify_d, options_p, indexes_p))) {\
  1721. printf_e("Error: got error while sync_idle(): %s (errno: %i).\n", strerror(ret), ret);\
  1722. return ret;\
  1723. }\
  1724. }
  1725. #define SYNC_INOTIFY_LOOP_CONTINUE_UNLOCK {\
  1726. pthread_cond_broadcast(&threadsinfo_p->cond[PTHREAD_MUTEX_STATE]);\
  1727. pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);\
  1728. continue;\
  1729. }
  1730. int sync_inotify_loop(int inotify_d, options_t *options_p, indexes_t *indexes_p) {
  1731. int state = STATE_INITSYNC;
  1732. int ret;
  1733. state_p = &state;
  1734. while(state != STATE_EXIT) {
  1735. int events;
  1736. threadsinfo_t *threadsinfo_p = thread_getinfo();
  1737. pthread_mutex_lock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);
  1738. printf_ddd("Debug3: sync_inotify_loop(): current state is %i\n", state);
  1739. events = 0;
  1740. switch(state) {
  1741. case STATE_PTHREAD_GC:
  1742. if(thread_gc(options_p)) {
  1743. state=STATE_EXIT;
  1744. break;
  1745. }
  1746. state = STATE_RUNNING;
  1747. SYNC_INOTIFY_LOOP_CONTINUE_UNLOCK;
  1748. case STATE_INITSYNC:
  1749. pthread_cond_broadcast(&threadsinfo_p->cond[PTHREAD_MUTEX_STATE]);
  1750. pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);
  1751. ret = sync_initialsync(options_p->watchdir, options_p, indexes_p, INITSYNC_FULL);
  1752. if(ret) return ret;
  1753. state = STATE_RUNNING;
  1754. continue;
  1755. case STATE_RUNNING:
  1756. events = sync_inotify_wait(inotify_d, options_p, indexes_p);
  1757. if(state != STATE_RUNNING)
  1758. SYNC_INOTIFY_LOOP_CONTINUE_UNLOCK;
  1759. break;
  1760. case STATE_REHASH:
  1761. printf_d("Debug: sync_inotify_loop(): rehashing.\n");
  1762. main_rehash(options_p);
  1763. state = STATE_RUNNING;
  1764. SYNC_INOTIFY_LOOP_CONTINUE_UNLOCK;
  1765. case STATE_TERM:
  1766. state = STATE_EXIT;
  1767. case STATE_EXIT:
  1768. SYNC_INOTIFY_LOOP_CONTINUE_UNLOCK;
  1769. }
  1770. pthread_cond_broadcast(&threadsinfo_p->cond[PTHREAD_MUTEX_STATE]);
  1771. pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);
  1772. if(events == 0) {
  1773. printf_dd("Debug2: sync_inotify_wait(%i, options_p, indexes_p) timed-out.\n", inotify_d);
  1774. SYNC_INOTIFY_LOOP_IDLE;
  1775. continue; // Timeout
  1776. }
  1777. if(events < 0) {
  1778. printf_e("Error: Got error while waiting for event from inotify with select(): %s (errno: %i).\n", strerror(errno), errno);
  1779. return errno;
  1780. }
  1781. int count=sync_inotify_handle(inotify_d, options_p, indexes_p);
  1782. if(count <= 0) {
  1783. printf_e("Error: Cannot handle with inotify events: %s (errno: %i).\n", strerror(errno), errno);
  1784. return errno;
  1785. }
  1786. // SYNC_INOTIFY_LOOP_IDLE;
  1787. }
  1788. SYNC_INOTIFY_LOOP_IDLE;
  1789. return exitcode;
  1790. #ifdef DOXYGEN
  1791. sync_idle(0, NULL, NULL);
  1792. #endif
  1793. }
  1794. int sync_notify_loop(int notify_d, options_t *options_p, indexes_t *indexes_p) {
  1795. switch(options_p->notifyengine) {
  1796. #ifdef FANOTIFY_SUPPORT
  1797. case NE_FANOTIFY:
  1798. return sync_fanotify_loop(notify_d, options_p, indexes_p);
  1799. #endif
  1800. case NE_INOTIFY:
  1801. return sync_inotify_loop (notify_d, options_p, indexes_p);
  1802. }
  1803. printf_e("Error: unknown notify-engine: %i\n", options_p->notifyengine);
  1804. errno = EINVAL;
  1805. return -1;
  1806. }
  1807. void sync_sig_int(int signal) {
  1808. printf_dd("Debug2: sync_sig_int(%i): Thread %p\n", signal, pthread_self());
  1809. return;
  1810. }
  1811. int sync_switch_state(pthread_t pthread_parent, int newstate) {
  1812. if(state_p == NULL) {
  1813. printf_ddd("Debug3: sync_switch_state(%p, %i), but state_p == NULL\n", pthread_parent, newstate);
  1814. return 0;
  1815. }
  1816. printf_ddd("Debug3: sync_switch_state(%p, %i)\n", pthread_parent, newstate);
  1817. // Getting mutexes
  1818. threadsinfo_t *threadsinfo_p = thread_getinfo();
  1819. if(threadsinfo_p == NULL) {
  1820. // If no mutexes, just change the state
  1821. goto l_sync_parent_interrupt_end;
  1822. }
  1823. if(!threadsinfo_p->mutex_init) {
  1824. // If no mutexes, just change the state
  1825. goto l_sync_parent_interrupt_end;
  1826. }
  1827. pthread_mutex_t *pthread_mutex_state = &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE];
  1828. pthread_cond_t *pthread_cond_state = &threadsinfo_p->cond [PTHREAD_MUTEX_STATE];
  1829. // Locking all necessary mutexes
  1830. if(pthread_mutex_trylock(pthread_mutex_state) == EBUSY) {
  1831. while(1) {
  1832. struct timespec time_timeout;
  1833. clock_gettime(CLOCK_REALTIME, &time_timeout);
  1834. time_timeout.tv_sec++;
  1835. // time_timeout.tv_sec = now.tv_sec;
  1836. printf_ddd("Debug3: sync_switch_state(): pthread_cond_timedwait() until %li.%li\n", time_timeout.tv_sec, time_timeout.tv_nsec);
  1837. if(pthread_cond_timedwait(pthread_cond_state, pthread_mutex_state, &time_timeout) != ETIMEDOUT)
  1838. break;
  1839. printf_ddd("Debug3: sending signal to interrupt blocking operations like select()-s and so on\n");
  1840. pthread_kill(pthread_parent, SIGUSR_BLOPINT);
  1841. #ifdef VERYPARANOID
  1842. int i=0;
  1843. if(++i > KILL_TIMEOUT) {
  1844. printf_e("Error: sync_switch_state(): Seems we got a deadlock.");
  1845. return EDEADLK;
  1846. }
  1847. #endif
  1848. }
  1849. }
  1850. // Changing the state
  1851. *state_p = newstate;
  1852. #ifdef VERYPARANOID
  1853. pthread_kill(pthread_parent, SIGUSR_BLOPINT);
  1854. #endif
  1855. // Unlocking mutexes
  1856. printf_ddd("Debug3: sync_switch_state(): pthread_mutex_unlock(). New state is %i.\n", *state_p);
  1857. pthread_cond_broadcast(pthread_cond_state);
  1858. pthread_mutex_unlock(pthread_mutex_state);
  1859. return 0;
  1860. l_sync_parent_interrupt_end:
  1861. *state_p = newstate;
  1862. pthread_kill(pthread_parent, SIGUSR_BLOPINT);
  1863. return 0;
  1864. }
  1865. int *sync_sighandler_exitcode_p = NULL;
  1866. int sync_sighandler(sighandler_arg_t *sighandler_arg_p) {
  1867. int signal, ret;
  1868. // options_t *options_p = sighandler_arg_p->options_p;
  1869. // indexes_t *indexes_p = sighandler_arg_p->indexes_p;
  1870. pthread_t pthread_parent = sighandler_arg_p->pthread_parent;
  1871. sigset_t *sigset_p = sighandler_arg_p->sigset_p;
  1872. int *exitcode_p = sighandler_arg_p->exitcode_p;
  1873. sync_sighandler_exitcode_p = exitcode_p;
  1874. while(1) {
  1875. printf_ddd("Debug3: sync_sighandler(): waiting for signal\n");
  1876. ret = sigwait(sigset_p, &signal);
  1877. if(state_p == NULL) {
  1878. switch(signal) {
  1879. case SIGALRM:
  1880. *exitcode_p = ETIME;
  1881. case SIGTERM:
  1882. case SIGINT:
  1883. // TODO: remove the exit() from here. Main thread should exit itself
  1884. exit(*exitcode_p);
  1885. break;
  1886. default:
  1887. printf_e("Warning: Got signal %i, but the main loop is not started, yet. Ignoring the signal.\n", signal);
  1888. break;
  1889. }
  1890. continue;
  1891. }
  1892. printf_ddd("Debug3: sync_sighandler(): got signal %i. *state_p == %i.\n", signal, *state_p);
  1893. if(ret) {
  1894. // TODO: handle an error here
  1895. }
  1896. switch(signal) {
  1897. case SIGALRM:
  1898. *exitcode_p = ETIME;
  1899. case SIGTERM:
  1900. case SIGINT:
  1901. sync_switch_state(pthread_parent, STATE_TERM);
  1902. break;
  1903. case SIGHUP:
  1904. sync_switch_state(pthread_parent, STATE_REHASH);
  1905. break;
  1906. case SIGUSR_PTHREAD_GC:
  1907. sync_switch_state(pthread_parent, STATE_PTHREAD_GC);
  1908. break;
  1909. case SIGUSR_INITSYNC:
  1910. sync_switch_state(pthread_parent, STATE_INITSYNC);
  1911. break;
  1912. default:
  1913. printf_e("Error: Unknown signal: %i. Exit.\n", signal);
  1914. sync_switch_state(pthread_parent, STATE_TERM);
  1915. break;
  1916. }
  1917. if((*state_p == STATE_TERM) || (*state_p == STATE_EXIT)) {
  1918. break;
  1919. }
  1920. }
  1921. return 0;
  1922. }
  1923. int sync_term(int exitcode) {
  1924. *sync_sighandler_exitcode_p = exitcode;
  1925. return pthread_kill(pthread_sighandler, SIGTERM);
  1926. }
  1927. int sync_run(options_t *options_p) {
  1928. int ret, i;
  1929. sighandler_arg_t sighandler_arg = {0};
  1930. // Creating signal handler thread
  1931. sigset_t sigset_sighandler;
  1932. sigemptyset(&sigset_sighandler);
  1933. sigaddset(&sigset_sighandler, SIGALRM);
  1934. sigaddset(&sigset_sighandler, SIGHUP);
  1935. sigaddset(&sigset_sighandler, SIGTERM);
  1936. sigaddset(&sigset_sighandler, SIGINT);
  1937. sigaddset(&sigset_sighandler, SIGUSR_PTHREAD_GC);
  1938. sigaddset(&sigset_sighandler, SIGUSR_INITSYNC);
  1939. ret = pthread_sigmask(SIG_BLOCK, &sigset_sighandler, NULL);
  1940. if(ret) return ret;
  1941. // sighandler_arg.options_p = options_p;
  1942. // sighandler_arg.indexes_p = &indexes;
  1943. sighandler_arg.pthread_parent = pthread_self();
  1944. sighandler_arg.exitcode_p = &ret;
  1945. sighandler_arg.sigset_p = &sigset_sighandler;
  1946. ret = pthread_create(&pthread_sighandler, NULL, (void *(*)(void *))sync_sighandler, &sighandler_arg);
  1947. if(ret) return ret;
  1948. sigset_t sigset_parent;
  1949. sigemptyset(&sigset_parent);
  1950. sigaddset(&sigset_parent, SIGUSR_BLOPINT);
  1951. ret = pthread_sigmask(SIG_UNBLOCK, &sigset_parent, NULL);
  1952. if(ret) return ret;
  1953. signal(SIGUSR_BLOPINT, sync_sig_int);
  1954. // Creating hash tables
  1955. indexes_t indexes = {NULL};
  1956. indexes.wd2fpath_ht = g_hash_table_new_full(g_direct_hash, g_direct_equal, 0, 0);
  1957. indexes.fpath2wd_ht = g_hash_table_new_full(g_str_hash, g_str_equal, free, 0);
  1958. indexes.fpath2ei_ht = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
  1959. indexes.exc_fpath_ht = g_hash_table_new_full(g_str_hash, g_str_equal, free, 0);
  1960. indexes.out_lines_aggr_ht= g_hash_table_new_full(g_str_hash, g_str_equal, free, 0);
  1961. i=0;
  1962. while(i<QUEUE_MAX) {
  1963. indexes.fpath2ei_coll_ht[i] = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
  1964. indexes.exc_fpath_coll_ht[i] = g_hash_table_new_full(g_str_hash, g_str_equal, free, 0);
  1965. i++;
  1966. }
  1967. // Loading dynamical libraries
  1968. if(options_p->flags[SYNCHANDLERSO]) {
  1969. void *synchandler_handle = dlopen(options_p->handlerfpath, RTLD_NOW|RTLD_LOCAL);
  1970. if(synchandler_handle == NULL) {
  1971. printf_e("Error: sync_run(): Cannot load shared object file \"%s\": %s\n", options_p->handlerfpath, dlerror());
  1972. return -1;
  1973. }
  1974. options_p->handler_handle = synchandler_handle;
  1975. options_p->handler_funct.init = (api_funct_init) dlsym(options_p->handler_handle, API_PREFIX"init");
  1976. options_p->handler_funct.sync = (api_funct_sync) dlsym(options_p->handler_handle, API_PREFIX"sync");
  1977. if(options_p->handler_funct.sync == NULL) {
  1978. char *dlerror_str = dlerror();
  1979. printf_e("Error: sync_run(): Cannot resolve symbol "API_PREFIX"sync in shared object \"%s\": %s\n",
  1980. options_p->handlerfpath, dlerror_str != NULL ? dlerror_str : "No error description returned.");
  1981. }
  1982. options_p->handler_funct.deinit = (api_funct_deinit)dlsym(options_p->handler_handle, API_PREFIX"deinit");
  1983. if(options_p->handler_funct.init != NULL)
  1984. if((ret = options_p->handler_funct.init(options_p, &indexes))) {
  1985. printf_e("Error: sync_run(): Cannot init sync-handler module: %s (errno: %i).\n", strerror(ret), ret);
  1986. return ret;
  1987. }
  1988. }
  1989. #ifdef CLUSTER_SUPPORT
  1990. // Initializing cluster subsystem
  1991. if(options_p->cluster_iface != NULL) {
  1992. ret = cluster_init(options_p, &indexes);
  1993. if(ret) {
  1994. printf_e("Error: Cannot initialize cluster subsystem: %s (errno %i).\n", strerror(ret), ret);
  1995. cluster_deinit();
  1996. return ret;
  1997. }
  1998. }
  1999. #endif
  2000. // Initializing rand-generator if it's required
  2001. if(options_p->listoutdir)
  2002. srand(time(NULL));
  2003. // Initializing FS monitor kernel subsystem in this userspace application
  2004. int notify_d = sync_notify_init(options_p);
  2005. if(notify_d == -1) return errno;
  2006. // Marking file tree for FS monitor
  2007. ret = sync_mark_walk(notify_d, options_p, options_p->watchdir, &indexes);
  2008. if(ret) return ret;
  2009. // "Infinite" loop of processling the events
  2010. ret = sync_notify_loop(notify_d, options_p, &indexes);
  2011. if(ret) return ret;
  2012. // TODO: Do cleanup of watching points
  2013. pthread_kill(pthread_sighandler, SIGTERM);
  2014. pthread_join(pthread_sighandler, NULL);
  2015. thread_cleanup(options_p);
  2016. printf_ddd("sync_run(): Closing notify_d\n");
  2017. close(notify_d);
  2018. // Closing shared libraries
  2019. if(options_p->flags[SYNCHANDLERSO]) {
  2020. int _ret;
  2021. if(options_p->handler_funct.deinit != NULL)
  2022. if((_ret = options_p->handler_funct.deinit())) {
  2023. printf_e("Error: sync_run(): Cannot deinit sync-handler module: %s (errno: %i).\n", strerror(ret), ret);
  2024. if(!ret) ret = _ret;
  2025. }
  2026. if(dlclose(options_p->handler_handle)) {
  2027. printf_e("Error: sync_run(): Cannot unload shared object file \"%s\": %s\n",
  2028. options_p->handlerfpath, dlerror());
  2029. if(!ret) ret = -1;
  2030. }
  2031. }
  2032. // Removing hash-tables
  2033. printf_ddd("sync_run(): Closing hash tables\n");
  2034. g_hash_table_destroy(indexes.wd2fpath_ht);
  2035. g_hash_table_destroy(indexes.fpath2wd_ht);
  2036. g_hash_table_destroy(indexes.fpath2ei_ht);
  2037. g_hash_table_destroy(indexes.exc_fpath_ht);
  2038. g_hash_table_destroy(indexes.out_lines_aggr_ht);
  2039. i=0;
  2040. while(i<QUEUE_MAX) {
  2041. g_hash_table_destroy(indexes.fpath2ei_coll_ht[i]);
  2042. g_hash_table_destroy(indexes.exc_fpath_coll_ht[i]);
  2043. i++;
  2044. }
  2045. // Deinitializing cluster subsystem
  2046. #ifdef CLUSTER_SUPPORT
  2047. if(options_p->cluster_iface != NULL) {
  2048. int _ret;
  2049. _ret = cluster_deinit();
  2050. if(_ret) {
  2051. printf_e("Error: Cannot deinitialize cluster subsystem: %s (errno: %i).\n", strerror(_ret), _ret);
  2052. ret = _ret;
  2053. }
  2054. }
  2055. #endif
  2056. #ifdef VERYPARANOID
  2057. // One second for another threads
  2058. sleep(1);
  2059. #endif
  2060. return ret;
  2061. }