12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403 |
- /*
- clsync - file tree sync utility based on inotify/kqueue
- Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "common.h"
- #if KQUEUE_SUPPORT
- # include "mon_kqueue.h"
- #endif
- #if INOTIFY_SUPPORT
- # include "mon_inotify.h"
- #endif
- #if FANOTIFY_SUPPORT
- # include "mon_fanotify.h"
- #endif
- #if BSM_SUPPORT
- # include "mon_bsm.h"
- # include <bsm/audit_kevents.h>
- #endif
- #if GIO_SUPPORT
- # include <gio/gio.h>
- # include "mon_gio.h"
- #endif
- #include "main.h"
- #include "error.h"
- #include "fileutils.h"
- #include "malloc.h"
- #include "cluster.h"
- #include "sync.h"
- #include "glibex.h"
- #include "control.h"
- #include "indexes.h"
- #include "privileged.h"
- #include "rules.h"
- #if CGROUP_SUPPORT
- # include "cgroup.h"
- #endif
- #include <stdio.h>
- #include <dlfcn.h>
- pthread_t pthread_sighandler;
- // seqid - is a counter of main loop. But it may overflow and it's required to compare
- // seqid-values anyway.
- // So if (a-b) is too big, let's assume, that "b<a".
- #define SEQID_WINDOW (((unsigned int)~0)>>1)
- #define SEQID_EQ(a, b) ((a)==(b))
- #define SEQID_GE(a, b) ((a)-(b) < SEQID_WINDOW)
- #define SEQID_LE(a, b) ((b)-(a) < SEQID_WINDOW)
- #define SEQID_GT(a, b) ((!SEQID_EQ(a, b)) && (SEQID_GE(a, b)))
- #define SEQID_LT(a, b) ((!SEQID_EQ(a, b)) && (SEQID_LE(a, b)))
- static unsigned int _sync_seqid_value = 0;
- static inline unsigned int sync_seqid()
- {
- return _sync_seqid_value++;
- }
- static inline void setenv_iteration ( uint32_t iteration_num )
- {
- char iterations[sizeof ( "4294967296" )]; // 4294967296 == 2**32
- sprintf ( iterations, "%i", iteration_num );
- setenv ( "CLSYNC_ITERATION", iterations, 1 );
- return;
- }
- static inline void finish_iteration ( ctx_t *ctx_p )
- {
- if ( ctx_p->iteration_num < ( typeof ( ctx_p->iteration_num ) ) ~0 ) // ~0 is the max value for unsigned variables
- ctx_p->iteration_num++;
- #ifdef THREADING_SUPPORT
- if ( !ctx_p->flags[THREADING] )
- #endif
- setenv_iteration ( ctx_p->iteration_num );
- debug ( 3, "next iteration: %u/%u",
- ctx_p->iteration_num, ctx_p->flags[MAXITERATIONS] );
- return;
- }
- gpointer eidup ( gpointer ei_gp )
- {
- eventinfo_t *ei = ( eventinfo_t * ) ei_gp;
- eventinfo_t *ei_dup = ( eventinfo_t * ) xmalloc ( sizeof ( *ei ) );
- memcpy ( ei_dup, ei, sizeof ( *ei ) );
- return ( gpointer ) ei_dup;
- }
- static inline void evinfo_merge ( ctx_t *ctx_p, eventinfo_t *evinfo_dst, eventinfo_t *evinfo_src )
- {
- debug ( 3, "evinfo_dst: seqid_min == %u; seqid_max == %u; objtype_old == %i; objtype_new == %i; \t"
- "evinfo_src: seqid_min == %u; seqid_max == %u; objtype_old == %i; objtype_new == %i",
- evinfo_dst->seqid_min, evinfo_dst->seqid_max, evinfo_dst->objtype_old, evinfo_dst->objtype_new,
- evinfo_src->seqid_min, evinfo_src->seqid_max, evinfo_src->objtype_old, evinfo_src->objtype_new
- );
- #if KQUEUE_SUPPORT | INOTIFY_SUPPORT
- switch ( ctx_p->flags[MONITOR] ) {
- #ifdef KQUEUE_SUPPORT
- case NE_KQUEUE:
- #endif
- #ifdef INOTIFY_SUPPORT
- case NE_INOTIFY:
- #endif
- evinfo_dst->evmask |= evinfo_src->evmask;
- break;
- }
- #endif
- evinfo_dst->flags |= evinfo_src->flags;
- if ( SEQID_LE ( evinfo_src->seqid_min, evinfo_dst->seqid_min ) ) {
- evinfo_dst->objtype_old = evinfo_src->objtype_old;
- evinfo_dst->seqid_min = evinfo_src->seqid_min;
- }
- if ( SEQID_GE ( evinfo_src->seqid_max, evinfo_dst->seqid_max ) ) {
- evinfo_dst->objtype_new = evinfo_src->objtype_new;
- evinfo_dst->seqid_max = evinfo_src->seqid_max;
- switch ( ctx_p->flags[MONITOR] ) {
- #ifdef GIO_SUPPORT
- case NE_GIO:
- evinfo_dst->evmask = evinfo_src->evmask;
- break;
- #endif
- #ifdef BSM_SUPPORT
- case NE_BSM:
- case NE_BSM_PREFETCH:
- evinfo_dst->evmask = evinfo_src->evmask;
- break;
- #endif
- default:
- break;
- }
- }
- return;
- }
- static inline int _exitcode_process ( ctx_t *ctx_p, int exitcode )
- {
- if ( ctx_p->isignoredexitcode[ ( unsigned char ) exitcode] )
- return 0;
- if ( exitcode && ! ( ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) && ( exitcode == 24 ) ) ) {
- error ( "Got non-zero exitcode %i from __sync_exec().", exitcode );
- return exitcode;
- }
- return 0;
- }
- int exitcode_process ( ctx_t *ctx_p, int exitcode )
- {
- int err = _exitcode_process ( ctx_p, exitcode );
- if ( err ) error ( "Got error-report from exitcode_process().\nExitcode is %i, strerror(%i) returns \"%s\". However strerror() is not ensures compliance "
- "between exitcode and error description for every utility. So, e.g if you're using rsync, you should look for the error description "
- "into rsync's manpage (\"man 1 rsync\"). Also some advices about diagnostics can be found in clsync's manpage (\"man 1 clsync\", see DIAGNOSTICS)",
- exitcode, exitcode, strerror ( exitcode ) );
- return err;
- }
- threadsinfo_t *thread_info() // TODO: optimize this
- {
- static threadsinfo_t threadsinfo = {0};
- if ( !threadsinfo.mutex_init ) {
- int i = 0;
- while ( i < PTHREAD_MUTEX_MAX ) {
- if ( pthread_mutex_init ( &threadsinfo.mutex[i], NULL ) ) {
- error ( "Cannot pthread_mutex_init()." );
- return NULL;
- }
- if ( pthread_cond_init ( &threadsinfo.cond [i], NULL ) ) {
- error ( "Cannot pthread_cond_init()." );
- return NULL;
- }
- i++;
- }
- threadsinfo.mutex_init++;
- }
- return &threadsinfo;
- }
- #ifdef THREADING_SUPPORT
- #define thread_info_lock() _thread_info_lock(__func__)
- static inline threadsinfo_t *_thread_info_lock ( const char *const function_name )
- {
- threadsinfo_t *threadsinfo_p = thread_info();
- debug ( 4, "used by %s()", function_name );
- pthread_mutex_lock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_THREADSINFO] );
- return threadsinfo_p;
- }
- #define thread_info_unlock(...) _thread_info_unlock(__func__, __VA_ARGS__)
- static inline int _thread_info_unlock ( const char *const function_name, int rc )
- {
- threadsinfo_t *threadsinfo_p = thread_info();
- debug ( 4, "used by %s()", function_name );
- pthread_mutex_unlock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_THREADSINFO] );
- return rc;
- }
- int threads_foreach ( int ( *funct ) ( threadinfo_t *, void * ), state_t state, void *arg )
- {
- int i, rc;
- threadsinfo_t *threadsinfo_p = thread_info_lock();
- #ifdef PARANOID
- if ( threadsinfo_p == NULL )
- return thread_info_unlock ( EINVAL );
- #endif
- rc = 0;
- i = 0;
- while ( i < threadsinfo_p->used ) {
- threadinfo_t *threadinfo_p = &threadsinfo_p->threads[i++];
- if ( ( state == STATE_UNKNOWN ) || ( threadinfo_p->state == state ) ) {
- if ( ( rc = funct ( threadinfo_p, arg ) ) )
- break;
- }
- }
- return thread_info_unlock ( rc );
- }
- time_t thread_nextexpiretime()
- {
- time_t nextexpiretime = 0;
- threadsinfo_t *threadsinfo_p = thread_info_lock();
- #ifdef PARANOID
- if ( threadsinfo_p == NULL )
- return thread_info_unlock ( 0 );
- #endif
- int thread_num = threadsinfo_p->used;
- while ( thread_num-- ) {
- threadinfo_t *threadinfo_p = &threadsinfo_p->threads[thread_num];
- debug ( 3, "threadsinfo_p->threads[%i].state == %i;\tthreadsinfo_p->threads[%i].pthread == %p;\tthreadsinfo_p->threads[%i].expiretime == %i",
- thread_num, threadinfo_p->state, thread_num, threadinfo_p->pthread, thread_num, threadinfo_p->expiretime );
- if ( threadinfo_p->state == STATE_EXIT )
- continue;
- if ( threadinfo_p->expiretime ) {
- if ( nextexpiretime )
- nextexpiretime = MIN ( nextexpiretime, threadinfo_p->expiretime );
- else
- nextexpiretime = threadinfo_p->expiretime;
- }
- }
- thread_info_unlock ( 0 );
- debug ( 3, "nextexpiretime == %i", nextexpiretime );
- return nextexpiretime;
- }
- threadinfo_t *thread_new()
- {
- threadsinfo_t *threadsinfo_p = thread_info_lock();
- #ifdef PARANOID
- if ( threadsinfo_p == NULL ) {
- thread_info_unlock ( 0 );
- return NULL;
- }
- #endif
- int thread_num;
- threadinfo_t *threadinfo_p;
- if ( threadsinfo_p->stacklen ) {
- threadinfo_p = threadsinfo_p->threadsstack[--threadsinfo_p->stacklen];
- thread_num = threadinfo_p->thread_num;
- } else {
- if ( threadsinfo_p->used >= threadsinfo_p->allocated ) {
- threadsinfo_p->allocated += ALLOC_PORTION;
- debug ( 2, "Reallocated memory for threadsinfo -> %i.", threadsinfo_p->allocated );
- threadsinfo_p->threads = ( threadinfo_t * ) xrealloc ( ( char * ) threadsinfo_p->threads,
- sizeof ( *threadsinfo_p->threads ) * ( threadsinfo_p->allocated + 2 ) );
- threadsinfo_p->threadsstack = ( threadinfo_t ** ) xrealloc ( ( char * ) threadsinfo_p->threadsstack,
- sizeof ( *threadsinfo_p->threadsstack ) * ( threadsinfo_p->allocated + 2 ) );
- }
- thread_num = threadsinfo_p->used++;
- threadinfo_p = &threadsinfo_p->threads[thread_num];
- }
- #ifdef PARANOID
- memset ( threadinfo_p, 0, sizeof ( *threadinfo_p ) );
- #else
- threadinfo_p->expiretime = 0;
- threadinfo_p->errcode = 0;
- threadinfo_p->exitcode = 0;
- #endif
- threadinfo_p->thread_num = thread_num;
- threadinfo_p->state = STATE_RUNNING;
- debug ( 2, "thread_new -> thread_num: %i; used: %i", thread_num, threadsinfo_p->used );
- thread_info_unlock ( 0 );
- return threadinfo_p;
- }
- int thread_del_bynum ( int thread_num )
- {
- debug ( 2, "thread_del_bynum(%i)", thread_num );
- threadsinfo_t *threadsinfo_p = thread_info_lock();
- #ifdef PARANOID
- if ( threadsinfo_p == NULL )
- return thread_info_unlock ( errno );
- #endif
- if ( thread_num >= threadsinfo_p->used )
- return thread_info_unlock ( EINVAL );
- threadinfo_t *threadinfo_p = &threadsinfo_p->threads[thread_num];
- threadinfo_p->state = STATE_EXIT;
- char **ptr = threadinfo_p->argv;
- if ( ptr != NULL ) {
- while ( *ptr )
- free ( * ( ptr++ ) );
- free ( threadinfo_p->argv );
- }
- if ( thread_num == ( threadsinfo_p->used - 1 ) ) {
- threadsinfo_p->used--;
- debug ( 3, "thread_del_bynum(%i): there're %i threads left (#0).", thread_num, threadsinfo_p->used - threadsinfo_p->stacklen );
- return thread_info_unlock ( 0 );
- }
- threadinfo_t *t = &threadsinfo_p->threads[threadsinfo_p->used - 1];
- if ( t->state == STATE_EXIT ) {
- threadsinfo_p->used--;
- debug ( 3, "%i [%p] -> %i [%p]; left: %i",
- threadsinfo_p->used, t->pthread, thread_num, threadinfo_p->pthread, threadsinfo_p->used - threadsinfo_p->stacklen );
- memcpy ( threadinfo_p, t, sizeof ( *threadinfo_p ) );
- } else {
- #ifdef PARANOID
- if ( threadsinfo_p->stacklen >= threadsinfo_p->allocated ) {
- error ( "Threads metadata structures pointers stack overflowed!" );
- return thread_info_unlock ( EINVAL );
- }
- #endif
- threadsinfo_p->threadsstack[threadsinfo_p->stacklen++] = threadinfo_p;
- }
- debug ( 3, "thread_del_bynum(%i): there're %i threads left (#1).", thread_num, threadsinfo_p->used - threadsinfo_p->stacklen );
- return thread_info_unlock ( 0 );
- }
- int thread_gc ( ctx_t *ctx_p )
- {
- int thread_num;
- time_t tm = time ( NULL );
- debug ( 3, "tm == %i; thread %p", tm, pthread_self() );
- if ( !ctx_p->flags[THREADING] )
- return 0;
- threadsinfo_t *threadsinfo_p = thread_info_lock();
- #ifdef PARANOID
- if ( threadsinfo_p == NULL )
- return thread_info_unlock ( errno );
- #endif
- debug ( 2, "There're %i threads.", threadsinfo_p->used );
- thread_num = -1;
- while ( ++thread_num < threadsinfo_p->used ) {
- int err;
- threadinfo_t *threadinfo_p = &threadsinfo_p->threads[thread_num];
- debug ( 3, "Trying thread #%i (==%i) (state: %i; expire at: %i, now: %i, exitcode: %i, errcode: %i; i_p: %p; p: %p).",
- thread_num, threadinfo_p->thread_num, threadinfo_p->state, threadinfo_p->expiretime, tm, threadinfo_p->exitcode,
- threadinfo_p->errcode, threadinfo_p, threadinfo_p->pthread );
- if ( threadinfo_p->state == STATE_EXIT )
- continue;
- if ( threadinfo_p->expiretime && ( threadinfo_p->expiretime <= tm ) ) {
- if ( pthread_tryjoin_np ( threadinfo_p->pthread, NULL ) ) { // TODO: check this pthread_tryjoin_np() on error returnings
- error ( "Debug3: thread_gc(): Thread #%i is alive too long: %lu <= %lu (started at %lu)", thread_num, threadinfo_p->expiretime, tm, threadinfo_p->starttime );
- return thread_info_unlock ( ETIME );
- }
- }
- #ifndef VERYPARANOID
- if ( threadinfo_p->state != STATE_TERM ) {
- debug ( 3, "Thread #%i is busy, skipping (#0).", thread_num );
- continue;
- }
- #endif
- debug ( 3, "Trying to join thread #%i: %p", thread_num, threadinfo_p->pthread );
- #ifndef VERYPARANOID
- switch ( ( err = pthread_join ( threadinfo_p->pthread, NULL ) ) ) {
- #else
- switch ( ( err = pthread_tryjoin_np ( threadinfo_p->pthread, NULL ) ) ) {
- case EBUSY:
- debug ( 3, "Thread #%i is busy, skipping (#1).", thread_num );
- continue;
- #endif
- case EDEADLK:
- case EINVAL:
- case 0:
- debug ( 3, "Thread #%i is finished with exitcode %i (errcode %i), deleting. threadinfo_p == %p",
- thread_num, threadinfo_p->exitcode, threadinfo_p->errcode, threadinfo_p );
- break;
- default:
- error ( "Got error while pthread_join() or pthread_tryjoin_np().", strerror ( err ), err );
- return thread_info_unlock ( errno );
- }
- if ( threadinfo_p->errcode ) {
- error ( "Got error from thread #%i: errcode %i.", thread_num, threadinfo_p->errcode );
- thread_info_unlock ( 0 );
- thread_del_bynum ( thread_num );
- return threadinfo_p->errcode;
- }
- thread_info_unlock ( 0 );
- if ( thread_del_bynum ( thread_num ) )
- return errno;
- thread_info_lock();
- }
- debug ( 3, "There're %i threads left.", threadsinfo_p->used - threadsinfo_p->stacklen );
- return thread_info_unlock ( 0 );
- }
- int thread_cleanup ( ctx_t *ctx_p )
- {
- ( void ) ctx_p;
- debug ( 3, "" );
- threadsinfo_t *threadsinfo_p = thread_info_lock();
- #ifdef PARANOID
- if ( threadsinfo_p == NULL )
- return thread_info_unlock ( errno );
- #endif
- // Waiting for threads:
- debug ( 1, "There're %i opened threads. Waiting.", threadsinfo_p->used );
- while ( threadsinfo_p->used ) {
- // int err;
- threadinfo_t *threadinfo_p = &threadsinfo_p->threads[--threadsinfo_p->used];
- if ( threadinfo_p->state == STATE_EXIT )
- continue;
- //pthread_kill(threadinfo_p->pthread, SIGTERM);
- debug ( 1, "killing pid %i with SIGTERM", threadinfo_p->child_pid );
- kill ( threadinfo_p->child_pid, SIGTERM );
- pthread_join ( threadinfo_p->pthread, NULL );
- debug ( 2, "thread #%i exitcode: %i", threadsinfo_p->used, threadinfo_p->exitcode );
- /*
- if(threadinfo_p->callback)
- if((err=threadinfo_p->callback(ctx_p, threadinfo_p->argv)))
- warning("Got error from callback function.", strerror(err), err);
- */
- char **ptr = threadinfo_p->argv;
- while ( *ptr )
- free ( * ( ptr++ ) );
- free ( threadinfo_p->argv );
- }
- debug ( 3, "All threads are closed." );
- // Freeing
- if ( threadsinfo_p->allocated ) {
- free ( threadsinfo_p->threads );
- free ( threadsinfo_p->threadsstack );
- }
- if ( threadsinfo_p->mutex_init ) {
- int i = 0;
- while ( i < PTHREAD_MUTEX_MAX ) {
- pthread_mutex_destroy ( &threadsinfo_p->mutex[i] );
- pthread_cond_destroy ( &threadsinfo_p->cond [i] );
- i++;
- }
- }
- #ifdef PARANOID
- // Reseting
- memset ( threadsinfo_p, 0, sizeof ( *threadsinfo_p ) ); // Just in case;
- #endif
- debug ( 3, "done." );
- return thread_info_unlock ( 0 );
- }
- #endif
- volatile state_t *state_p = NULL;
- volatile int exitcode = 0;
- #define SHOULD_THREAD(ctx_p) ((ctx_p->flags[THREADING] != PM_OFF) && (ctx_p->flags[THREADING] != PM_SAFE || ctx_p->iteration_num))
- int exec_argv ( char **argv, int *child_pid )
- {
- debug ( 3, "Thread %p.", pthread_self() );
- pid_t pid;
- int status;
- // Forking
- pid = privileged_fork_execvp ( argv[0], ( char *const * ) argv );
- // debug(3, "After fork thread %p"")".", pthread_self() );
- debug ( 3, "Child pid is %u", pid );
- // Setting *child_pid value
- if ( child_pid )
- *child_pid = pid;
- // Waiting for process end
- #ifdef VERYPARANOID
- sigset_t sigset_exec, sigset_old;
- sigemptyset ( &sigset_exec );
- sigaddset ( &sigset_exec, SIGUSR_BLOPINT );
- pthread_sigmask ( SIG_BLOCK, &sigset_exec, &sigset_old );
- #endif
- // debug(3, "Pre-wait thread %p"")".", pthread_self() );
- if ( privileged_waitpid ( pid, &status, 0 ) != pid ) {
- switch ( errno ) {
- case ECHILD:
- debug ( 2, "Child %u is already dead.", pid );
- break;
- default:
- error ( "Cannot waitid()." );
- return errno;
- }
- }
- // debug(3, "After-wait thread %p"")".", pthread_self() );
- #ifdef VERYPARANOID
- pthread_sigmask ( SIG_SETMASK, &sigset_old, NULL );
- #endif
- // Return
- int exitcode = WEXITSTATUS ( status );
- debug ( 3, "execution completed with exitcode %i", exitcode );
- return exitcode;
- }
- #ifdef THREADING_SUPPORT
- static inline int thread_exit ( threadinfo_t *threadinfo_p, int exitcode )
- {
- int err = 0;
- threadinfo_p->exitcode = exitcode;
- #if _DEBUG_FORCE | VERYPARANOID
- if ( threadinfo_p->pthread != pthread_self() ) {
- error ( "pthread id mismatch! (i_p->p) %p != (p) %p""", threadinfo_p->pthread, pthread_self() );
- return EINVAL;
- }
- #endif
- if ( threadinfo_p->callback ) {
- if ( threadinfo_p->ctx_p->flags[DEBUG] > 2 ) {
- debug ( 3, "thread %p, argv: ", threadinfo_p->pthread );
- char **argv = threadinfo_p->argv;
- while ( *argv ) {
- debug ( 3, "\t%p == %s", *argv, *argv );
- argv++;
- }
- }
- if ( ( err = threadinfo_p->callback ( threadinfo_p->ctx_p, threadinfo_p->callback_arg ) ) ) {
- error ( "Got error from callback function.", strerror ( err ), err );
- threadinfo_p->errcode = err;
- }
- }
- // Notifying the parent-thread, that it's time to collect garbage threads
- threadinfo_p->state = STATE_TERM;
- debug ( 3, "thread %p is sending signal to sighandler to call GC", threadinfo_p->pthread );
- return pthread_kill ( pthread_sighandler, SIGUSR_THREAD_GC );
- }
- #endif
- static inline void so_call_sync_finished ( int n, api_eventinfo_t *ei )
- {
- int i = 0;
- api_eventinfo_t *ei_i = ei;
- while ( i < n ) {
- #ifdef PARANOID
- if ( ei_i->path == NULL ) {
- warning ( "ei_i->path == NULL" );
- i++;
- continue;
- }
- #endif
- free ( ( char * ) ei_i->path );
- ei_i++;
- i++;
- }
- if ( ei != NULL )
- free ( ei );
- return;
- }
- #ifdef THREADING_SUPPORT
- int so_call_sync_thread ( threadinfo_t *threadinfo_p )
- {
- debug ( 3, "thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p",
- threadinfo_p->thread_num, threadinfo_p, threadinfo_p->pthread, pthread_self() );
- ctx_t *ctx_p = threadinfo_p->ctx_p;
- int n = threadinfo_p->n;
- api_eventinfo_t *ei = threadinfo_p->ei;
- int err = 0, rc = 0, try_again = 0;
- do {
- try_again = 0;
- threadinfo_p->try_n++;
- rc = ctx_p->handler_funct.sync ( n, ei );
- if ( ( err = exitcode_process ( threadinfo_p->ctx_p, rc ) ) ) {
- try_again = ( ( !ctx_p->retries ) || ( threadinfo_p->try_n < ctx_p->retries ) ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT );
- warning ( "Bad exitcode %i (errcode %i). %s.", rc, err, try_again ? "Retrying" : "Give up" );
- if ( try_again ) {
- debug ( 2, "Sleeping for %u seconds before the retry.", ctx_p->syncdelay );
- sleep ( ctx_p->syncdelay );
- }
- }
- } while ( err && ( ( !ctx_p->retries ) || ( threadinfo_p->try_n < ctx_p->retries ) ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) );
- if ( err && !ctx_p->flags[IGNOREFAILURES] ) {
- error ( "Bad exitcode %i (errcode %i)", rc, err );
- threadinfo_p->errcode = err;
- }
- so_call_sync_finished ( n, ei );
- if ( ( err = thread_exit ( threadinfo_p, rc ) ) ) {
- exitcode = err; // This's global variable "exitcode"
- pthread_kill ( pthread_sighandler, SIGTERM );
- }
- return rc;
- }
- #endif
- static inline int so_call_sync ( ctx_t *ctx_p, indexes_t *indexes_p, int n, api_eventinfo_t *ei )
- {
- debug ( 2, "n == %i", n );
- #ifdef THREADING_SUPPORT
- if ( !SHOULD_THREAD ( ctx_p ) ) {
- #endif
- int rc = 0, ret = 0, err = 0;
- int try_n = 0, try_again;
- state_t status = STATE_UNKNOWN;
- // indexes_p->nonthreaded_syncing_fpath2ei_ht = g_hash_table_dup(indexes_p->fpath2ei_ht, g_str_hash, g_str_equal, free, free, (gpointer(*)(gpointer))strdup, eidup);
- indexes_p->nonthreaded_syncing_fpath2ei_ht = indexes_p->fpath2ei_ht;
- do {
- try_again = 0;
- try_n++;
- alarm ( ctx_p->synctimeout );
- rc = ctx_p->handler_funct.sync ( n, ei );
- alarm ( 0 );
- if ( ( err = exitcode_process ( ctx_p, rc ) ) ) {
- if ( ( try_n == 1 ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) ) {
- status = ctx_p->state;
- ctx_p->state = STATE_SYNCHANDLER_ERR;
- main_status_update ( ctx_p );
- }
- try_again = ( ( !ctx_p->retries ) || ( try_n < ctx_p->retries ) ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT );
- warning ( "Bad exitcode %i (errcode %i). %s.", rc, err, try_again ? "Retrying" : "Give up" );
- if ( try_again ) {
- debug ( 2, "Sleeping for %u seconds before the retry.", ctx_p->syncdelay );
- sleep ( ctx_p->syncdelay );
- }
- }
- } while ( err && ( ( !ctx_p->retries ) || ( try_n < ctx_p->retries ) ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) );
- if ( err && !ctx_p->flags[IGNOREFAILURES] ) {
- error ( "Bad exitcode %i (errcode %i)", rc, err );
- ret = err;
- } else if ( status != STATE_UNKNOWN ) {
- ctx_p->state = status;
- main_status_update ( ctx_p );
- }
- // g_hash_table_destroy(indexes_p->nonthreaded_syncing_fpath2ei_ht);
- indexes_p->nonthreaded_syncing_fpath2ei_ht = NULL;
- so_call_sync_finished ( n, ei );
- return ret;
- #ifdef THREADING_SUPPORT
- }
- threadinfo_t *threadinfo_p = thread_new();
- if ( threadinfo_p == NULL )
- return errno;
- threadinfo_p->try_n = 0;
- threadinfo_p->callback = NULL;
- threadinfo_p->argv = NULL;
- threadinfo_p->ctx_p = ctx_p;
- threadinfo_p->starttime = time ( NULL );
- threadinfo_p->fpath2ei_ht = g_hash_table_dup ( indexes_p->fpath2ei_ht, g_str_hash, g_str_equal, free, free, ( gpointer ( * ) ( gpointer ) ) strdup, eidup );
- threadinfo_p->n = n;
- threadinfo_p->ei = ei;
- threadinfo_p->iteration = ctx_p->iteration_num;
- if ( ctx_p->synctimeout )
- threadinfo_p->expiretime = threadinfo_p->starttime + ctx_p->synctimeout;
- if ( pthread_create ( &threadinfo_p->pthread, NULL, ( void * ( * ) ( void * ) ) so_call_sync_thread, threadinfo_p ) ) {
- error ( "Cannot pthread_create()." );
- return errno;
- }
- debug ( 3, "thread %p", threadinfo_p->pthread );
- return 0;
- #endif
- }
- static inline int so_call_rsync_finished ( ctx_t *ctx_p, const char *inclistfile, const char *exclistfile )
- {
- int ret0, ret1;
- debug ( 5, "" );
- if ( ctx_p->flags[DONTUNLINK] )
- return 0;
- if ( inclistfile == NULL ) {
- error ( "inclistfile == NULL." );
- return EINVAL;
- }
- debug ( 3, "unlink()-ing \"%s\"", inclistfile );
- ret0 = unlink ( inclistfile );
- if ( ctx_p->flags[RSYNCPREFERINCLUDE] )
- return ret0;
- if ( exclistfile == NULL ) {
- error ( "exclistfile == NULL." );
- return EINVAL;
- }
- debug ( 3, "unlink()-ing \"%s\"", exclistfile );
- ret1 = unlink ( exclistfile );
- return ret0 == 0 ? ret1 : ret0;
- }
- #ifdef THREADING_SUPPORT
- int so_call_rsync_thread ( threadinfo_t *threadinfo_p )
- {
- debug ( 3, "thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p",
- threadinfo_p->thread_num, threadinfo_p, threadinfo_p->pthread, pthread_self() );
- ctx_t *ctx_p = threadinfo_p->ctx_p;
- char **argv = threadinfo_p->argv;
- int err = 0, rc = 0, try_again;
- do {
- try_again = 0;
- threadinfo_p->try_n++;
- rc = ctx_p->handler_funct.rsync ( argv[0], argv[1] );
- if ( ( err = exitcode_process ( threadinfo_p->ctx_p, rc ) ) ) {
- try_again = ( ( !ctx_p->retries ) || ( threadinfo_p->try_n < ctx_p->retries ) ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT );
- warning ( "Bad exitcode %i (errcode %i). %s.", rc, err, try_again ? "Retrying" : "Give up" );
- if ( try_again ) {
- debug ( 2, "Sleeping for %u seconds before the retry.", ctx_p->syncdelay );
- sleep ( ctx_p->syncdelay );
- }
- }
- } while ( try_again );
- if ( err && !ctx_p->flags[IGNOREFAILURES] ) {
- error ( "Bad exitcode %i (errcode %i)", rc, err );
- threadinfo_p->errcode = err;
- }
- if ( ( err = so_call_rsync_finished ( ctx_p, argv[0], argv[1] ) ) ) {
- exitcode = err; // This's global variable "exitcode"
- pthread_kill ( pthread_sighandler, SIGTERM );
- }
- free ( argv[0] );
- free ( argv[1] );
- free ( argv );
- if ( ( err = thread_exit ( threadinfo_p, rc ) ) ) {
- exitcode = err; // This's global variable "exitcode"
- pthread_kill ( pthread_sighandler, SIGTERM );
- }
- return rc;
- }
- #endif
- static inline int so_call_rsync ( ctx_t *ctx_p, indexes_t *indexes_p, const char *inclistfile, const char *exclistfile )
- {
- debug ( 2, "inclistfile == \"%s\"; exclistfile == \"%s\"", inclistfile, exclistfile );
- #ifdef THREADING_SUPPORT
- if ( !SHOULD_THREAD ( ctx_p ) ) {
- #endif
- debug ( 3, "ctx_p->handler_funct.rsync == %p", ctx_p->handler_funct.rsync );
- // indexes_p->nonthreaded_syncing_fpath2ei_ht = g_hash_table_dup(indexes_p->fpath2ei_ht, g_str_hash, g_str_equal, free, free, (gpointer(*)(gpointer))strdup, eidup);
- indexes_p->nonthreaded_syncing_fpath2ei_ht = indexes_p->fpath2ei_ht;
- int rc = 0, err = 0;
- int try_n = 0, try_again;
- state_t status = STATE_UNKNOWN;
- do {
- try_again = 0;
- try_n++;
- alarm ( ctx_p->synctimeout );
- rc = ctx_p->handler_funct.rsync ( inclistfile, exclistfile );
- alarm ( 0 );
- if ( ( err = exitcode_process ( ctx_p, rc ) ) ) {
- if ( ( try_n == 1 ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) ) {
- status = ctx_p->state;
- ctx_p->state = STATE_SYNCHANDLER_ERR;
- main_status_update ( ctx_p );
- }
- try_again = ( ( !ctx_p->retries ) || ( try_n < ctx_p->retries ) ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT );
- warning ( "Bad exitcode %i (errcode %i). %s.", rc, err, try_again ? "Retrying" : "Give up" );
- if ( try_again ) {
- debug ( 2, "Sleeping for %u seconds before the retry.", ctx_p->syncdelay );
- sleep ( ctx_p->syncdelay );
- }
- }
- } while ( try_again );
- if ( err && !ctx_p->flags[IGNOREFAILURES] ) {
- error ( "Bad exitcode %i (errcode %i)", rc, err );
- rc = err;
- } else if ( ( status != STATE_UNKNOWN ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) ) {
- ctx_p->state = status;
- main_status_update ( ctx_p );
- }
- // g_hash_table_destroy(indexes_p->nonthreaded_syncing_fpath2ei_ht);
- indexes_p->nonthreaded_syncing_fpath2ei_ht = NULL;
- int ret_cleanup;
- if ( ( ret_cleanup = so_call_rsync_finished ( ctx_p, inclistfile, exclistfile ) ) )
- return rc ? rc : ret_cleanup;
- return rc;
- #ifdef THREADING_SUPPORT
- }
- threadinfo_t *threadinfo_p = thread_new();
- if ( threadinfo_p == NULL )
- return errno;
- threadinfo_p->try_n = 0;
- threadinfo_p->callback = NULL;
- threadinfo_p->argv = xmalloc ( sizeof ( char * ) * 3 );
- threadinfo_p->ctx_p = ctx_p;
- threadinfo_p->starttime = time ( NULL );
- threadinfo_p->fpath2ei_ht = g_hash_table_dup ( indexes_p->fpath2ei_ht, g_str_hash, g_str_equal, free, free, ( gpointer ( * ) ( gpointer ) ) strdup, eidup );
- threadinfo_p->iteration = ctx_p->iteration_num;
- threadinfo_p->argv[0] = strdup ( inclistfile );
- threadinfo_p->argv[1] = strdup ( exclistfile );
- if ( ctx_p->synctimeout )
- threadinfo_p->expiretime = threadinfo_p->starttime + ctx_p->synctimeout;
- if ( pthread_create ( &threadinfo_p->pthread, NULL, ( void * ( * ) ( void * ) ) so_call_rsync_thread, threadinfo_p ) ) {
- error ( "Cannot pthread_create()." );
- return errno;
- }
- debug ( 3, "thread %p", threadinfo_p->pthread );
- return 0;
- #endif
- }
- // === SYNC_EXEC() === {
- //#define SYNC_EXEC(...) (SHOULD_THREAD(ctx_p) ? sync_exec_thread : sync_exec )(__VA_ARGS__)
- #ifdef THREADING_SUPPORT
- #define SYNC_EXEC_ARGV(...) (SHOULD_THREAD(ctx_p) ? sync_exec_argv_thread : sync_exec_argv)(__VA_ARGS__)
- #else
- #define SYNC_EXEC_ARGV(...) sync_exec_argv(__VA_ARGS__)
- #endif
- #define debug_argv_dump(level, argv)\
- if (unlikely(ctx_p->flags[DEBUG] >= level))\
- argv_dump(level, argv)
- static inline void argv_dump ( int debug_level, char **argv )
- {
- #ifdef _DEBUG_FORCE
- debug ( 19, "(%u, %p)", debug_level, argv );
- #endif
- char **argv_p = argv;
- while ( *argv_p != NULL ) {
- debug ( debug_level, "%p: \"%s\"", *argv_p, *argv_p );
- argv_p++;
- }
- return;
- }
- #define _sync_exec_getargv(argv, firstarg, COPYARG) {\
- va_list arglist;\
- va_start(arglist, firstarg);\
- \
- int i = 0;\
- do {\
- char *arg;\
- if(i >= MAXARGUMENTS) {\
- error("Too many arguments (%i >= %i).", i, MAXARGUMENTS);\
- return ENOMEM;\
- }\
- arg = (char *)va_arg(arglist, const char *const);\
- argv[i] = arg!=NULL ? COPYARG : NULL;\
- } while(argv[i++] != NULL);\
- va_end(arglist);\
- }
- char *sync_path_rel2abs ( ctx_t *ctx_p, const char *path_rel, ssize_t path_rel_len, size_t *path_abs_len_p, char *path_abs_oldptr )
- {
- if ( path_rel == NULL )
- return NULL;
- if ( path_rel_len == -1 )
- path_rel_len = strlen ( path_rel );
- char *path_abs;
- size_t watchdirlen =
- ( ctx_p->watchdir == ctx_p->watchdirwslash ) ? 0 : ctx_p->watchdirlen;
- // if [watchdir == "/"] ? 0 : watchdir.length()
- size_t path_abs_len = path_rel_len + watchdirlen + 1;
- path_abs = ( path_abs_len_p == NULL || path_abs_len >= *path_abs_len_p ) ?
- xrealloc ( path_abs_oldptr, path_abs_len + 1 ) :
- path_abs_oldptr;
- if ( path_abs_oldptr == NULL ) {
- memcpy ( path_abs, ctx_p->watchdir, watchdirlen );
- path_abs[watchdirlen] = '/';
- }
- memcpy ( &path_abs[watchdirlen + 1], path_rel, path_rel_len + 1 );
- if ( path_abs_len_p != NULL )
- *path_abs_len_p = path_abs_len;
- return path_abs;
- }
- char *sync_path_abs2rel ( ctx_t *ctx_p, const char *path_abs, ssize_t path_abs_len, size_t *path_rel_len_p, char *path_rel_oldptr )
- {
- if ( path_abs == NULL )
- return NULL;
- if ( path_abs_len == -1 )
- path_abs_len = strlen ( path_abs );
- size_t path_rel_len;
- char *path_rel;
- size_t watchdirlen =
- ( ctx_p->watchdir == ctx_p->watchdirwslash ) ? 0 : ctx_p->watchdirlen;
- signed long path_rel_len_signed = path_abs_len - ( watchdirlen + 1 );
- path_rel_len = ( path_rel_len_signed > 0 ) ? path_rel_len_signed : 0;
- path_rel = ( path_rel_len_p == NULL || path_rel_len >= *path_rel_len_p ) ?
- xrealloc ( path_rel_oldptr, path_rel_len + 1 ) :
- path_rel_oldptr;
- if ( !path_rel_len ) {
- path_rel[0] = 0;
- return path_rel;
- }
- memcpy ( path_rel, &path_abs[watchdirlen + 1], path_rel_len + 1 );
- #ifdef VERYPARANOID
- // Removing "/" on the end
- debug ( 3, "\"%s\" (len: %i) --%i--> \"%s\" (len: %i) + ",
- path_abs, path_abs_len, path_rel[path_rel_len - 1] == '/',
- ctx_p->watchdirwslash, watchdirlen + 1 );
- if ( path_rel[path_rel_len - 1] == '/' )
- path_rel[--path_rel_len] = 0x00;
- debug ( 3, "\"%s\" (len: %i)", path_rel, path_rel_len );
- #endif
- if ( path_rel_len_p != NULL )
- *path_rel_len_p = path_rel_len;
- return path_rel;
- }
- pid_t clsyncapi_fork ( ctx_t *ctx_p )
- {
- // if(ctx_p->flags[THREADING])
- // return fork();
- // Cleaning stale pids. TODO: Optimize this. Remove this GC.
- int i = 0;
- while ( i < ctx_p->children ) {
- if ( privileged_waitpid ( ctx_p->child_pid[i], NULL, WNOHANG ) < 0 )
- if ( errno == ECHILD )
- ctx_p->child_pid[i] = ctx_p->child_pid[--ctx_p->children];
- i++;
- }
- // Too many children
- if ( ctx_p->children >= MAXCHILDREN ) {
- errno = ECANCELED;
- return -1;
- }
- // Forking
- pid_t pid = fork();
- ctx_p->child_pid[ctx_p->children++] = pid;
- return pid;
- }
- int sync_exec_argv ( ctx_t *ctx_p, indexes_t *indexes_p, thread_callbackfunct_t callback, thread_callbackfunct_arg_t *callback_arg_p, char **argv )
- {
- debug ( 2, "" );
- debug_argv_dump ( 2, argv );
- // indexes_p->nonthreaded_syncing_fpath2ei_ht = g_hash_table_dup(indexes_p->fpath2ei_ht, g_str_hash, g_str_equal, free, free, (gpointer(*)(gpointer))strdup, eidup);
- indexes_p->nonthreaded_syncing_fpath2ei_ht = indexes_p->fpath2ei_ht;
- int exitcode = 0, ret = 0, err = 0;
- int try_n = 0, try_again;
- state_t status = STATE_UNKNOWN;
- do {
- try_again = 0;
- try_n++;
- debug ( 2, "try_n == %u (retries == %u)", try_n, ctx_p->retries );
- alarm ( ctx_p->synctimeout );
- ctx_p->children = 1;
- exitcode = exec_argv ( argv, ctx_p->child_pid );
- ctx_p->children = 0;
- alarm ( 0 );
- if ( ( err = exitcode_process ( ctx_p, exitcode ) ) ) {
- if ( ( try_n == 1 ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) ) {
- status = ctx_p->state;
- ctx_p->state = STATE_SYNCHANDLER_ERR;
- main_status_update ( ctx_p );
- }
- try_again = ( ( !ctx_p->retries ) || ( try_n < ctx_p->retries ) ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT );
- warning ( "Bad exitcode %i (errcode %i). %s.", exitcode, err, try_again ? "Retrying" : "Give up" );
- if ( try_again ) {
- debug ( 2, "Sleeping for %u seconds before the retry.", ctx_p->syncdelay );
- sleep ( ctx_p->syncdelay );
- }
- }
- } while ( try_again );
- if ( err && !ctx_p->flags[IGNOREFAILURES] ) {
- error ( "Bad exitcode %i (errcode %i)", exitcode, err );
- ret = err;
- } else if ( ( status != STATE_UNKNOWN ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) ) {
- ctx_p->state = status;
- main_status_update ( ctx_p );
- }
- if ( callback != NULL ) {
- int nret = callback ( ctx_p, callback_arg_p );
- if ( nret ) {
- error ( "Got error while callback()." );
- if ( !ret ) ret = nret;
- }
- }
- // g_hash_table_destroy(indexes_p->nonthreaded_syncing_fpath2ei_ht);
- indexes_p->nonthreaded_syncing_fpath2ei_ht = NULL;
- return ret;
- }
- /*
- static inline int sync_exec(ctx_t *ctx_p, indexes_t *indexes_p, thread_callbackfunct_t callback, thread_callbackfunct_arg_t *callback_arg_p, ...) {
- int rc;
- debug(2, "");
- char **argv = (char **)xcalloc(sizeof(char *), MAXARGUMENTS);
- memset(argv, 0, sizeof(char *)*MAXARGUMENTS);
- _sync_exec_getargv(argv, callback_arg_p, arg);
- rc = sync_exec_argv(ctx_p, indexes_p, callback, callback_arg_p, argv);
- free(argv);
- return rc;
- }
- */
- #ifdef THREADING_SUPPORT
- int __sync_exec_thread ( threadinfo_t *threadinfo_p )
- {
- char **argv = threadinfo_p->argv;
- ctx_t *ctx_p = threadinfo_p->ctx_p;
- debug ( 3, "thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p""",
- threadinfo_p->thread_num, threadinfo_p, threadinfo_p->pthread, pthread_self() );
- int err = 0, exec_exitcode = 0, try_again;
- do {
- try_again = 0;
- threadinfo_p->try_n++;
- exec_exitcode = exec_argv ( argv, &threadinfo_p->child_pid );
- if ( ( err = exitcode_process ( threadinfo_p->ctx_p, exec_exitcode ) ) ) {
- try_again = ( ( !ctx_p->retries ) || ( threadinfo_p->try_n < ctx_p->retries ) ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT );
- warning ( "__sync_exec_thread(): Bad exitcode %i (errcode %i). %s.", exec_exitcode, err, try_again ? "Retrying" : "Give up" );
- if ( try_again ) {
- debug ( 2, "Sleeping for %u seconds before the retry.", ctx_p->syncdelay );
- sleep ( ctx_p->syncdelay );
- }
- }
- } while ( try_again );
- if ( err && !ctx_p->flags[IGNOREFAILURES] ) {
- error ( "Bad exitcode %i (errcode %i)", exec_exitcode, err );
- threadinfo_p->errcode = err;
- }
- g_hash_table_destroy ( threadinfo_p->fpath2ei_ht );
- if ( ( err = thread_exit ( threadinfo_p, exec_exitcode ) ) ) {
- exitcode = err; // This's global variable "exitcode"
- pthread_kill ( pthread_sighandler, SIGTERM );
- }
- debug ( 3, "thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p""; errcode %i",
- threadinfo_p->thread_num, threadinfo_p, threadinfo_p->pthread, pthread_self(), threadinfo_p->errcode );
- return exec_exitcode;
- }
- static inline int sync_exec_argv_thread ( ctx_t *ctx_p, indexes_t *indexes_p, thread_callbackfunct_t callback, thread_callbackfunct_arg_t *callback_arg_p, char **argv )
- {
- debug ( 2, "" );
- debug_argv_dump ( 2, argv );
- threadinfo_t *threadinfo_p = thread_new();
- if ( threadinfo_p == NULL )
- return errno;
- threadinfo_p->try_n = 0;
- threadinfo_p->callback = callback;
- threadinfo_p->callback_arg = callback_arg_p;
- threadinfo_p->argv = argv;
- threadinfo_p->ctx_p = ctx_p;
- threadinfo_p->starttime = time ( NULL );
- threadinfo_p->fpath2ei_ht = g_hash_table_dup ( indexes_p->fpath2ei_ht, g_str_hash, g_str_equal, free, free, ( gpointer ( * ) ( gpointer ) ) strdup, eidup );
- threadinfo_p->iteration = ctx_p->iteration_num;
- if ( ctx_p->synctimeout )
- threadinfo_p->expiretime = threadinfo_p->starttime + ctx_p->synctimeout;
- if ( pthread_create ( &threadinfo_p->pthread, NULL, ( void * ( * ) ( void * ) ) __sync_exec_thread, threadinfo_p ) ) {
- error ( "Cannot pthread_create()." );
- return errno;
- }
- debug ( 3, "thread %p", threadinfo_p->pthread );
- return 0;
- }
- /*
- static inline int sync_exec_thread(ctx_t *ctx_p, indexes_t *indexes_p, thread_callbackfunct_t callback, thread_callbackfunct_arg_t *callback_arg_p, ...) {
- debug(2, "");
- char **argv = (char **)xcalloc(sizeof(char *), MAXARGUMENTS);
- memset(argv, 0, sizeof(char *)*MAXARGUMENTS);
- _sync_exec_getargv(argv, callback_arg_p, strdup(arg));
- return sync_exec_argv_thread(ctx_p, indexes_p, callback, callback_arg_p, argv);
- }
- */
- #endif
- // } === SYNC_EXEC() ===
- static int sync_queuesync ( const char *fpath_rel, eventinfo_t *evinfo, ctx_t *ctx_p, indexes_t *indexes_p, queue_id_t queue_id )
- {
- debug ( 3, "sync_queuesync(\"%s\", ...): fsize == %lu; tres == %lu, queue_id == %u", fpath_rel, evinfo->fsize, ctx_p->bfilethreshold, queue_id );
- if ( queue_id == QUEUE_AUTO )
- queue_id = ( evinfo->fsize > ctx_p->bfilethreshold ) ? QUEUE_BIGFILE : QUEUE_NORMAL;
- queueinfo_t *queueinfo = &ctx_p->_queues[queue_id];
- if ( !queueinfo->stime )
- queueinfo->stime = time ( NULL );
- // char *fpath_rel = sync_path_abs2rel(ctx_p, fpath, -1, NULL, NULL);
- // Filename can contain "" character that conflicts with event-row separator of list-files.
- if ( strchr ( fpath_rel, '\n' ) ) {
- // At the moment, we will just ignore events of such files :(
- debug ( 3, "There's \"\\n\" character in path \"%s\". Ignoring it :(. Feedback to: https://github.com/clsync/clsync/issues/12", fpath_rel );
- return 0;
- }
- #ifdef CLUSTER_SUPPORT
- if ( ctx_p->cluster_iface )
- cluster_capture ( fpath_rel );
- #endif
- eventinfo_t *evinfo_q = indexes_lookupinqueue ( indexes_p, fpath_rel, queue_id );
- if ( evinfo_q == NULL ) {
- eventinfo_t *evinfo_dup = ( eventinfo_t * ) xmalloc ( sizeof ( *evinfo_dup ) );
- memcpy ( evinfo_dup, evinfo, sizeof ( *evinfo_dup ) );
- return indexes_queueevent ( indexes_p, strdup ( fpath_rel ), evinfo_dup, queue_id );
- } else {
- evinfo_merge ( ctx_p, evinfo_q, evinfo );
- }
- return 0;
- }
- static inline void evinfo_initialevmask ( ctx_t *ctx_p, eventinfo_t *evinfo_p, int isdir )
- {
- switch ( ctx_p->flags[MONITOR] ) {
- #ifdef FANOTIFY_SUPPORT
- case NE_FANOTIFY:
- critical ( "fanotify is not supported" );
- break;
- #endif
- #if INOTIFY_SUPPORT | KQUEUE_SUPPORT
- #ifdef INOTIFY_SUPPORT
- case NE_INOTIFY:
- #endif
- #ifdef KQUEUE_SUPPORT
- case NE_KQUEUE:
- #endif
- evinfo_p->evmask = IN_CREATE_SELF;
- if ( isdir )
- evinfo_p->evmask |= IN_ISDIR;
- break;
- #endif
- #ifdef BSM_SUPPORT
- case NE_BSM:
- case NE_BSM_PREFETCH:
- evinfo_p->evmask = ( isdir ? AUE_MKDIR : AUE_OPEN_RWC );
- break;
- #endif
- #ifdef GIO_SUPPORT
- case NE_GIO:
- evinfo_p->evmask = G_FILE_MONITOR_EVENT_CREATED;
- break;
- #endif
- #ifdef VERYPARANOID
- default:
- critical ( "Unknown monitor subsystem: %u", ctx_p->flags[MONITOR] );
- #endif
- }
- return;
- }
- static inline void api_evinfo_initialevmask ( ctx_t *ctx_p, api_eventinfo_t *evinfo_p, int isdir )
- {
- eventinfo_t evinfo = {0};
- evinfo_initialevmask ( ctx_p, &evinfo, isdir );
- evinfo_p->evmask = evinfo.evmask;
- return;
- }
- int sync_dosync ( const char *fpath, uint32_t evmask, ctx_t *ctx_p, indexes_t *indexes_p );
- int sync_initialsync_walk ( ctx_t *ctx_p, const char *dirpath, indexes_t *indexes_p, queue_id_t queue_id, initsync_t initsync )
- {
- int ret = 0;
- const char *rootpaths[] = {dirpath, NULL};
- eventinfo_t evinfo;
- FTS *tree;
- rule_t *rules_p = ctx_p->rules;
- debug ( 2, "(ctx_p, \"%s\", indexes_p, %i, %i).", dirpath, queue_id, initsync );
- char skip_rules = ( initsync == INITSYNC_FULL ) && ctx_p->flags[INITFULL];
- char rsync_and_prefer_excludes =
- (
- ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSHELL ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSO )
- ) &&
- !ctx_p->flags[RSYNCPREFERINCLUDE];
- if ( ( !ctx_p->flags[RSYNCPREFERINCLUDE] ) && skip_rules )
- return 0;
- skip_rules |= ( ctx_p->rules_count == 0 );
- char fts_no_stat =
- (
- (
- initsync == INITSYNC_FULL
- ) ||
- (
- ctx_p->_queues[QUEUE_NORMAL ].collectdelay ==
- ctx_p->_queues[QUEUE_BIGFILE].collectdelay
- ) ||
- (
- ctx_p->bfilethreshold == 0
- )
- ) && ! ( ctx_p->flags[EXCLUDEMOUNTPOINTS] );
- int fts_opts = FTS_NOCHDIR | FTS_PHYSICAL |
- ( fts_no_stat ? FTS_NOSTAT : 0 ) |
- ( ctx_p->flags[ONEFILESYSTEM] ? FTS_XDEV : 0 );
- debug ( 3, "fts_opts == %p", ( void * ) ( long ) fts_opts );
- tree = privileged_fts_open ( ( char *const * ) &rootpaths, fts_opts, NULL, PC_SYNC_INIIALSYNC_WALK_FTS_OPEN );
- if ( tree == NULL ) {
- error ( "Cannot privileged_fts_open() on \"%s\".", dirpath );
- return errno;
- }
- memset ( &evinfo, 0, sizeof ( evinfo ) );
- FTSENT *node;
- char *path_rel = NULL;
- size_t path_rel_len = 0;
- #ifdef VERYPARANOID
- errno = 0;
- #endif
- while ( ( node = privileged_fts_read ( tree, PC_SYNC_INIIALSYNC_WALK_FTS_READ ) ) ) {
- switch ( node->fts_info ) {
- // Duplicates:
- case FTS_DP:
- continue;
- // To sync:
- case FTS_DEFAULT:
- case FTS_SL:
- case FTS_SLNONE:
- case FTS_F:
- case FTS_D:
- case FTS_DOT:
- case FTS_DC: // TODO: think about case of FTS_DC
- case FTS_NSOK:
- break;
- // Error cases:
- case FTS_ERR:
- case FTS_NS:
- case FTS_DNR: {
- int fts_errno = node->fts_errno;
- if ( fts_errno == ENOENT ) {
- debug ( 1, "Got error while privileged_fts_read(): %s (errno: %i; fts_info: %i).", strerror ( fts_errno ), fts_errno, node->fts_info );
- continue;
- } else {
- error ( "Got error while privileged_fts_read(): %s (errno: %i; fts_info: %i).", strerror ( fts_errno ), fts_errno, node->fts_info );
- ret = node->fts_errno;
- goto l_sync_initialsync_walk_end;
- }
- }
- default:
- error ( "Got unknown fts_info vlaue while privileged_fts_read(): %i.", node->fts_info );
- ret = EINVAL;
- goto l_sync_initialsync_walk_end;
- }
- path_rel = sync_path_abs2rel ( ctx_p, node->fts_path, -1, &path_rel_len, path_rel );
- debug ( 3, "Pointing to \"%s\" (node->fts_info == %i)", path_rel, node->fts_info );
- if ( ctx_p->flags[EXCLUDEMOUNTPOINTS] && node->fts_info == FTS_D ) {
- if ( rsync_and_prefer_excludes ) {
- if ( node->fts_statp->st_dev != ctx_p->st_dev ) {
- debug ( 3, "Excluding \"%s\" due to location on other device: node->fts_statp->st_dev [0x%o] != ctx_p->st_dev [0x%o]", path_rel, node->fts_statp->st_dev, ctx_p->st_dev );
- if ( queue_id == QUEUE_AUTO ) {
- int i = 0;
- while ( i < QUEUE_MAX )
- indexes_addexclude ( indexes_p, strdup ( path_rel ), EVIF_CONTENTRECURSIVELY, i++ );
- } else
- indexes_addexclude ( indexes_p, strdup ( path_rel ), EVIF_CONTENTRECURSIVELY, queue_id );
- fts_set ( tree, node, FTS_SKIP );
- }
- } else if ( !ctx_p->flags[RSYNCPREFERINCLUDE] )
- error ( "Excluding mount points is not implentemted for non \"rsync*\" modes." );
- }
- mode_t st_mode = fts_no_stat ? ( node->fts_info == FTS_D ? S_IFDIR : S_IFREG ) : node->fts_statp->st_mode;
- if ( !skip_rules ) {
- ruleaction_t perm = rules_getperm ( path_rel, st_mode, rules_p, RA_WALK | RA_SYNC );
- if ( ! ( perm & RA_WALK ) ) {
- debug ( 3, "Rejecting to walk into \"%s\".", path_rel );
- fts_set ( tree, node, FTS_SKIP );
- }
- if ( ! ( perm & RA_SYNC ) ) {
- debug ( 3, "Excluding \"%s\".", path_rel );
- if ( rsync_and_prefer_excludes ) {
- if ( queue_id == QUEUE_AUTO ) {
- int i = 0;
- while ( i < QUEUE_MAX )
- indexes_addexclude ( indexes_p, strdup ( path_rel ), EVIF_NONE, i++ );
- } else
- indexes_addexclude ( indexes_p, strdup ( path_rel ), EVIF_NONE, queue_id );
- }
- continue;
- }
- }
- if ( !rsync_and_prefer_excludes ) {
- evinfo_initialevmask ( ctx_p, &evinfo, node->fts_info == FTS_D );
- switch ( ctx_p->flags[MODE] ) {
- case MODE_SIMPLE:
- SAFE ( sync_dosync ( node->fts_path, evinfo.evmask, ctx_p, indexes_p ), debug ( 1, "fpath == \"%s\"; evmask == 0x%o", node->fts_path, evinfo.evmask ); return -1; );
- continue;
- default:
- break;
- }
- evinfo.seqid_min = sync_seqid();
- evinfo.seqid_max = evinfo.seqid_min;
- evinfo.objtype_old = EOT_DOESNTEXIST;
- evinfo.objtype_new = node->fts_info == FTS_D ? EOT_DIR : EOT_FILE;
- evinfo.fsize = fts_no_stat ? 0 : node->fts_statp->st_size;
- debug ( 3, "queueing \"%s\" (depth: %i) with int-flags %p", node->fts_path, node->fts_level, ( void * ) ( unsigned long ) evinfo.flags );
- int _ret = sync_queuesync ( path_rel, &evinfo, ctx_p, indexes_p, queue_id );
- if ( _ret ) {
- error ( "Got error while queueing \"%s\".", node->fts_path );
- ret = errno;
- goto l_sync_initialsync_walk_end;
- }
- continue;
- }
- /* "FTS optimization" */
- if (
- skip_rules &&
- node->fts_info == FTS_D &&
- !ctx_p->flags[EXCLUDEMOUNTPOINTS]
- ) {
- debug ( 4, "\"FTS optimizator\"" );
- fts_set ( tree, node, FTS_SKIP );
- }
- }
- if ( errno ) {
- error ( "Got error while privileged_fts_read() and related routines." );
- ret = errno;
- goto l_sync_initialsync_walk_end;
- }
- if ( privileged_fts_close ( tree, PC_SYNC_INIIALSYNC_WALK_FTS_CLOSE ) ) {
- error ( "Got error while privileged_fts_close()." );
- ret = errno;
- goto l_sync_initialsync_walk_end;
- }
- l_sync_initialsync_walk_end:
- if ( path_rel != NULL )
- free ( path_rel );
- return ret;
- }
- const char *sync_parameter_get ( const char *variable_name, void *_dosync_arg_p )
- {
- struct dosync_arg *dosync_arg_p = _dosync_arg_p;
- ctx_t *ctx_p = dosync_arg_p->ctx_p;
- #ifdef _DEBUG_FORCE
- debug ( 15, "(\"%s\", %p): 0x%x, \"%s\"", variable_name, _dosync_arg_p, ctx_p == NULL ? 0 : ctx_p->synchandler_argf, dosync_arg_p->evmask_str );
- #endif
- if ( ( ctx_p == NULL || ( ctx_p->synchandler_argf & SHFL_INCLUDE_LIST_PATH ) ) && !strcmp ( variable_name, "INCLUDE-LIST-PATH" ) )
- return dosync_arg_p->outf_path;
- else if ( ( ctx_p == NULL || ( ctx_p->synchandler_argf & SHFL_EXCLUDE_LIST_PATH ) ) && !strcmp ( variable_name, "EXCLUDE-LIST-PATH" ) )
- return dosync_arg_p->excf_path;
- else if ( !strcmp ( variable_name, "TYPE" ) )
- return dosync_arg_p->list_type_str;
- else if ( !strcmp ( variable_name, "EVENT-MASK" ) )
- return dosync_arg_p->evmask_str;
- errno = ENOENT;
- return NULL;
- }
- static char **sync_customargv ( ctx_t *ctx_p, struct dosync_arg *dosync_arg_p, synchandler_args_t *args_p )
- {
- int d, s;
- char **argv = ( char ** ) xcalloc ( sizeof ( char * ), MAXARGUMENTS + 2 );
- s = d = 0;
- argv[d++] = strdup ( ctx_p->handlerfpath );
- while ( s < args_p->c ) {
- char *arg = args_p->v[s];
- char isexpanded = args_p->isexpanded[s];
- s++;
- #ifdef _DEBUG_FORCE
- debug ( 30, "\"%s\" [%p]", arg, arg );
- #endif
- if ( isexpanded ) {
- #ifdef _DEBUG_FORCE
- debug ( 19, "\"%s\" [%p] is already expanded, just strdup()-ing it", arg, arg );
- #endif
- argv[d++] = strdup ( arg );
- continue;
- }
- if ( !strcmp ( arg, "%INCLUDE-LIST%" ) ) {
- int i = 0, e = dosync_arg_p->include_list_count;
- const char **include_list = dosync_arg_p->include_list;
- #ifdef _DEBUG_FORCE
- debug ( 19, "INCLUDE-LIST: e == %u; d,s: %u,%u", e, d, s );
- #endif
- while ( i < e ) {
- #ifdef PARANOID
- if ( d >= MAXARGUMENTS ) {
- errno = E2BIG;
- critical ( "Too many arguments" );
- }
- #endif
- argv[d++] = parameter_expand ( ctx_p, strdup ( include_list[i++] ), PEF_NONE, NULL, NULL, sync_parameter_get, dosync_arg_p );
- #ifdef _DEBUG_FORCE
- debug ( 19, "include-list: argv[%u] == %p", d - 1, argv[d - 1] );
- #endif
- }
- continue;
- }
- #ifdef PARANOID
- if ( d >= MAXARGUMENTS ) {
- errno = E2BIG;
- critical ( "Too many arguments" );
- }
- #endif
- argv[d] = parameter_expand ( ctx_p, strdup ( arg ), PEF_NONE, NULL, NULL, sync_parameter_get, dosync_arg_p );
- #ifdef _DEBUG_FORCE
- debug ( 19, "argv[%u] == %p \"%s\"", d, argv[d], argv[d] );
- #endif
- d++;
- }
- argv[d] = NULL;
- #ifdef _DEBUG_FORCE
- debug ( 18, "return %p", argv );
- #endif
- return argv;
- }
- static void argv_free ( char **argv )
- {
- char **argv_p;
- #ifdef _DEBUG_FORCE
- debug ( 18, "(%p)", argv );
- #endif
- #ifdef VERYPARANOID
- if ( argv == NULL )
- critical ( MSG_SECURITY_PROBLEM ( "argv_free(NULL)" ) );
- #endif
- argv_p = argv;
- while ( *argv_p != NULL ) {
- #ifdef _DEBUG_FORCE
- debug ( 25, "free(%p)", *argv_p );
- #endif
- free ( * ( argv_p++ ) );
- }
- free ( argv );
- return;
- }
- static inline int sync_initialsync_finish ( ctx_t *ctx_p, initsync_t initsync, int ret )
- {
- ( void ) initsync;
- finish_iteration ( ctx_p );
- return ret;
- }
- int sync_initialsync ( const char *path, ctx_t *ctx_p, indexes_t *indexes_p, initsync_t initsync )
- {
- int ret;
- queue_id_t queue_id;
- debug ( 3, "(\"%s\", ctx_p, indexes_p, %i)", path, initsync );
- #ifdef CLUSTER_SUPPORT
- if ( initsync == INITSYNC_FULL ) {
- if ( ctx_p->cluster_iface )
- return cluster_initialsync();
- }
- #endif
- if ( initsync == INITSYNC_FULL )
- queue_id = QUEUE_INSTANT;
- else
- queue_id = QUEUE_NORMAL;
- // non-RSYNC case:
- if (
- ! (
- ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSHELL ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSO )
- )
- ) {
- debug ( 3, "syncing \"%s\"", path );
- if ( ctx_p->flags[HAVERECURSIVESYNC] ) {
- if ( ctx_p->flags[MODE] == MODE_SO ) {
- api_eventinfo_t *ei = ( api_eventinfo_t * ) xmalloc ( sizeof ( *ei ) );
- #ifdef PARANIOD
- memset ( ei, 0, sizeof ( *ei ) );
- #endif
- api_evinfo_initialevmask ( ctx_p, ei, 1 );
- ei->flags = EVIF_RECURSIVELY;
- ei->path_len = strlen ( path );
- ei->path = strdup ( path );
- ei->objtype_old = EOT_DOESNTEXIST;
- ei->objtype_new = EOT_DIR;
- ret = so_call_sync ( ctx_p, indexes_p, 1, ei );
- return sync_initialsync_finish ( ctx_p, initsync, ret );
- } else {
- struct dosync_arg dosync_arg;
- synchandler_args_t *args_p;
- args_p = ctx_p->synchandler_args[SHARGS_INITIAL].c ?
- &ctx_p->synchandler_args[SHARGS_INITIAL] :
- &ctx_p->synchandler_args[SHARGS_PRIMARY];
- dosync_arg.ctx_p = ctx_p;
- *dosync_arg.include_list = path;
- dosync_arg.include_list_count = 1;
- dosync_arg.list_type_str = "initialsync";
- char **argv = sync_customargv ( ctx_p, &dosync_arg, args_p );
- ret = SYNC_EXEC_ARGV (
- ctx_p,
- indexes_p,
- NULL,
- NULL,
- argv );
- #ifdef THREADING_SUPPORT
- if ( !SHOULD_THREAD ( ctx_p ) ) // If it's a thread then it will free the argv in GC. If not a thread then we have to free right here.
- #endif
- argv_free ( argv );
- return sync_initialsync_finish ( ctx_p, initsync, ret );
- }
- }
- #ifdef DOXYGEN
- sync_exec_argv ( NULL, NULL );
- sync_exec_argv_thread ( NULL, NULL );
- #endif
- ret = sync_initialsync_walk ( ctx_p, path, indexes_p, queue_id, initsync );
- if ( ret )
- error ( "Cannot get synclist" );
- return sync_initialsync_finish ( ctx_p, initsync, ret );
- }
- // RSYNC case:
- if ( !ctx_p->flags[RSYNCPREFERINCLUDE] ) {
- queueinfo_t *queueinfo = &ctx_p->_queues[queue_id];
- if ( !queueinfo->stime )
- queueinfo->stime = time ( NULL ); // Useful for debugging
- eventinfo_t *evinfo = ( eventinfo_t * ) xmalloc ( sizeof ( *evinfo ) );
- memset ( evinfo, 0, sizeof ( *evinfo ) );
- evinfo->flags |= EVIF_RECURSIVELY;
- evinfo->seqid_min = sync_seqid();
- evinfo->seqid_max = evinfo->seqid_min;
- evinfo->objtype_old = EOT_DOESNTEXIST;
- evinfo->objtype_new = EOT_DIR;
- // Searching for excludes
- ret = sync_initialsync_walk ( ctx_p, path, indexes_p, queue_id, initsync );
- if ( ret ) {
- error ( "Cannot get exclude what to exclude" );
- return sync_initialsync_finish ( ctx_p, initsync, ret );
- }
- debug ( 3, "queueing \"%s\" with int-flags %p", path, ( void * ) ( unsigned long ) evinfo->flags );
- char *path_rel = sync_path_abs2rel ( ctx_p, path, -1, NULL, NULL );
- ret = indexes_queueevent ( indexes_p, path_rel, evinfo, queue_id );
- return sync_initialsync_finish ( ctx_p, initsync, ret );
- }
- // Searching for includes
- ret = sync_initialsync_walk ( ctx_p, path, indexes_p, queue_id, initsync );
- return sync_initialsync_finish ( ctx_p, initsync, ret );
- }
- int sync_notify_mark ( ctx_t *ctx_p, const char *accpath, const char *path, size_t pathlen, indexes_t *indexes_p )
- {
- debug ( 3, "(..., \"%s\", %i,...)", path, pathlen );
- int wd = indexes_fpath2wd ( indexes_p, path );
- if ( wd != -1 ) {
- debug ( 1, "\"%s\" is already marked (wd: %i). Skipping.", path, wd );
- return wd;
- }
- debug ( 5, "ctx_p->notifyenginefunct.add_watch_dir(ctx_p, indexes_p, \"%s\")", accpath );
- if ( ( wd = ctx_p->notifyenginefunct.add_watch_dir ( ctx_p, indexes_p, accpath ) ) == -1 ) {
- if ( errno == ENOENT )
- return -2;
- error ( "Cannot ctx_p->notifyenginefunct.add_watch_dir() on \"%s\".",
- path );
- return -1;
- }
- debug ( 6, "endof ctx_p->notifyenginefunct.add_watch_dir(ctx_p, indexes_p, \"%s\")", accpath );
- indexes_add_wd ( indexes_p, wd, path, pathlen );
- return wd;
- }
- #ifdef CLUSTER_SUPPORT
- static inline int sync_mark_walk_cluster_modtime_update ( ctx_t *ctx_p, const char *path, short int dirlevel, mode_t st_mode )
- {
- if ( ctx_p->cluster_iface ) {
- int ret = cluster_modtime_update ( path, dirlevel, st_mode );
- if ( ret ) error ( "cannot cluster_modtime_update()" );
- return ret;
- }
- return 0;
- }
- #endif
- int sync_mark_walk ( ctx_t *ctx_p, const char *dirpath, indexes_t *indexes_p )
- {
- int ret = 0;
- const char *rootpaths[] = {dirpath, NULL};
- FTS *tree;
- rule_t *rules_p = ctx_p->rules;
- debug ( 2, "(ctx_p, \"%s\", indexes_p).", dirpath );
- int fts_opts = FTS_NOCHDIR | FTS_PHYSICAL | FTS_NOSTAT | ( ctx_p->flags[ONEFILESYSTEM] ? FTS_XDEV : 0 );
- debug ( 3, "fts_opts == %p", ( void * ) ( long ) fts_opts );
- tree = privileged_fts_open ( ( char *const * ) rootpaths, fts_opts, NULL, PC_SYNC_MARK_WALK_FTS_OPEN );
- if ( tree == NULL ) {
- error_or_debug ( ( ctx_p->state == STATE_STARTING ) ? -1 : 2, "Cannot privileged_fts_open() on \"%s\".", dirpath );
- return errno;
- }
- FTSENT *node;
- char *path_rel = NULL;
- size_t path_rel_len = 0;
- #ifdef VERYPARANOID
- errno = 0;
- #endif
- while ( ( node = privileged_fts_read ( tree, PC_SYNC_MARK_WALK_FTS_READ ) ) ) {
- #ifdef CLUSTER_SUPPORT
- int ret;
- #endif
- debug ( 2, "walking: \"%s\" (depth %u): fts_info == %i", node->fts_path, node->fts_level, node->fts_info );
- switch ( node->fts_info ) {
- // Duplicates:
- case FTS_DP:
- continue;
- // Files:
- case FTS_DEFAULT:
- case FTS_SL:
- case FTS_SLNONE:
- case FTS_F:
- case FTS_NSOK:
- #ifdef CLUSTER_SUPPORT
- if ( ( ret = sync_mark_walk_cluster_modtime_update ( ctx_p, node->fts_path, node->fts_level, S_IFREG ) ) )
- goto l_sync_mark_walk_end;
- #endif
- continue;
- // Directories (to mark):
- case FTS_D:
- case FTS_DC: // TODO: think about case of FTS_DC
- case FTS_DOT:
- #ifdef CLUSTER_SUPPORT
- if ( ( ret = sync_mark_walk_cluster_modtime_update ( ctx_p, node->fts_path, node->fts_level, S_IFDIR ) ) )
- goto l_sync_mark_walk_end;
- #endif
- break;
- // Error cases:
- case FTS_ERR:
- case FTS_NS:
- case FTS_DNR:
- if ( errno == ENOENT ) {
- debug ( 1, "Got error while privileged_fts_read(); fts_info: %i.", node->fts_info );
- continue;
- } else {
- error_or_debug ( ( ctx_p->state == STATE_STARTING ) ? -1 : 2, "Got error while privileged_fts_read(); fts_info: %i.", node->fts_info );
- ret = errno;
- goto l_sync_mark_walk_end;
- }
- default:
- error_or_debug ( ( ctx_p->state == STATE_STARTING ) ? -1 : 2, "Got unknown fts_info vlaue while privileged_fts_read(): %i.", node->fts_info );
- ret = EINVAL;
- goto l_sync_mark_walk_end;
- }
- path_rel = sync_path_abs2rel ( ctx_p, node->fts_path, -1, &path_rel_len, path_rel );
- ruleaction_t perm = rules_search_getperm ( path_rel, S_IFDIR, rules_p, RA_WALK, NULL );
- debug ( 3, "perm == 0x%o", perm );
- if ( ! ( perm & RA_WALK ) ) {
- debug ( 2, "setting an FTS_SKIP on the directory" );
- if ( fts_set ( tree, node, FTS_SKIP ) )
- warning ( "Got error while fts_set(tree, node, FTS_SKIP): %s", path_rel );
- }
- if ( ! ( perm & RA_MONITOR ) ) {
- debug ( 2, "don't mark the directory" );
- continue;
- }
- debug ( 2, "marking \"%s\" (depth %u)", node->fts_path, node->fts_level );
- int wd = sync_notify_mark ( ctx_p, node->fts_accpath, node->fts_path, node->fts_pathlen, indexes_p );
- if ( wd == -1 ) {
- error_or_debug ( ( ctx_p->state == STATE_STARTING ) ? -1 : 2, "Got error while notify-marking \"%s\".", node->fts_path );
- ret = errno;
- goto l_sync_mark_walk_end;
- }
- debug ( 2, "watching descriptor is %i.", wd );
- }
- if ( errno ) {
- error_or_debug ( ( ctx_p->state == STATE_STARTING ) ? -1 : 2, "Got error while privileged_fts_read() and related routines." );
- ret = errno;
- goto l_sync_mark_walk_end;
- }
- if ( privileged_fts_close ( tree, PC_SYNC_MARK_WALK_FTS_CLOSE ) ) {
- error_or_debug ( ( ctx_p->state == STATE_STARTING ) ? -1 : 2, "Got error while privileged_fts_close()." );
- ret = errno;
- goto l_sync_mark_walk_end;
- }
- l_sync_mark_walk_end:
- if ( path_rel != NULL )
- free ( path_rel );
- return ret;
- }
- int sync_notify_init ( ctx_t *ctx_p )
- {
- switch ( ctx_p->flags[MONITOR] ) {
- #ifdef FANOTIFY_SUPPORT
- case NE_FANOTIFY: {
- ctx_p->fsmondata = ( long ) fanotify_init ( FANOTIFY_FLAGS, FANOTIFY_EVFLAGS );
- if ( ( long ) ctx_p->fsmondata == -1 ) {
- error ( "cannot fanotify_init(%i, %i).", FANOTIFY_FLAGS, FANOTIFY_EVFLAGS );
- return -1;
- }
- return 0;
- }
- #endif
- #ifdef INOTIFY_SUPPORT
- case NE_INOTIFY: {
- # ifdef INOTIFY_OLD
- ctx_p->fsmondata = ( void * ) ( long ) inotify_init();
- # if INOTIFY_FLAGS != 0
- # warning Do not know how to set inotify flags (too old system)
- # endif
- # else
- ctx_p->fsmondata = ( void * ) ( long ) inotify_init1 ( INOTIFY_FLAGS );
- # endif
- if ( ( long ) ctx_p->fsmondata == -1 ) {
- error ( "cannot inotify_init1(%i).", INOTIFY_FLAGS );
- return -1;
- }
- return 0;
- }
- #endif
- #ifdef KQUEUE_SUPPORT
- case NE_KQUEUE: {
- int kqueue_d = kqueue_init ( ctx_p );
- if ( kqueue_d == -1 ) {
- error ( "cannot kqueue_init(ctx_p)." );
- return -1;
- }
- return 0;
- }
- #endif
- #ifdef BSM_SUPPORT
- case NE_BSM:
- case NE_BSM_PREFETCH: {
- int bsm_d = bsm_init ( ctx_p );
- if ( bsm_d == -1 ) {
- error ( "cannot bsm_init(ctx_p)." );
- return -1;
- }
- return 0;
- }
- #endif
- #ifdef GIO_SUPPORT
- case NE_GIO: {
- critical_on ( gio_init ( ctx_p ) == -1 );
- return 0;
- }
- #endif
- }
- error ( "unknown notify-engine: %i", ctx_p->flags[MONITOR] );
- errno = EINVAL;
- return -1;
- }
- static inline int sync_dosync_exec ( ctx_t *ctx_p, indexes_t *indexes_p, const char *evmask_str, const char *fpath )
- {
- int rc;
- struct dosync_arg dosync_arg;
- debug ( 20, "(ctx_p, indexes_p, \"%s\", \"%s\")", evmask_str, fpath );
- dosync_arg.ctx_p = ctx_p;
- *dosync_arg.include_list = fpath;
- dosync_arg.include_list_count = 1;
- dosync_arg.list_type_str = "sync";
- dosync_arg.evmask_str = evmask_str;
- char **argv = sync_customargv ( ctx_p, &dosync_arg, &ctx_p->synchandler_args[SHARGS_PRIMARY] );
- rc = SYNC_EXEC_ARGV (
- ctx_p,
- indexes_p,
- NULL, NULL,
- argv );
- #ifdef THREADING_SUPPORT
- if ( !SHOULD_THREAD ( ctx_p ) ) // If it's a thread then it will free the argv in GC. If not a thread then we have to free right here.
- #endif
- argv_free ( argv );
- return rc;
- #ifdef DOXYGEN
- sync_exec_argv ( NULL, NULL );
- sync_exec_argv_thread ( NULL, NULL );
- #endif
- }
- int sync_dosync ( const char *fpath, uint32_t evmask, ctx_t *ctx_p, indexes_t *indexes_p )
- {
- int ret;
- #ifdef CLUSTER_SUPPORT
- ret = cluster_lock ( fpath );
- if ( ret ) return ret;
- #endif
- char *evmask_str = xmalloc ( 1 << 8 );
- sprintf ( evmask_str, "%u", evmask );
- ret = sync_dosync_exec ( ctx_p, indexes_p, evmask_str, fpath );
- free ( evmask_str );
- #ifdef CLUSTER_SUPPORT
- ret = cluster_unlock_all();
- #endif
- return ret;
- }
- int fileischanged ( ctx_t *ctx_p, indexes_t *indexes_p, const char *path_rel, stat64_t *lst_p, int is_deleted )
- {
- if ( lst_p == NULL || !ctx_p->flags[MODSIGN] )
- return 1;
- debug ( 9, "Checking modification signature" );
- fileinfo_t *finfo = indexes_fileinfo ( indexes_p, path_rel );
- if ( finfo != NULL ) {
- uint32_t diff;
- if ( ! ( diff = stat_diff ( &finfo->lst, lst_p ) & ctx_p->flags[MODSIGN] ) ) {
- debug ( 8, "Modification signature: File not changed: \"%s\"", path_rel );
- return 0; // Skip file syncing if it's metadata not changed enough (according to "--modification-signature" setting)
- }
- debug ( 8, "Modification signature: stat_diff == 0x%o; significant diff == 0x%o (ctx_p->flags[MODSIGN] == 0x%o)", diff, diff & ctx_p->flags[MODSIGN], ctx_p->flags[MODSIGN] );
- if ( is_deleted ) {
- debug ( 8, "Modification signature: Deleting information about \"%s\"", path_rel );
- indexes_fileinfo_add ( indexes_p, path_rel, NULL );
- free ( finfo );
- } else {
- debug ( 8, "Modification signature: Updating information about \"%s\"", path_rel );
- memcpy ( &finfo->lst, lst_p, sizeof ( finfo->lst ) );
- }
- } else {
- debug ( 8, "There's no information about this file/dir: \"%s\". Just remembering the current state.", path_rel );
- // Adding file/dir information
- finfo = xmalloc ( sizeof ( *finfo ) );
- memcpy ( &finfo->lst, lst_p, sizeof ( finfo->lst ) );
- indexes_fileinfo_add ( indexes_p, path_rel, finfo );
- }
- return 1;
- }
- static inline int sync_indexes_fpath2ei_addfixed ( ctx_t *ctx_p, indexes_t *indexes_p, const char *fpath, eventinfo_t *evinfo )
- {
- static const char fpath_dot[] = ".";
- const char *fpath_fixed;
- fpath_fixed = fpath;
- switch ( ctx_p->flags[MODE] ) {
- case MODE_DIRECT:
- // If fpath is empty (that means CWD) then assign it to "."
- if ( !*fpath )
- fpath_fixed = fpath_dot;
- break;
- default:
- break;
- }
- return indexes_fpath2ei_add ( indexes_p, strdup ( fpath_fixed ), evinfo );
- }
- int sync_prequeue_loadmark
- (
- int monitored, // Is an event from event monitor handler (1 -- it is; 0 -- it doesn't)
- ctx_t *ctx_p,
- indexes_t *indexes_p,
- const char *path_full,
- const char *path_rel,
- stat64_t *lst_p,
- eventobjtype_t objtype_old,
- eventobjtype_t objtype_new,
- uint32_t event_mask,
- int event_wd,
- mode_t st_mode,
- off_t st_size,
- char **path_buf_p,
- size_t *path_buf_len_p,
- eventinfo_t *evinfo
- )
- {
- debug ( 10, "%i %p %p %p %p %p %i %i 0x%o %i %i %i %p %p %p",
- monitored,
- ctx_p,
- indexes_p,
- path_full,
- path_rel,
- lst_p,
- objtype_old,
- objtype_new,
- event_mask,
- event_wd,
- st_mode,
- st_size,
- path_buf_p,
- path_buf_len_p,
- evinfo
- );
- #ifdef PARANOID
- // &path_buf and &path_buf_len are passed to do not reallocate memory for path_rel/path_full each time
- if ( ( path_buf_p == NULL || path_buf_len_p == NULL ) && ( path_full == NULL || path_rel == NULL ) ) {
- error ( "path_rel_p == NULL || path_rel_len_p == NULL" );
- return EINVAL;
- }
- #endif
- #ifdef VERYPARANOID
- if ( path_full == NULL && path_rel == NULL ) {
- error ( "path_full == NULL && path_rel == NULL" );
- return EINVAL;
- }
- #endif
- if ( path_rel == NULL ) {
- *path_buf_p = sync_path_abs2rel ( ctx_p, path_full, -1, path_buf_len_p, *path_buf_p );
- path_rel = *path_buf_p;
- }
- ruleaction_t perm = RA_ALL;
- if ( st_mode ) {
- // Checking by filter rules
- perm = rules_getperm ( path_rel, st_mode, ctx_p->rules, RA_WALK | RA_MONITOR | RA_SYNC );
- if ( ! ( perm & ( RA_MONITOR | RA_WALK | RA_SYNC ) ) ) {
- return 0;
- }
- }
- // Handling different cases
- int is_dir = objtype_old == EOT_DIR || objtype_new == EOT_DIR;
- int is_created = objtype_old == EOT_DOESNTEXIST;
- int is_deleted = objtype_new == EOT_DOESNTEXIST;
- debug ( 4, "is_dir == %x; is_created == %x; is_deleted == %x", is_dir, is_created, is_deleted );
- if ( is_dir ) {
- if ( is_created ) {
- int ret;
- if ( perm & ( RA_WALK | RA_MONITOR ) ) {
- if ( path_full == NULL ) {
- *path_buf_p = sync_path_rel2abs ( ctx_p, path_rel, -1, path_buf_len_p, *path_buf_p );
- path_full = *path_buf_p;
- }
- if ( ( perm & RA_MONITOR ) && monitored ) {
- ret = sync_mark_walk ( ctx_p, path_full, indexes_p );
- if ( ret ) {
- debug ( 1, "Seems, that directory \"%s\" disappeared, while trying to mark it.", path_full );
- return 0;
- }
- }
- if ( perm & RA_WALK ) {
- ret = sync_initialsync ( path_full, ctx_p, indexes_p, INITSYNC_SUBDIR );
- if ( ret ) {
- errno = ret;
- error ( "Got error from sync_initialsync()" );
- return errno;
- }
- }
- }
- fileischanged ( ctx_p, indexes_p, path_rel, lst_p, is_deleted ); // Just to remember it's state
- return 0;
- } else if ( is_deleted ) {
- debug ( 2, "Disappeared \".../%s\".", path_rel );
- }
- }
- if ( ! ( perm & RA_SYNC ) ) {
- return 0;
- }
- if ( !fileischanged ( ctx_p, indexes_p, path_rel, lst_p, is_deleted ) ) {
- debug ( 4, "The file/dir is not changed. Returning." );
- return 0;
- }
- switch ( ctx_p->flags[MODE] ) {
- case MODE_SIMPLE:
- if ( path_full == NULL ) {
- *path_buf_p = sync_path_rel2abs ( ctx_p, path_rel, -1, path_buf_len_p, *path_buf_p );
- path_full = *path_buf_p;
- }
- return SAFE ( sync_dosync ( path_full, event_mask, ctx_p, indexes_p ), debug ( 1, "fpath == \"%s\"; evmask == 0x%o", path_full, event_mask ); return -1; );
- default:
- break;
- }
- // Locally queueing the event
- int isnew = 0;
- if ( evinfo == NULL )
- evinfo = indexes_fpath2ei ( indexes_p, path_rel );
- else
- isnew++; // It's new for prequeue (but old for lockwait queue)
- if ( evinfo == NULL ) {
- evinfo = ( eventinfo_t * ) xmalloc ( sizeof ( *evinfo ) );
- memset ( evinfo, 0, sizeof ( *evinfo ) );
- evinfo->fsize = st_size;
- evinfo->wd = event_wd;
- evinfo->seqid_min = sync_seqid();
- evinfo->seqid_max = evinfo->seqid_min;
- evinfo->objtype_old = objtype_old;
- isnew++;
- debug ( 3, "new event: fsize == %i; wd == %i", evinfo->fsize, evinfo->wd );
- } else {
- evinfo->seqid_max = sync_seqid();
- }
- switch ( ctx_p->flags[MONITOR] ) {
- #ifdef KQUEUE_SUPPORT
- case NE_KQUEUE:
- #endif
- #ifdef INOTIFY_SUPPORT
- case NE_INOTIFY:
- #endif
- #if KQUEUE_SUPPORT | INOTIFY_SUPPORT
- evinfo->evmask |= event_mask;
- break;
- #endif
- #ifdef BSM_SUPPORT
- case NE_BSM:
- case NE_BSM_PREFETCH:
- evinfo->evmask = event_mask;
- break;
- #endif
- #ifdef GIO_SUPPORT
- case NE_GIO:
- evinfo->evmask = event_mask;
- break;
- #endif
- }
- evinfo->objtype_new = objtype_new;
- debug ( 2, "path_rel == \"%s\"; evinfo->objtype_old == %i; evinfo->objtype_new == %i; "
- "evinfo->seqid_min == %u; evinfo->seqid_max == %u",
- path_rel, evinfo->objtype_old, evinfo->objtype_new,
- evinfo->seqid_min, evinfo->seqid_max
- );
- if ( isnew )
- // Fix the path (if required) and call indexes_fpath2ei_add() to remeber the new object to be synced
- sync_indexes_fpath2ei_addfixed ( ctx_p, indexes_p, path_rel, evinfo );
- return 0;
- }
- void _sync_idle_dosync_collectedexcludes ( gpointer fpath_gp, gpointer flags_gp, gpointer arg_gp )
- {
- char *fpath = ( char * ) fpath_gp;
- indexes_t *indexes_p = ( ( struct dosync_arg * ) arg_gp )->indexes_p;
- debug ( 3, "\"%s\", %u (%p).", fpath, GPOINTER_TO_INT ( flags_gp ), flags_gp );
- indexes_addexclude_aggr ( indexes_p, strdup ( fpath ), ( eventinfo_flags_t ) GPOINTER_TO_INT ( flags_gp ) );
- return;
- }
- // Is not a thread-save function!
- eventinfo_t *ht_fpath_isincluded ( GHashTable *ht, const char *const fpath )
- {
- static char buf[PATH_MAX + 2] = {0};
- char *ptr, *end;
- eventinfo_t *evinfo = g_hash_table_lookup ( ht, fpath );
- debug ( 5, "looking up for \"%s\": %p", fpath, evinfo );
- if ( evinfo != NULL )
- return evinfo;
- if ( !*fpath )
- return NULL;
- evinfo = g_hash_table_lookup ( ht, "" );
- if ( evinfo != NULL ) {
- debug ( 5, "recursive looking up for \"\": %p (%x: recusively: %x)", evinfo, evinfo->flags, evinfo->flags & EVIF_RECURSIVELY );
- if ( evinfo->flags & EVIF_RECURSIVELY )
- return evinfo;
- }
- size_t fpath_len = strlen ( fpath );
- memcpy ( buf, fpath, fpath_len + 1 );
- ptr = buf;
- end = &buf[fpath_len];
- while ( ptr < end ) {
- if ( *ptr == '/' ) {
- *ptr = 0;
- evinfo = g_hash_table_lookup ( ht, buf );
- if ( evinfo != NULL ) {
- debug ( 5, "recursive looking up for \"%s\": %p (%x: recusively: %x)", buf, evinfo, evinfo->flags, evinfo->flags & EVIF_RECURSIVELY );
- *ptr = '/';
- if ( evinfo->flags & EVIF_RECURSIVELY )
- return evinfo;
- }
- }
- ptr++;
- }
- return evinfo;
- }
- int _sync_islocked ( threadinfo_t *threadinfo_p, void *_fpath )
- {
- char *fpath = _fpath;
- eventinfo_t *evinfo = ht_fpath_isincluded ( threadinfo_p->fpath2ei_ht, fpath );
- debug ( 4, "scanning thread %p: fpath<%s> -> evinfo<%p>", threadinfo_p->pthread, fpath, evinfo );
- if ( evinfo != NULL )
- return 1;
- return 0;
- }
- static inline int sync_islocked ( const char *const fpath )
- {
- #ifdef THREADING_SUPPORT
- int rc = threads_foreach ( _sync_islocked, STATE_RUNNING, ( void * ) fpath );
- debug ( 3, "<%s>: %u", fpath, rc );
- return rc;
- #else
- return 0;
- #endif
- }
- void _sync_idle_dosync_collectedevents ( gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp )
- {
- char *fpath = ( char * ) fpath_gp;
- eventinfo_t *evinfo = ( eventinfo_t * ) evinfo_gp;
- int *evcount_p = & ( ( struct dosync_arg * ) arg_gp )->evcount;
- ctx_t *ctx_p = ( ( struct dosync_arg * ) arg_gp )->ctx_p;
- indexes_t *indexes_p = ( ( struct dosync_arg * ) arg_gp )->indexes_p;
- queue_id_t queue_id = ( queue_id_t ) ( ( struct dosync_arg * ) arg_gp )->data;
- debug ( 3, "queue_id == %i.", queue_id );
- if ( ctx_p->flags[THREADING] == PM_SAFE )
- if ( sync_islocked ( fpath ) ) {
- debug ( 3, "\"%s\" is locked, dropping to waitlock queue", fpath );
- eventinfo_t *evinfo_dup = xmalloc ( sizeof ( *evinfo_dup ) );
- memcpy ( evinfo_dup, evinfo, sizeof ( *evinfo ) );
- sync_queuesync ( fpath, evinfo_dup, ctx_p, indexes_p, QUEUE_LOCKWAIT );
- return;
- }
- if ( ( ctx_p->listoutdir == NULL ) && ( ! ( ctx_p->synchandler_argf & SHFL_INCLUDE_LIST ) ) && ( ! ( ctx_p->flags[MODE] == MODE_SO ) ) ) {
- debug ( 3, "calling sync_dosync()" );
- SAFE ( sync_dosync ( fpath, evinfo->evmask, ctx_p, indexes_p ), debug ( 1, "fpath == \"%s\"; evmask == 0x%o", fpath, evinfo->evmask ); exit ( errno ? errno : -1 ) ); // TODO: remove exit() from here
- return;
- }
- int isnew = 0;
- eventinfo_t *evinfo_idx = indexes_fpath2ei ( indexes_p, fpath );
- if ( evinfo_idx == NULL ) {
- evinfo_idx = ( eventinfo_t * ) xmalloc ( sizeof ( *evinfo_idx ) );
- memset ( evinfo_idx, 0, sizeof ( *evinfo_idx ) );
- isnew++;
- ( *evcount_p )++;
- evinfo_idx->evmask = evinfo->evmask;
- evinfo_idx->flags = evinfo->flags;
- evinfo_idx->objtype_old = evinfo->objtype_old;
- evinfo_idx->objtype_new = evinfo->objtype_new;
- evinfo_idx->seqid_min = evinfo->seqid_min;
- evinfo_idx->seqid_max = evinfo->seqid_max;
- } else
- evinfo_merge ( ctx_p, evinfo_idx, evinfo );
- queue_id_t _queue_id = 0;
- while ( _queue_id < QUEUE_MAX ) {
- if ( _queue_id == queue_id ) {
- _queue_id++;
- continue;
- }
- eventinfo_t *evinfo_q = indexes_lookupinqueue ( indexes_p, fpath, _queue_id );
- if ( evinfo_q != NULL ) {
- evinfo_merge ( ctx_p, evinfo_idx, evinfo_q );
- indexes_removefromqueue ( indexes_p, fpath, _queue_id );
- if ( !indexes_queuelen ( indexes_p, _queue_id ) )
- ctx_p->_queues[_queue_id].stime = 0;
- }
- _queue_id++;
- }
- if ( isnew ) {
- debug ( 4, "Collecting \"%s\"", fpath );
- // Fix the path (if required) and call indexes_fpath2ei_add() to remeber the new object to be synced
- sync_indexes_fpath2ei_addfixed ( ctx_p, indexes_p, fpath, evinfo_idx );
- } else
- free ( fpath );
- return;
- }
- struct trylocked_arg {
- char *path_full;
- size_t path_full_len;
- };
- gboolean sync_trylocked ( gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp )
- {
- char *fpath = ( char * ) fpath_gp;
- eventinfo_t *evinfo = ( eventinfo_t * ) evinfo_gp;
- struct dosync_arg *arg_p = ( struct dosync_arg * ) arg_gp;
- ctx_t *ctx_p = arg_p->ctx_p;
- indexes_t *indexes_p = arg_p->indexes_p;
- struct trylocked_arg *data = arg_p->data;
- if ( !sync_islocked ( fpath ) ) {
- if ( sync_prequeue_loadmark ( 0, ctx_p, indexes_p, NULL, fpath, NULL,
- evinfo->objtype_old,
- evinfo->objtype_new,
- evinfo->evmask,
- 0, 0, 0, &data->path_full, &data->path_full_len, evinfo ) ) {
- critical ( "Cannot re-queue \"%s\" to be synced", fpath );
- return FALSE;
- }
- return TRUE;
- }
- return FALSE;
- }
- int sync_idle_dosync_collectedevents_cleanup ( ctx_t *ctx_p, thread_callbackfunct_arg_t *arg_p )
- {
- int ret0 = 0, ret1 = 0;
- if ( ctx_p->flags[DONTUNLINK] )
- return 0;
- debug ( 3, "(ctx_p, {inc: %p, exc: %p}) thread %p", arg_p->incfpath, arg_p->excfpath, pthread_self() );
- if ( arg_p->excfpath != NULL ) {
- debug ( 3, "unlink()-ing exclude-file: \"%s\"", arg_p->excfpath );
- ret0 = unlink ( arg_p->excfpath );
- free ( arg_p->excfpath );
- }
- if ( arg_p->incfpath != NULL ) {
- debug ( 3, "unlink()-ing include-file: \"%s\"", arg_p->incfpath );
- ret1 = unlink ( arg_p->incfpath );
- free ( arg_p->incfpath );
- }
- free ( arg_p );
- return ret0 ? ret0 : ret1;
- }
- void sync_queuesync_wrapper ( gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp )
- {
- char *fpath_rel = ( char * ) fpath_gp;
- eventinfo_t *evinfo = ( eventinfo_t * ) evinfo_gp;
- ctx_t *ctx_p = ( ( struct dosync_arg * ) arg_gp )->ctx_p;
- indexes_t *indexes_p = ( ( struct dosync_arg * ) arg_gp )->indexes_p;
- sync_queuesync ( fpath_rel, evinfo, ctx_p, indexes_p, QUEUE_AUTO );
- return;
- }
- int sync_prequeue_unload ( ctx_t *ctx_p, indexes_t *indexes_p )
- {
- struct dosync_arg dosync_arg;
- dosync_arg.ctx_p = ctx_p;
- dosync_arg.indexes_p = indexes_p;
- debug ( 3, "collected %i events per this time.", g_hash_table_size ( indexes_p->fpath2ei_ht ) );
- g_hash_table_foreach ( indexes_p->fpath2ei_ht, sync_queuesync_wrapper, &dosync_arg );
- g_hash_table_remove_all ( indexes_p->fpath2ei_ht );
- return 0;
- }
- int sync_idle_dosync_collectedevents_aggrqueue ( queue_id_t queue_id, ctx_t *ctx_p, indexes_t *indexes_p, struct dosync_arg *dosync_arg )
- {
- time_t tm = time ( NULL );
- queueinfo_t *queueinfo = &ctx_p->_queues[queue_id];
- if ( ( ctx_p->state == STATE_RUNNING ) && ( queueinfo->stime + queueinfo->collectdelay > tm ) && ( queueinfo->collectdelay != COLLECTDELAY_INSTANT ) && ( !ctx_p->flags[EXITONNOEVENTS] ) ) {
- debug ( 3, "(%i, ...): too early (%i + %i > %i).", queue_id, queueinfo->stime, queueinfo->collectdelay, tm );
- return 0;
- }
- queueinfo->stime = 0;
- int evcount_real = g_hash_table_size ( indexes_p->fpath2ei_coll_ht[queue_id] );
- debug ( 3, "(%i, ...): evcount_real == %i", queue_id, evcount_real );
- if ( evcount_real <= 0 ) {
- debug ( 3, "(%i, ...): no events, return 0.", queue_id );
- return 0;
- }
- switch ( queue_id ) {
- case QUEUE_LOCKWAIT: {
- struct trylocked_arg arg_data = {0};
- dosync_arg->data = &arg_data;
- g_hash_table_foreach_remove ( indexes_p->fpath2ei_coll_ht[queue_id], sync_trylocked, dosync_arg );
- // Placing to global queues recently unlocked objects
- sync_prequeue_unload ( ctx_p, indexes_p );
- #ifdef PARANOID
- if ( arg_data.path_full != NULL )
- #endif
- free ( arg_data.path_full );
- break;
- }
- default: {
- g_hash_table_foreach ( indexes_p->fpath2ei_coll_ht[queue_id], _sync_idle_dosync_collectedevents, dosync_arg );
- g_hash_table_remove_all ( indexes_p->fpath2ei_coll_ht[queue_id] );
- if ( !ctx_p->flags[RSYNCPREFERINCLUDE] ) {
- g_hash_table_foreach ( indexes_p->exc_fpath_coll_ht[queue_id], _sync_idle_dosync_collectedexcludes, dosync_arg );
- g_hash_table_remove_all ( indexes_p->exc_fpath_coll_ht[queue_id] );
- }
- break;
- }
- }
- return 0;
- }
- int sync_idle_dosync_collectedevents_uniqfname ( ctx_t *ctx_p, char *fpath, char *name )
- {
- pid_t pid = getpid();
- time_t tm = time ( NULL );
- stat64_t stat64;
- int counter = 0;
- do {
- snprintf ( fpath, PATH_MAX, "%s/.clsync-%s.%u.%lu.%lu.%u", ctx_p->listoutdir, name, pid, ( long ) pthread_self(), ( unsigned long ) tm, rand() ); // To be unique
- lstat64 ( fpath, &stat64 );
- if ( counter++ > COUNTER_LIMIT ) {
- error ( "Cannot find unused filename for list-file. The last try was \"%s\".", fpath );
- return ENOENT;
- }
- } while ( errno != ENOENT ); // TODO: find another way to check if the object exists
- errno = 0;
- return 0;
- }
- int sync_idle_dosync_collectedevents_listcreate ( struct dosync_arg *dosync_arg_p, char *name )
- {
- debug ( 3, "Creating %s file", name );
- char *fpath = dosync_arg_p->outf_path;
- ctx_t *ctx_p = dosync_arg_p->ctx_p;
- int ret;
- if ( ( ret = sync_idle_dosync_collectedevents_uniqfname ( ctx_p, fpath, name ) ) ) {
- error ( "sync_idle_dosync_collectedevents_listcreate: Cannot get unique file name." );
- return ret;
- }
- dosync_arg_p->outf = fopen ( fpath, "w" );
- if ( dosync_arg_p->outf == NULL ) {
- error ( "Cannot open \"%s\" as file for writing.", fpath );
- return errno;
- }
- setbuffer ( dosync_arg_p->outf, dosync_arg_p->buf, BUFSIZ );
- debug ( 3, "Created list-file \"%s\"", fpath );
- dosync_arg_p->linescount = 0;
- return 0;
- }
- size_t rsync_escape_result_size = 0;
- char *rsync_escape_result = NULL;
- void rsync_escape_cleanup()
- {
- if ( rsync_escape_result_size )
- free ( rsync_escape_result );
- }
- const char *rsync_escape ( const char *path )
- {
- size_t sc_count = 0;
- size_t i = 0;
- while ( 1 ) {
- switch ( path[i] ) {
- case 0:
- goto l_rsync_escape_loop0_end;
- case '[':
- case ']':
- case '*':
- case '?':
- case '\\':
- sc_count++;
- }
- i++;
- };
- l_rsync_escape_loop0_end:
- if ( !sc_count )
- return path;
- size_t required_size = i + sc_count + 1;
- if ( required_size >= rsync_escape_result_size ) {
- rsync_escape_result_size = required_size + ALLOC_PORTION;
- rsync_escape_result = xrealloc ( rsync_escape_result, rsync_escape_result_size );
- }
- // TODO: Optimize this. Second "switch" is a bad way.
- i++;
- while ( i-- ) {
- rsync_escape_result[i + sc_count] = path[i];
- switch ( path[i] ) {
- case '[':
- case ']':
- case '*':
- case '?':
- case '\\':
- sc_count--;
- rsync_escape_result[i + sc_count] = '\\';
- break;
- }
- }
- return rsync_escape_result;
- }
- static inline int rsync_outline ( FILE *outf, char *outline, eventinfo_flags_t flags )
- {
- #ifdef VERYPARANOID
- critical_on ( outf == NULL );
- #endif
- // doxygen recognizes / * * as start of a doxy comment, so trick it with concatenated strings
- if ( flags & EVIF_RECURSIVELY ) {
- debug ( 3, "Recursively \"%s\": Writing to rsynclist: \"%s/*""**\".", outline, outline );
- critical_on ( fprintf ( outf, "%s/*""**\n", outline ) <= 0 );
- } else if ( flags & EVIF_CONTENTRECURSIVELY ) {
- debug ( 3, "Content-recursively \"%s\": Writing to rsynclist: \"%s/*""*\".", outline, outline );
- critical_on ( fprintf ( outf, "%s/*""*\n", outline ) <= 0 );
- } else {
- debug ( 3, "Non-recursively \"%s\": Writing to rsynclist: \"%s\".", outline, outline );
- critical_on ( fprintf ( outf, "%s\n", outline ) <= 0 );
- }
- return 0;
- }
- gboolean rsync_aggrout ( gpointer outline_gp, gpointer flags_gp, gpointer arg_gp )
- {
- struct dosync_arg *dosync_arg_p = ( struct dosync_arg * ) arg_gp;
- char *outline = ( char * ) outline_gp;
- FILE *outf = dosync_arg_p->outf;
- eventinfo_flags_t flags = ( eventinfo_flags_t ) GPOINTER_TO_INT ( flags_gp );
- // debug(3, "\"%s\"", outline);
- int ret;
- if ( ( ret = rsync_outline ( outf, outline, flags ) ) ) {
- error ( "Got error from rsync_outline(). Exit." );
- exit ( ret ); // TODO: replace this with kill(0, ...)
- }
- return TRUE;
- }
- static inline int rsync_listpush ( indexes_t *indexes_p, const char *fpath, size_t fpath_len, eventinfo_flags_t flags, unsigned int *linescount_p )
- {
- char *fpathwslash;
- if ( fpath_len > 0 ) {
- // Prepending with the slash
- fpathwslash = alloca ( fpath_len + 2 );
- fpathwslash[0] = '/';
- memcpy ( &fpathwslash[1], fpath, fpath_len + 1 );
- } else {
- // In this case slash is not required
- fpathwslash = ( char * ) fpath;
- }
- fpathwslash = ( char * ) rsync_escape ( fpathwslash );
- char *end = fpathwslash;
- debug ( 3, "\"%s\": Adding to rsynclist: \"%s\" with flags %p.",
- fpathwslash, fpathwslash, ( void * ) ( long ) flags );
- indexes_outaggr_add ( indexes_p, strdup ( fpathwslash ), flags );
- if ( linescount_p != NULL )
- ( *linescount_p )++;
- while ( end != NULL ) {
- if ( *fpathwslash == 0x00 )
- break;
- debug ( 3, "Non-recursively \"%s\": Adding to rsynclist: \"%s\".", fpathwslash, fpathwslash );
- indexes_outaggr_add ( indexes_p, strdup ( fpathwslash ), EVIF_NONE );
- if ( linescount_p != NULL )
- ( *linescount_p )++;
- end = strrchr ( fpathwslash, '/' );
- if ( end == NULL )
- break;
- if ( end - fpathwslash <= 0 )
- break;
- *end = 0x00;
- };
- return 0;
- }
- gboolean sync_idle_dosync_collectedevents_rsync_exclistpush ( gpointer fpath_gp, gpointer flags_gp, gpointer arg_gp )
- {
- struct dosync_arg *dosync_arg_p = ( struct dosync_arg * ) arg_gp;
- char *fpath = ( char * ) fpath_gp;
- FILE *excf = dosync_arg_p->outf;
- eventinfo_flags_t flags = GPOINTER_TO_INT ( flags_gp );
- // ctx_t *ctx_p = dosync_arg_p->ctx_p;
- // indexes_t *indexes_p = dosync_arg_p->indexes_p;
- debug ( 3, "\"%s\"", fpath );
- size_t fpath_len = strlen ( fpath );
- char *fpathwslash;
- if ( fpath_len > 0 ) {
- // Prepending with the slash
- fpathwslash = alloca ( fpath_len + 2 );
- fpathwslash[0] = '/';
- memcpy ( &fpathwslash[1], fpath, fpath_len + 1 );
- } else {
- // In this case slash is not required
- fpathwslash = fpath;
- }
- fpathwslash = ( char * ) rsync_escape ( fpathwslash );
- int ret;
- if ( ( ret = rsync_outline ( excf, fpathwslash, flags ) ) ) {
- error ( "Got error from rsync_outline(). Exit." );
- exit ( ret ); // TODO: replace this with kill(0, ...)
- }
- return TRUE;
- }
- int sync_idle_dosync_collectedevents_commitpart ( struct dosync_arg *dosync_arg_p )
- {
- ctx_t *ctx_p = dosync_arg_p->ctx_p;
- indexes_t *indexes_p = dosync_arg_p->indexes_p;
- debug ( 3, "Committing the file (flags[MODE] == %i)", ctx_p->flags[MODE] );
- if (
- ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSHELL ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSO )
- )
- g_hash_table_foreach_remove ( indexes_p->out_lines_aggr_ht, rsync_aggrout, dosync_arg_p );
- if ( dosync_arg_p->outf != NULL ) {
- critical_on ( fclose ( dosync_arg_p->outf ) );
- dosync_arg_p->outf = NULL;
- }
- if ( dosync_arg_p->evcount > 0 ) {
- thread_callbackfunct_arg_t *callback_arg_p;
- debug ( 3, "%s [%s] (%p) -> %s [%s]", ctx_p->watchdir, ctx_p->watchdirwslash, ctx_p->watchdirwslash,
- ctx_p->destdir ? ctx_p->destdir : "", ctx_p->destdirwslash ? ctx_p->destdirwslash : "" );
- if ( ctx_p->flags[MODE] == MODE_SO ) {
- api_eventinfo_t *ei = dosync_arg_p->api_ei;
- return so_call_sync ( ctx_p, indexes_p, dosync_arg_p->evcount, ei );
- }
- if ( ctx_p->flags[MODE] == MODE_RSYNCSO )
- return so_call_rsync (
- ctx_p,
- indexes_p,
- dosync_arg_p->outf_path,
- * ( dosync_arg_p->excf_path ) ? dosync_arg_p->excf_path : NULL );
- callback_arg_p = xcalloc ( 1, sizeof ( *callback_arg_p ) );
- if ( ctx_p->synchandler_argf & SHFL_INCLUDE_LIST_PATH )
- callback_arg_p->incfpath = strdup ( dosync_arg_p->outf_path );
- if ( ctx_p->synchandler_argf & SHFL_EXCLUDE_LIST_PATH )
- callback_arg_p->excfpath = strdup ( dosync_arg_p->excf_path );
- {
- int rc;
- dosync_arg_p->list_type_str =
- ctx_p->flags[MODE] == MODE_RSYNCDIRECT ||
- ctx_p->flags[MODE] == MODE_RSYNCSHELL
- ? "rsynclist" : "synclist";
- debug ( 9, "dosync_arg_p->include_list_count == %u", dosync_arg_p->include_list_count );
- char **argv = sync_customargv ( ctx_p, dosync_arg_p, &ctx_p->synchandler_args[SHARGS_PRIMARY] );
- while ( dosync_arg_p->include_list_count )
- free ( ( char * ) dosync_arg_p->include_list[--dosync_arg_p->include_list_count] );
- rc = SYNC_EXEC_ARGV (
- ctx_p,
- indexes_p,
- sync_idle_dosync_collectedevents_cleanup,
- callback_arg_p,
- argv );
- #ifdef THREADING_SUPPORT
- if ( !SHOULD_THREAD ( ctx_p ) ) // If it's a thread then it will free the argv in GC. If not a thread then we have to free right here.
- #endif
- argv_free ( argv );
- return rc;
- }
- }
- return 0;
- #ifdef DOXYGEN
- sync_exec_argv ( NULL, NULL );
- sync_exec_argv_thread ( NULL, NULL );
- #endif
- }
- void sync_inclist_rotate ( ctx_t *ctx_p, struct dosync_arg *dosync_arg_p )
- {
- int ret;
- char newexc_path[PATH_MAX + 1];
- if ( ctx_p->synchandler_argf & SHFL_EXCLUDE_LIST_PATH ) {
- // TODO: optimize this out {
- if ( ( ret = sync_idle_dosync_collectedevents_uniqfname ( ctx_p, newexc_path, "exclist" ) ) ) {
- error ( "Cannot get unique file name." );
- exit ( ret );
- }
- if ( ( ret = fileutils_copy ( dosync_arg_p->excf_path, newexc_path ) ) ) {
- error ( "Cannot copy file \"%s\" to \"%s\".", dosync_arg_p->excf_path, newexc_path );
- exit ( ret );
- }
- // }
- // That's required to copy excludes' list file for every rsync execution.
- // The problem appears do to unlink()-ing the excludes' list file on callback function
- // "sync_idle_dosync_collectedevents_cleanup()" of every execution.
- }
- if ( ( ret = sync_idle_dosync_collectedevents_commitpart ( dosync_arg_p ) ) ) {
- error ( "Cannot commit list-file \"%s\"", dosync_arg_p->outf_path );
- exit ( ret ); // TODO: replace with kill(0, ...);
- }
- if ( ctx_p->synchandler_argf & SHFL_INCLUDE_LIST_PATH ) {
- #ifdef VERYPARANOID
- require_strlen_le ( newexc_path, PATH_MAX );
- #endif
- strcpy ( dosync_arg_p->excf_path, newexc_path ); // TODO: optimize this out
- if ( ( ret = sync_idle_dosync_collectedevents_listcreate ( dosync_arg_p, "list" ) ) ) {
- error ( "Cannot create new list-file" );
- exit ( ret ); // TODO: replace with kill(0, ...);
- }
- }
- return;
- }
- void sync_idle_dosync_collectedevents_listpush ( gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp )
- {
- struct dosync_arg *dosync_arg_p = ( struct dosync_arg * ) arg_gp;
- char *fpath = ( char * ) fpath_gp;
- eventinfo_t *evinfo = ( eventinfo_t * ) evinfo_gp;
- //int *evcount_p =&dosync_arg_p->evcount;
- FILE *outf = dosync_arg_p->outf;
- ctx_t *ctx_p = dosync_arg_p->ctx_p;
- unsigned int *linescount_p = &dosync_arg_p->linescount;
- indexes_t *indexes_p = dosync_arg_p->indexes_p;
- api_eventinfo_t **api_ei_p = &dosync_arg_p->api_ei;
- int *api_ei_count_p = &dosync_arg_p->api_ei_count;
- debug ( 3, "\"%s\" with int-flags %p. "
- "evinfo: seqid_min == %u, seqid_max == %u type_o == %i, type_n == %i",
- fpath, ( void * ) ( unsigned long ) evinfo->flags,
- evinfo->seqid_min, evinfo->seqid_max,
- evinfo->objtype_old, evinfo->objtype_new
- );
- // so-module case:
- if ( ctx_p->flags[MODE] == MODE_SO ) {
- api_eventinfo_t *ei = & ( *api_ei_p ) [ ( *api_ei_count_p )++];
- ei->evmask = evinfo->evmask;
- ei->flags = evinfo->flags;
- ei->objtype_old = evinfo->objtype_old;
- ei->objtype_new = evinfo->objtype_new;
- ei->path_len = strlen ( fpath );
- ei->path = strdup ( fpath );
- return;
- }
- if ( ctx_p->synchandler_argf & SHFL_INCLUDE_LIST ) {
- dosync_arg_p->include_list[dosync_arg_p->include_list_count++] = strdup ( fpath );
- if (
- dosync_arg_p->include_list_count >= ( size_t )
- ( MAXARGUMENTS -
- MAX (
- ctx_p->synchandler_args[SHARGS_PRIMARY].c,
- ctx_p->synchandler_args[SHARGS_INITIAL].c
- )
- )
- )
- sync_inclist_rotate ( ctx_p, dosync_arg_p );
- }
- // Finish if we don't use list files
- if ( ! ( ctx_p->synchandler_argf &
- ( SHFL_INCLUDE_LIST_PATH | SHFL_EXCLUDE_LIST_PATH ) ) )
- return;
- // List files cases:
- // non-RSYNC case
- if ( ! (
- ( ctx_p->flags[MODE] == MODE_RSYNCSHELL ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSO )
- ) ) {
- if ( ctx_p->flags[SYNCLISTSIMPLIFY] ) {
- critical_on ( fprintf ( outf, "%s\n", fpath ) <= 0 );
- } else {
- critical_on ( fprintf ( outf, "sync %s %i %s\n", ctx_p->label, evinfo->evmask, fpath ) <= 0 );
- }
- return;
- }
- // RSYNC case
- if ( ctx_p->rsyncinclimit && ( *linescount_p >= ctx_p->rsyncinclimit ) )
- sync_inclist_rotate ( ctx_p, dosync_arg_p );
- int ret;
- if ( ( ret = rsync_listpush ( indexes_p, fpath, strlen ( fpath ), evinfo->flags, linescount_p ) ) ) {
- error ( "Got error from rsync_listpush(). Exit." );
- exit ( ret );
- }
- return;
- }
- int sync_idle_dosync_collectedevents ( ctx_t *ctx_p, indexes_t *indexes_p )
- {
- debug ( 3, "" );
- struct dosync_arg dosync_arg = {0};
- dosync_arg.ctx_p = ctx_p;
- dosync_arg.indexes_p = indexes_p;
- char isrsyncpreferexclude =
- (
- ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSHELL ) ||
- ( ctx_p->flags[MODE] == MODE_RSYNCSO )
- ) && ( !ctx_p->flags[RSYNCPREFERINCLUDE] );
- #ifdef PARANOID
- if ( ctx_p->listoutdir != NULL ) {
- g_hash_table_remove_all ( indexes_p->fpath2ei_ht );
- if ( isrsyncpreferexclude )
- g_hash_table_remove_all ( indexes_p->exc_fpath_ht );
- }
- #endif
- // Setting the time to sync not before it:
- ctx_p->synctime = time ( NULL ) + ctx_p->syncdelay;
- debug ( 3, "Next sync will be not before: %u", ctx_p->synctime );
- int queue_id = 0;
- while ( queue_id < QUEUE_MAX ) {
- int ret;
- if ( ( queue_id == QUEUE_LOCKWAIT ) && ( ctx_p->flags[THREADING] != PM_SAFE ) ) {
- queue_id++;
- continue;
- }
- queue_id_t *queue_id_p = ( queue_id_t * ) &dosync_arg.data;
- *queue_id_p = queue_id;
- ret = sync_idle_dosync_collectedevents_aggrqueue ( queue_id, ctx_p, indexes_p, &dosync_arg );
- if ( ret ) {
- error ( "Got error while processing queue #%i\n.", queue_id );
- g_hash_table_remove_all ( indexes_p->fpath2ei_ht );
- if ( isrsyncpreferexclude )
- g_hash_table_remove_all ( indexes_p->exc_fpath_ht );
- return ret;
- }
- queue_id++;
- }
- if ( !dosync_arg.evcount ) {
- debug ( 3, "Summary events' count is zero. Return 0." );
- return 0;
- }
- if ( ctx_p->flags[MODE] == MODE_SO ) {
- //dosync_arg.evcount = g_hash_table_size(indexes_p->fpath2ei_ht);
- debug ( 3, "There's %i events. Processing.", dosync_arg.evcount );
- dosync_arg.api_ei = ( api_eventinfo_t * ) xmalloc ( dosync_arg.evcount * sizeof ( *dosync_arg.api_ei ) );
- }
- {
- int ret;
- if ( ( ctx_p->listoutdir != NULL ) || ( ctx_p->flags[MODE] == MODE_SO ) ) {
- if ( ! ( ctx_p->flags[MODE] == MODE_SO ) ) {
- * ( dosync_arg.excf_path ) = 0x00;
- if ( isrsyncpreferexclude ) {
- if ( ( ret = sync_idle_dosync_collectedevents_listcreate ( &dosync_arg, "exclist" ) ) ) {
- error ( "Cannot create list-file" );
- return ret;
- }
- #ifdef PARANOID
- g_hash_table_remove_all ( indexes_p->out_lines_aggr_ht );
- #endif
- g_hash_table_foreach_remove ( indexes_p->exc_fpath_ht, sync_idle_dosync_collectedevents_rsync_exclistpush, &dosync_arg );
- g_hash_table_foreach_remove ( indexes_p->out_lines_aggr_ht, rsync_aggrout, &dosync_arg );
- critical_on ( fclose ( dosync_arg.outf ) );
- #ifdef VERYPARANOID
- require_strlen_le ( dosync_arg.outf_path, PATH_MAX );
- #endif
- strcpy ( dosync_arg.excf_path, dosync_arg.outf_path ); // TODO: remove this strcpy()
- }
- if ( ( ret = sync_idle_dosync_collectedevents_listcreate ( &dosync_arg, "list" ) ) ) {
- error ( "Cannot create list-file" );
- return ret;
- }
- }
- }
- if ( ( ctx_p->listoutdir != NULL ) || ( ctx_p->flags[MODE] == MODE_SO ) || ( ctx_p->synchandler_argf & SHFL_INCLUDE_LIST ) ) {
- #ifdef PARANOID
- g_hash_table_remove_all ( indexes_p->out_lines_aggr_ht );
- #endif
- g_hash_table_foreach ( indexes_p->fpath2ei_ht, sync_idle_dosync_collectedevents_listpush, &dosync_arg );
- if ( ( ret = sync_idle_dosync_collectedevents_commitpart ( &dosync_arg ) ) ) {
- error ( "Cannot submit to sync the list \"%s\"", dosync_arg.outf_path );
- // TODO: free dosync_arg.api_ei on case of error
- g_hash_table_remove_all ( indexes_p->fpath2ei_ht );
- return ret;
- }
- g_hash_table_remove_all ( indexes_p->fpath2ei_ht );
- }
- }
- finish_iteration ( ctx_p );
- return 0;
- }
- int apievinfo2rsynclist ( indexes_t *indexes_p, FILE *listfile, int n, api_eventinfo_t *apievinfo )
- {
- int i;
- if ( listfile == NULL ) {
- error ( "listfile == NULL." );
- return EINVAL;
- }
- i = 0;
- while ( i < n ) {
- rsync_listpush ( indexes_p, apievinfo[i].path, apievinfo[i].path_len, apievinfo[i].flags, NULL );
- i++;
- }
- struct dosync_arg dosync_arg = {0};
- dosync_arg.outf = listfile;
- g_hash_table_foreach_remove ( indexes_p->out_lines_aggr_ht, rsync_aggrout, &dosync_arg );
- return 0;
- }
- int sync_idle ( ctx_t *ctx_p, indexes_t *indexes_p )
- {
- int ret;
- // Collecting garbage
- #ifdef THREADING_SUPPORT
- ret = thread_gc ( ctx_p );
- if ( ret ) return ret;
- #endif
- // Checking if we can sync
- if ( ctx_p->flags[STANDBYFILE] ) {
- struct stat st;
- if ( !stat ( ctx_p->standbyfile, &st ) ) {
- state_t state_old;
- state_old = ctx_p->state;
- ctx_p->state = STATE_HOLDON;
- main_status_update ( ctx_p );
- debug ( 1, "Found standby file. Holding over syncs. Sleeping "XTOSTR ( SLEEP_SECONDS ) " second." );
- sleep ( SLEEP_SECONDS );
- ctx_p->state = state_old;
- main_status_update ( ctx_p );
- return 0;
- }
- }
- // Syncing
- debug ( 3, "calling sync_idle_dosync_collectedevents()" );
- #ifdef CLUSTER_SUPPORT
- ret = cluster_lock_byindexes();
- if ( ret ) return ret;
- #endif
- ret = sync_idle_dosync_collectedevents ( ctx_p, indexes_p );
- if ( ret ) return ret;
- #ifdef CLUSTER_SUPPORT
- ret = cluster_unlock_all();
- if ( ret ) return ret;
- #endif
- return 0;
- }
- int notify_wait ( ctx_t *ctx_p, indexes_t *indexes_p )
- {
- static struct timeval tv;
- time_t tm = time ( NULL );
- long delay = ( ( unsigned long ) ~0 >> 1 );
- threadsinfo_t *threadsinfo_p = thread_info();
- debug ( 4, "pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE])" );
- pthread_cond_broadcast ( &threadsinfo_p->cond[PTHREAD_MUTEX_STATE] );
- pthread_mutex_unlock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- long queue_id = 0;
- while ( queue_id < QUEUE_MAX ) {
- queueinfo_t *queueinfo = &ctx_p->_queues[queue_id++];
- if ( !queueinfo->stime )
- continue;
- if ( queueinfo->collectdelay == COLLECTDELAY_INSTANT ) {
- debug ( 3, "There're events in instant queue (#%i), don't waiting.", queue_id - 1 );
- return 0;
- }
- int qdelay = queueinfo->stime + queueinfo->collectdelay - tm;
- debug ( 3, "queue #%i: %i %i %i -> %i", queue_id - 1, queueinfo->stime, queueinfo->collectdelay, tm, qdelay );
- if ( qdelay < - ( long ) ctx_p->syncdelay )
- qdelay = - ( long ) ctx_p->syncdelay;
- delay = MIN ( delay, qdelay );
- }
- long synctime_delay = ( ( long ) ctx_p->synctime ) - ( ( long ) tm );
- synctime_delay = synctime_delay > 0 ? synctime_delay : 0;
- debug ( 3, "delay = MAX(%li, %li)", delay, synctime_delay );
- delay = MAX ( delay, synctime_delay );
- delay = delay > 0 ? delay : 0;
- #ifdef THREADING_SUPPORT
- if ( ctx_p->flags[THREADING] ) {
- time_t _thread_nextexpiretime = thread_nextexpiretime();
- debug ( 3, "thread_nextexpiretime == %i", _thread_nextexpiretime );
- if ( _thread_nextexpiretime ) {
- long thread_expiredelay = ( long ) thread_nextexpiretime() - ( long ) tm + 1; // +1 is to make "tm>threadinfo_p->expiretime" after select() definitely TRUE
- debug ( 3, "thread_expiredelay == %i", thread_expiredelay );
- thread_expiredelay = thread_expiredelay > 0 ? thread_expiredelay : 0;
- debug ( 3, "delay = MIN(%li, %li)", delay, thread_expiredelay );
- delay = MIN ( delay, thread_expiredelay );
- }
- }
- #endif
- if ( ( !delay ) || ( ctx_p->state != STATE_RUNNING && ctx_p->state != STATE_LASTSYNC ) ) {
- debug ( 4, "forcing: no events (delay is %li, state is %s)",
- delay, status_descr[ctx_p->state] )
- return 0;
- }
- if ( ctx_p->flags[EXITONNOEVENTS] || ctx_p->state == STATE_LASTSYNC ) {
- // zero delay if "--exit-on-no-events" is set or if it is the last sync (see "--sync-on-quit")
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- } else {
- debug ( 3, "sleeping for %li second(s).", SLEEP_SECONDS );
- sleep ( SLEEP_SECONDS );
- delay = ( ( long ) delay ) > SLEEP_SECONDS ? delay - SLEEP_SECONDS : 0;
- tv.tv_sec = delay;
- tv.tv_usec = 0;
- }
- debug ( 4, "pthread_mutex_lock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE])" );
- pthread_mutex_lock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- if ( ctx_p->state != STATE_RUNNING && ctx_p->state != STATE_LASTSYNC )
- return 0;
- debug ( 4, "pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE])" );
- pthread_cond_broadcast ( &threadsinfo_p->cond[PTHREAD_MUTEX_STATE] );
- pthread_mutex_lock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_SELECT] );
- pthread_mutex_unlock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- debug ( 8, "ctx_p->notifyenginefunct.wait() [%p]", ctx_p->notifyenginefunct.wait );
- int ret = ctx_p->notifyenginefunct.wait ( ctx_p, indexes_p, &tv );
- pthread_mutex_unlock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_SELECT] );
- if ( ( ret == -1 ) && ( errno == EINTR ) ) {
- errno = 0;
- ret = 0;
- }
- debug ( 4, "pthread_mutex_lock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE])" );
- pthread_mutex_lock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- if ( ( ctx_p->flags[EXITONNOEVENTS] ) && ( ret == 0 ) && ( ctx_p->state != STATE_LASTSYNC ) && ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) ) {
- // if not events and "--exit-on-no-events" is set
- if ( ctx_p->flags[PREEXITHOOK] || ctx_p->flags[SOFTEXITSYNC] )
- ctx_p->state = STATE_PREEXIT;
- else
- ctx_p->state = STATE_EXIT;
- }
- return ret;
- }
- #define SYNC_LOOP_IDLE {\
- int ret;\
- if((ret=sync_idle(ctx_p, indexes_p))) {\
- error("got error while sync_idle().");\
- return ret;\
- }\
- }
- #define SYNC_LOOP_CONTINUE_UNLOCK {\
- pthread_cond_broadcast(&threadsinfo_p->cond[PTHREAD_MUTEX_STATE]);\
- debug(4, "pthread_mutex_unlock()");\
- pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);\
- continue;\
- }
- void hook_preexit ( ctx_t *ctx_p )
- {
- debug ( 2, "\"%s\" \"%s\"", ctx_p->preexithookfile, ctx_p->label );
- #ifdef VERYPARANOID
- if ( ctx_p->preexithookfile == NULL )
- critical ( "ctx_p->preexithookfile == NULL" );
- #endif
- char *argv[] = { ctx_p->preexithookfile, ctx_p->label, NULL};
- exec_argv ( argv, NULL );
- return;
- }
- int sync_loop ( ctx_t *ctx_p, indexes_t *indexes_p )
- {
- int ret;
- threadsinfo_t *threadsinfo_p = thread_info();
- state_p = &ctx_p->state;
- ctx_p->state = ctx_p->flags[SKIPINITSYNC] ? STATE_RUNNING : STATE_INITSYNC;
- while ( ctx_p->state != STATE_EXIT ) {
- int events;
- debug ( 4, "pthread_mutex_lock(): PTHREAD_MUTEX_STATE" );
- pthread_mutex_lock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- debug ( 3, "current state is \"%s\" (%i) (iteration: %u/%u); threadsinfo_p->used == %u",
- status_descr[ctx_p->state], ctx_p->state,
- ctx_p->iteration_num, ctx_p->flags[MAXITERATIONS], threadsinfo_p->used );
- while ( ( ctx_p->flags[THREADING] == PM_OFF ) && threadsinfo_p->used ) {
- debug ( 1, "We are in non-threading mode but have %u syncer threads. Waiting for them end.", threadsinfo_p->used );
- pthread_cond_wait ( &threadsinfo_p->cond[PTHREAD_MUTEX_STATE], &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- pthread_mutex_unlock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- }
- events = 0;
- switch ( ctx_p->state ) {
- case STATE_THREAD_GC:
- main_status_update ( ctx_p );
- #ifdef THREADING_SUPPORT
- if ( thread_gc ( ctx_p ) ) {
- ctx_p->state = STATE_EXIT;
- break;
- }
- #endif
- ctx_p->state = STATE_RUNNING;
- SYNC_LOOP_CONTINUE_UNLOCK;
- case STATE_INITSYNC:
- if ( !ctx_p->flags[THREADING] ) {
- ctx_p->iteration_num = 0;
- setenv_iteration ( ctx_p->iteration_num );
- }
- main_status_update ( ctx_p );
- pthread_cond_broadcast ( &threadsinfo_p->cond[PTHREAD_MUTEX_STATE] );
- pthread_mutex_unlock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- ret = sync_initialsync ( ctx_p->watchdir, ctx_p, indexes_p, INITSYNC_FULL );
- if ( ret ) return ret;
- if ( ( ctx_p->state == STATE_TERM ) || ( ctx_p->state == STATE_EXIT ) ) {
- continue;
- }
- if ( ctx_p->flags[ONLYINITSYNC] ) {
- SYNC_LOOP_IDLE;
- ctx_p->state = STATE_EXIT;
- return ret;
- }
- ctx_p->state = STATE_RUNNING;
- continue;
- case STATE_RUNNING:
- if ( ( !ctx_p->flags[THREADING] ) && ctx_p->flags[MAXITERATIONS] ) {
- if ( ( typeof ( ctx_p->iteration_num ) ) ctx_p->flags[MAXITERATIONS] == ctx_p->iteration_num - 1 )
- ctx_p->state = STATE_PREEXIT;
- else if ( ( typeof ( ctx_p->iteration_num ) ) ctx_p->flags[MAXITERATIONS] <= ctx_p->iteration_num )
- ctx_p->state = STATE_EXIT;
- }
- case STATE_PREEXIT:
- if ( ctx_p->state == STATE_PREEXIT && ctx_p->flags[PREEXITHOOK] == 0 && ctx_p->flags[SOFTEXITSYNC] == 0 ) {
- ctx_p->state = STATE_TERM;
- SYNC_LOOP_IDLE;
- }
- case STATE_LASTSYNC:
- switch ( ctx_p->state ) {
- case STATE_PREEXIT:
- debug ( 1, "preparing to exit" );
- main_status_update ( ctx_p );
- if ( ctx_p->flags[PREEXITHOOK] )
- hook_preexit ( ctx_p );
- if ( ctx_p->flags[SOFTEXITSYNC] ) {
- ctx_p->state = STATE_LASTSYNC;
- } else {
- ctx_p->state = STATE_TERM;
- }
- break;
- case STATE_LASTSYNC:
- debug ( 3, "notify_wait ( ctx_p, indexes_p ) [lastsync]" );
- events = notify_wait ( ctx_p, indexes_p );
- ctx_p->state = STATE_TERM;
- break;
- case STATE_RUNNING:
- debug ( 3, "notify_wait ( ctx_p, indexes_p )" );
- events = notify_wait ( ctx_p, indexes_p );
- break;
- default:
- SYNC_LOOP_CONTINUE_UNLOCK;
- }
- break;
- case STATE_REHASH:
- main_status_update ( ctx_p );
- debug ( 1, "rehashing." );
- main_rehash ( ctx_p );
- ctx_p->state = STATE_RUNNING;
- SYNC_LOOP_CONTINUE_UNLOCK;
- case STATE_TERM:
- main_status_update ( ctx_p );
- ctx_p->state = STATE_EXIT;
- case STATE_EXIT:
- main_status_update ( ctx_p );
- SYNC_LOOP_CONTINUE_UNLOCK;
- default:
- critical ( "internal error: ctx_p->state == %u", ctx_p->state );
- break;
- }
- pthread_cond_broadcast ( &threadsinfo_p->cond[PTHREAD_MUTEX_STATE] );
- debug ( 4, "pthread_mutex_unlock(): PTHREAD_MUTEX_STATE" );
- pthread_mutex_unlock ( &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE] );
- if ( events == 0 ) {
- debug ( 2, "events == 0" );
- SYNC_LOOP_IDLE;
- continue; // Timeout
- }
- if ( events < 0 ) {
- error ( "Got error while waiting for event from notify subsystem." );
- return errno;
- }
- debug ( 3, "ctx_p->notifyenginefunct.handle" );
- int count = ctx_p->notifyenginefunct.handle ( ctx_p, indexes_p );
- if ( count <= 0 ) {
- error ( "Cannot handle with notify events." );
- return errno;
- }
- main_status_update ( ctx_p );
- if ( ctx_p->flags[EXITONNOEVENTS] ) // clsync exits on no events, so sync_idle() is never called. We have to force the calling of it.
- SYNC_LOOP_IDLE;
- }
- debug ( 1, "last SYNC_LOOP_IDLE" );
- SYNC_LOOP_IDLE;
- debug ( 1, "end" );
- return exitcode;
- #ifdef DOXYGEN
- sync_idle ( 0, NULL, NULL );
- #endif
- }
- void sync_sig_int ( int signal )
- {
- debug ( 2, "%i: Thread %p", signal, pthread_self() );
- return;
- }
- #ifdef PARANOID
- int _sync_tryforcecycle_i;
- #endif
- int sync_tryforcecycle ( ctx_t *ctx_p, pthread_t pthread_parent )
- {
- ( void ) pthread_parent;
- debug ( 3, "sending signal to interrupt blocking operations like select()-s and so on (ctx_p->blockthread_count == %i)", ctx_p->blockthread_count );
- //pthread_kill(pthread_parent, SIGUSR_BLOPINT);
- int i, count;
- count = ctx_p->blockthread_count;
- i = 0;
- while ( i < count ) {
- debug ( 2, "Sending SIGUSR_BLOPINT to thread %p", ctx_p->blockthread[i] );
- pthread_kill ( ctx_p->blockthread[i], SIGUSR_BLOPINT );
- i++;
- }
- #ifdef PARANOID
- if ( ++_sync_tryforcecycle_i > KILL_TIMEOUT ) {
- error ( "Seems we got a deadlock." );
- return EDEADLK;
- }
- #endif
- #ifdef SYNC_SWITCHSTATE_COND_TIMEDWAIT // Hangs
- struct timespec time_timeout;
- clock_gettime ( CLOCK_REALTIME, &time_timeout );
- time_timeout.tv_sec++;
- // time_timeout.tv_sec = now.tv_sec;
- debug ( 3, "pthread_cond_timedwait() until %li.%li", time_timeout.tv_sec, time_timeout.tv_nsec );
- if ( pthread_cond_timedwait ( pthread_cond_state, pthread_mutex_state, &time_timeout ) != ETIMEDOUT )
- return 0;
- #else
- debug ( 9, "sleep("XTOSTR ( SLEEP_SECONDS ) ")" );
- sleep ( SLEEP_SECONDS ); // TODO: replace this with pthread_cond_timedwait()
- #endif
- return EINPROGRESS;
- }
- int sync_switch_state ( ctx_t *ctx_p, pthread_t pthread_parent, int newstate )
- {
- if ( state_p == NULL ) {
- debug ( 3, "sync_switch_state(ctx_p, %p, %i), but state_p == NULL", pthread_parent, newstate );
- return 0;
- }
- debug ( 3, "sync_switch_state(ctx_p, %p, %i)", pthread_parent, newstate );
- // Getting mutexes
- threadsinfo_t *threadsinfo_p = thread_info();
- if ( threadsinfo_p == NULL ) {
- // If no mutexes, just change the state
- goto l_sync_parent_interrupt_end;
- }
- if ( !threadsinfo_p->mutex_init ) {
- // If no mutexes, just change the state
- goto l_sync_parent_interrupt_end;
- }
- pthread_mutex_t *pthread_mutex_state = &threadsinfo_p->mutex[PTHREAD_MUTEX_STATE];
- pthread_mutex_t *pthread_mutex_select = &threadsinfo_p->mutex[PTHREAD_MUTEX_SELECT];
- pthread_cond_t *pthread_cond_state = &threadsinfo_p->cond [PTHREAD_MUTEX_STATE];
- // Locking all necessary mutexes
- #ifdef PARANOID
- _sync_tryforcecycle_i = 0;
- #endif
- debug ( 4, "while(pthread_mutex_trylock( pthread_mutex_state ))" );
- while ( pthread_mutex_trylock ( pthread_mutex_state ) == EBUSY ) {
- int rc = sync_tryforcecycle ( ctx_p, pthread_parent );
- if ( rc && rc != EINPROGRESS )
- return rc;
- if ( !rc )
- break;
- }
- #ifdef PARANOID
- _sync_tryforcecycle_i = 0;
- #endif
- debug ( 4, "while(pthread_mutex_trylock( pthread_mutex_select ))" );
- while ( pthread_mutex_trylock ( pthread_mutex_select ) == EBUSY ) {
- int rc = sync_tryforcecycle ( ctx_p, pthread_parent );
- if ( rc && rc != EINPROGRESS )
- return rc;
- if ( !rc )
- break;
- }
- // Changing the state
- *state_p = newstate;
- #ifdef PARANOID
- pthread_kill ( pthread_parent, SIGUSR_BLOPINT );
- #endif
- // Unlocking mutexes
- debug ( 4, "pthread_cond_broadcast(). New state is %i.", *state_p );
- pthread_cond_broadcast ( pthread_cond_state );
- debug ( 4, "pthread_mutex_unlock( pthread_mutex_state )" );
- pthread_mutex_unlock ( pthread_mutex_state );
- debug ( 4, "pthread_mutex_unlock( pthread_mutex_select )" );
- pthread_mutex_unlock ( pthread_mutex_select );
- #ifdef THREADING_SUPPORT
- return thread_info_unlock ( 0 );
- #else
- return 0;
- #endif
- l_sync_parent_interrupt_end:
- *state_p = newstate;
- pthread_kill ( pthread_parent, SIGUSR_BLOPINT );
- #ifdef THREADING_SUPPORT
- return thread_info_unlock ( 0 );
- #else
- return 0;
- #endif
- }
- /* === DUMP === */
- enum dump_dirfd_obj {
- DUMP_DIRFD_ROOT = 0,
- DUMP_DIRFD_QUEUE,
- DUMP_DIRFD_THREAD,
- DUMP_DIRFD_MAX
- };
- enum dump_ltype {
- DUMP_LTYPE_INCLUDE,
- DUMP_LTYPE_EXCLUDE,
- DUMP_LTYPE_EVINFO,
- };
- struct sync_dump_arg {
- ctx_t *ctx_p;
- int dirfd[DUMP_DIRFD_MAX];
- int fd_out;
- int data;
- };
- void sync_dump_liststep ( gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp )
- {
- char *fpath = ( char * ) fpath_gp;
- eventinfo_t *evinfo = ( eventinfo_t * ) evinfo_gp;
- struct sync_dump_arg *arg = arg_gp;
- char act, num;
- if ( fpath == NULL || evinfo == NULL )
- return;
- switch ( arg->data ) {
- case DUMP_LTYPE_INCLUDE:
- act = '+';
- num = '1';
- break;
- case DUMP_LTYPE_EXCLUDE:
- act = '-';
- num = '1';
- break;
- case DUMP_LTYPE_EVINFO:
- act = '+';
- num = evinfo->flags & EVIF_RECURSIVELY ? '*' :
- ( evinfo->flags & EVIF_CONTENTRECURSIVELY ? '/' : '1' );
- break;
- default:
- act = '?';
- num = '?';
- }
- dprintf ( arg->fd_out, "%c%c\t%s\n", act, num, fpath );
- return;
- }
- int sync_dump_thread ( threadinfo_t *threadinfo_p, void *_arg )
- {
- struct sync_dump_arg *arg = _arg;
- char buf[BUFSIZ];
- snprintf ( buf, BUFSIZ, "%u-%u-%lx", threadinfo_p->iteration, threadinfo_p->thread_num, ( long ) threadinfo_p->pthread );
- arg->fd_out = openat ( arg->dirfd[DUMP_DIRFD_THREAD], buf, O_WRONLY | O_CREAT, DUMP_FILEMODE );
- if ( arg->fd_out == -1 )
- return errno;
- {
- char **argv;
- dprintf ( arg->fd_out,
- "thread:\n\titeration == %u\n\tnum == %u\n\tpthread == %lx\n\tstarttime == %lu\n\texpiretime == %lu\n\tchild_pid == %u\n\ttry_n == %u\nCommand:",
- threadinfo_p->iteration,
- threadinfo_p->thread_num,
- ( long ) threadinfo_p->pthread,
- threadinfo_p->starttime,
- threadinfo_p->expiretime,
- threadinfo_p->child_pid,
- threadinfo_p->try_n
- );
- argv = threadinfo_p->argv;
- while ( *argv != NULL )
- dprintf ( arg->fd_out, " \"%s\"", * ( argv++ ) );
- dprintf ( arg->fd_out, "\n" );
- }
- arg->data = DUMP_LTYPE_EVINFO;
- g_hash_table_foreach ( threadinfo_p->fpath2ei_ht, sync_dump_liststep, arg );
- close ( arg->fd_out );
- return 0;
- }
- int sync_dump ( ctx_t *ctx_p, const char *const dir_path )
- {
- indexes_t *indexes_p = ctx_p->indexes_p;
- int rootfd, fd_out;
- struct sync_dump_arg arg = {0};
- enum dump_dirfd_obj dirfd_obj;
- arg.ctx_p = ctx_p;
- debug ( 3, "%s", dir_path );
- if ( dir_path == NULL )
- return EINVAL;
- static const char *const subdirs[] = {
- [DUMP_DIRFD_QUEUE] = "queue",
- [DUMP_DIRFD_THREAD] = "threads"
- };
- errno = 0;
- rootfd = mkdirat_open ( dir_path, AT_FDCWD, DUMP_DIRMODE );
- if ( rootfd == -1 ) {
- error ( "Cannot open directory \"%s\"", dir_path );
- goto l_sync_dump_end;
- }
- fd_out = openat ( rootfd, "instance", O_WRONLY | O_CREAT, DUMP_FILEMODE );
- if ( fd_out == -1 ) {
- error ( "Cannot open file \"%s\" for writing" );
- goto l_sync_dump_end;
- }
- dprintf ( fd_out, "status == %s\n", getenv ( "CLSYNC_STATUS" ) ); // TODO: remove getenv() from here
- arg.fd_out = fd_out;
- arg.data = DUMP_LTYPE_EVINFO;
- if ( indexes_p->nonthreaded_syncing_fpath2ei_ht != NULL )
- g_hash_table_foreach ( indexes_p->nonthreaded_syncing_fpath2ei_ht, sync_dump_liststep, &arg );
- close ( fd_out );
- arg.dirfd[DUMP_DIRFD_ROOT] = rootfd;
- dirfd_obj = DUMP_DIRFD_ROOT + 1;
- while ( dirfd_obj < DUMP_DIRFD_MAX ) {
- const char *const subdir = subdirs[dirfd_obj];
- arg.dirfd[dirfd_obj] = mkdirat_open ( subdir, rootfd, DUMP_DIRMODE );
- if ( arg.dirfd[dirfd_obj] == -1 ) {
- error ( "Cannot open directory \"%s\"", subdir );
- goto l_sync_dump_end;
- }
- dirfd_obj++;
- }
- int queue_id = 0;
- while ( queue_id < QUEUE_MAX ) {
- char buf[BUFSIZ];
- snprintf ( buf, BUFSIZ, "%u", queue_id );
- arg.fd_out = openat ( arg.dirfd[DUMP_DIRFD_QUEUE], buf, O_WRONLY | O_CREAT, DUMP_FILEMODE );
- arg.data = DUMP_LTYPE_EVINFO;
- g_hash_table_foreach ( indexes_p->fpath2ei_coll_ht[queue_id], sync_dump_liststep, &arg );
- if ( indexes_p->exc_fpath_coll_ht[queue_id] != NULL ) {
- arg.data = DUMP_LTYPE_EXCLUDE;
- g_hash_table_foreach ( indexes_p->exc_fpath_coll_ht[queue_id], sync_dump_liststep, &arg );
- }
- close ( arg.fd_out );
- queue_id++;
- }
- #ifdef THREADING_SUPPORT
- threads_foreach ( sync_dump_thread, STATE_RUNNING, &arg );
- #endif
- l_sync_dump_end:
- dirfd_obj = DUMP_DIRFD_ROOT;
- while ( dirfd_obj < DUMP_DIRFD_MAX ) {
- if ( arg.dirfd[dirfd_obj] != -1 && arg.dirfd[dirfd_obj] != 0 )
- close ( arg.dirfd[dirfd_obj] );
- dirfd_obj++;
- }
- if ( errno )
- error ( "Cannot create the dump to \"%s\"", dir_path );
- return errno;
- }
- /* === /DUMP === */
- void sync_sigchld()
- {
- debug ( 9, "" );
- privileged_check();
- return;
- }
- int *sync_sighandler_exitcode_p = NULL;
- int sync_sighandler ( sighandler_arg_t *sighandler_arg_p )
- {
- int signal = 0, ret;
- sigset_t sigset_full;
- ctx_t *ctx_p = sighandler_arg_p->ctx_p;
- // indexes_t *indexes_p = sighandler_arg_p->indexes_p;
- pthread_t pthread_parent = sighandler_arg_p->pthread_parent;
- // sigset_t *sigset_p = sighandler_arg_p->sigset_p;
- int *exitcode_p = sighandler_arg_p->exitcode_p;
- sync_sighandler_exitcode_p = exitcode_p;
- sethandler_sigchld ( sync_sigchld );
- sigfillset ( &sigset_full );
- while ( state_p == NULL || ( ( ctx_p->state != STATE_TERM ) && ( ctx_p->state != STATE_EXIT ) ) ) {
- debug ( 3, "waiting for signal (is sigset filled == %i)", sigismember ( &sigset_full, SIGTERM ) );
- ret = sigwait ( &sigset_full, &signal );
- if ( state_p == NULL ) {
- switch ( signal ) {
- case SIGALRM:
- *exitcode_p = ETIME;
- case SIGQUIT:
- case SIGTERM:
- case SIGINT:
- case SIGCHLD:
- // TODO: remove the exit() from here. Main thread should exit itself
- exit ( *exitcode_p );
- break;
- default:
- warning ( "Got signal %i, but the main loop is not started, yet. Ignoring the signal.", signal );
- break;
- }
- continue;
- }
- debug ( 3, "got signal %i. ctx_p->state == %i.", signal, ctx_p->state );
- if ( ret ) {
- // TODO: handle an error here
- }
- if ( ctx_p->customsignal[signal] != NULL ) {
- if ( config_block_parse ( ctx_p, ctx_p->customsignal[signal] ) ) {
- *exitcode_p = errno;
- signal = SIGTERM;
- }
- continue;
- }
- switch ( signal ) {
- case SIGALRM:
- *exitcode_p = ETIME;
- case SIGQUIT:
- sync_switch_state ( ctx_p, pthread_parent, STATE_PREEXIT );
- break;
- case SIGTERM:
- case SIGINT:
- sync_switch_state ( ctx_p, pthread_parent, STATE_TERM );
- // bugfix of https://github.com/clsync/clsync/issues/44
- while ( ctx_p->children ) { // Killing children if non-pthread mode or/and (mode=="so" or mode=="rsyncso")
- pid_t child_pid = ctx_p->child_pid[--ctx_p->children];
- if ( privileged_kill_child ( child_pid, signal, 0 ) == ENOENT )
- continue;
- if ( signal != SIGQUIT )
- if ( privileged_kill_child ( child_pid, SIGQUIT, 0 ) == ENOENT )
- continue;
- if ( signal != SIGTERM )
- if ( privileged_kill_child ( child_pid, SIGTERM, 0 ) == ENOENT )
- continue;
- if ( privileged_kill_child ( child_pid, SIGKILL, 0 ) == ENOENT )
- continue;
- }
- break;
- case SIGHUP:
- sync_switch_state ( ctx_p, pthread_parent, STATE_REHASH );
- break;
- case SIGCHLD:
- sync_sigchld();
- break;
- case SIGUSR_THREAD_GC:
- sync_switch_state ( ctx_p, pthread_parent, STATE_THREAD_GC );
- break;
- case SIGUSR_INITSYNC:
- sync_switch_state ( ctx_p, pthread_parent, STATE_INITSYNC );
- break;
- case SIGUSR_DUMP:
- sync_dump ( ctx_p, ctx_p->dump_path );
- break;
- default:
- error ( "Unknown signal: %i. Exit.", signal );
- sync_switch_state ( ctx_p, pthread_parent, STATE_TERM );
- break;
- }
- }
- debug ( 3, "signal handler closed." );
- return 0;
- }
- int sync_term ( int exitcode )
- {
- *sync_sighandler_exitcode_p = exitcode;
- return pthread_kill ( pthread_sighandler, SIGTERM );
- }
- __extension__ int sync_run ( ctx_t *ctx_p )
- {
- int ret;
- sighandler_arg_t sighandler_arg = {0};
- indexes_t indexes = {NULL};
- debug ( 9, "Creating signal handler thread" );
- {
- int i;
- register_blockthread();
- sigset_t sigset_sighandler;
- sigemptyset ( &sigset_sighandler );
- sigaddset ( &sigset_sighandler, SIGALRM );
- sigaddset ( &sigset_sighandler, SIGHUP );
- sigaddset ( &sigset_sighandler, SIGQUIT );
- sigaddset ( &sigset_sighandler, SIGTERM );
- sigaddset ( &sigset_sighandler, SIGINT );
- sigaddset ( &sigset_sighandler, SIGCHLD );
- sigaddset ( &sigset_sighandler, SIGUSR_THREAD_GC );
- sigaddset ( &sigset_sighandler, SIGUSR_INITSYNC );
- sigaddset ( &sigset_sighandler, SIGUSR_DUMP );
- i = 0;
- while ( i < MAXSIGNALNUM ) {
- if ( ctx_p->customsignal[i] != NULL )
- sigaddset ( &sigset_sighandler, i );
- i++;
- }
- ret = pthread_sigmask ( SIG_BLOCK, &sigset_sighandler, NULL );
- if ( ret ) return ret;
- sighandler_arg.ctx_p = ctx_p;
- sighandler_arg.pthread_parent = pthread_self();
- sighandler_arg.exitcode_p = &ret;
- sighandler_arg.sigset_p = &sigset_sighandler;
- ret = pthread_create ( &pthread_sighandler, NULL, ( void * ( * ) ( void * ) ) sync_sighandler, &sighandler_arg );
- if ( ret ) return ret;
- sigset_t sigset_parent;
- sigemptyset ( &sigset_parent );
- sigaddset ( &sigset_parent, SIGUSR_BLOPINT );
- ret = pthread_sigmask ( SIG_UNBLOCK, &sigset_parent, NULL );
- if ( ret ) return ret;
- signal ( SIGUSR_BLOPINT, sync_sig_int );
- }
- debug ( 9, "Creating hash tables" );
- {
- int i;
- ctx_p->indexes_p = &indexes;
- indexes.wd2fpath_ht = g_hash_table_new_full ( g_direct_hash, g_direct_equal, 0, 0 );
- indexes.fpath2wd_ht = g_hash_table_new_full ( g_str_hash, g_str_equal, free, 0 );
- indexes.fpath2ei_ht = g_hash_table_new_full ( g_str_hash, g_str_equal, free, free );
- indexes.exc_fpath_ht = g_hash_table_new_full ( g_str_hash, g_str_equal, free, 0 );
- indexes.out_lines_aggr_ht = g_hash_table_new_full ( g_str_hash, g_str_equal, free, 0 );
- indexes.fileinfo_ht = g_hash_table_new_full ( g_str_hash, g_str_equal, free, free );
- i = 0;
- while ( i < QUEUE_MAX ) {
- switch ( i ) {
- case QUEUE_LOCKWAIT:
- indexes.fpath2ei_coll_ht[i] = g_hash_table_new_full ( g_str_hash, g_str_equal, free, 0 );
- break;
- default:
- indexes.fpath2ei_coll_ht[i] = g_hash_table_new_full ( g_str_hash, g_str_equal, free, free );
- indexes.exc_fpath_coll_ht[i] = g_hash_table_new_full ( g_str_hash, g_str_equal, free, 0 );
- }
- i++;
- }
- }
- debug ( 9, "Loading dynamical libraries" );
- if ( ctx_p->flags[MODE] == MODE_SO || ctx_p->flags[MODE] == MODE_RSYNCSO ) {
- /* security checks before dlopen */
- struct stat so_stat;
- if ( stat ( ctx_p->handlerfpath, &so_stat ) == -1 ) {
- error ( "Can't stat shared object file \"%s\": %s", ctx_p->handlerfpath, strerror ( errno ) );
- return errno;
- }
- // allow normal files only (stat will follow symlinks)
- if ( !S_ISREG ( so_stat.st_mode ) ) {
- error ( "Shared object \"%s\" must be a regular file (or symlink to a regular file).",
- ctx_p->handlerfpath, so_stat.st_uid );
- return EPERM;
- }
- // allowed owners are: root and real uid (who started clsync prior to setuid)
- if ( so_stat.st_uid && so_stat.st_uid != getuid() ) {
- /* check for rare case when clsync binary owner is neither root nor current uid */
- struct stat cl_stat;
- char *cl_str = alloca ( 20 ); // allocate for "/proc/PID/exe"
- int ret;
- snprintf ( cl_str, 20, "/proc/%i/exe", getpid() );
- // stat clsync binary itself to get its owner's uid
- if ( ( ret = stat ( cl_str, &cl_stat ) ) == -1 ) {
- error ( "Can't stat clsync binary file \"%s\": %s", cl_str, strerror ( errno ) );
- }
- if ( ret == -1 || so_stat.st_uid != cl_stat.st_uid ) {
- error ( "Wrong owner for shared object \"%s\": %i. "
- "Only root, clsync file owner and user started the program are allowed.",
- ctx_p->handlerfpath, so_stat.st_uid );
- return EPERM;
- }
- }
- // do not allow special bits and g+w,o+w
- if ( so_stat.st_mode & ( S_ISUID | S_ISGID | S_ISVTX | S_IWGRP | S_IWOTH ) ) {
- error ( "Wrong shared object \"%s\" permissions: %#lo"
- "Special bits, group and world writable are not allowed.",
- ctx_p->handlerfpath, so_stat.st_mode & 07777 );
- return EPERM;
- }
- // dlopen()
- void *synchandler_handle = dlopen ( ctx_p->handlerfpath, RTLD_NOW | RTLD_LOCAL );
- if ( synchandler_handle == NULL ) {
- error ( "Cannot load shared object file \"%s\": %s", ctx_p->handlerfpath, dlerror() );
- return -1;
- }
- // resolving init, sync and deinit functions' handlers
- ctx_p->handler_handle = synchandler_handle;
- ctx_p->handler_funct.init = ( api_funct_init ) dlsym ( ctx_p->handler_handle, API_PREFIX"init" );
- if ( ctx_p->flags[MODE] == MODE_RSYNCSO ) {
- ctx_p->handler_funct.rsync = ( api_funct_rsync ) dlsym ( ctx_p->handler_handle, API_PREFIX"rsync" );
- if ( ctx_p->handler_funct.rsync == NULL ) {
- char *dlerror_str = dlerror();
- error ( "Cannot resolve symbol "API_PREFIX"rsync in shared object \"%s\": %s",
- ctx_p->handlerfpath, dlerror_str != NULL ? dlerror_str : "No error description returned." );
- }
- } else {
- ctx_p->handler_funct.sync = ( api_funct_sync ) dlsym ( ctx_p->handler_handle, API_PREFIX"sync" );
- if ( ctx_p->handler_funct.sync == NULL ) {
- char *dlerror_str = dlerror();
- error ( "Cannot resolve symbol "API_PREFIX"sync in shared object \"%s\": %s",
- ctx_p->handlerfpath, dlerror_str != NULL ? dlerror_str : "No error description returned." );
- }
- }
- ctx_p->handler_funct.deinit = ( api_funct_deinit ) dlsym ( ctx_p->handler_handle, API_PREFIX"deinit" );
- // running init function
- if ( ctx_p->handler_funct.init != NULL )
- if ( ( ret = ctx_p->handler_funct.init ( ctx_p, &indexes ) ) ) {
- error ( "Cannot init sync-handler module." );
- return ret;
- }
- }
- // Initializing rand-generator if it's required
- if ( ctx_p->listoutdir )
- srand ( time ( NULL ) );
- if ( !ctx_p->flags[ONLYINITSYNC] ) {
- debug ( 9, "Initializing FS monitor kernel subsystem in this userspace application" );
- if ( sync_notify_init ( ctx_p ) )
- return errno;
- }
- if ( ( ret = privileged_init ( ctx_p ) ) )
- return ret;
- {
- // Preparing monitor subsystem context function pointers
- switch ( ctx_p->flags[MONITOR] ) {
- #ifdef INOTIFY_SUPPORT
- case NE_INOTIFY:
- ctx_p->notifyenginefunct.add_watch_dir = inotify_add_watch_dir;
- ctx_p->notifyenginefunct.wait = inotify_wait;
- ctx_p->notifyenginefunct.handle = inotify_handle;
- break;
- #endif
- #ifdef KQUEUE_SUPPORT
- case NE_KQUEUE:
- ctx_p->notifyenginefunct.add_watch_dir = kqueue_add_watch_dir;
- ctx_p->notifyenginefunct.wait = kqueue_wait;
- ctx_p->notifyenginefunct.handle = kqueue_handle;
- break;
- #endif
- #ifdef BSM_SUPPORT
- case NE_BSM:
- case NE_BSM_PREFETCH:
- ctx_p->notifyenginefunct.add_watch_dir = bsm_add_watch_dir;
- ctx_p->notifyenginefunct.wait = bsm_wait;
- ctx_p->notifyenginefunct.handle = bsm_handle;
- break;
- #endif
- #ifdef GIO_SUPPORT
- case NE_GIO:
- ctx_p->notifyenginefunct.add_watch_dir = gio_add_watch_dir;
- ctx_p->notifyenginefunct.wait = gio_wait;
- ctx_p->notifyenginefunct.handle = gio_handle;
- break;
- #endif
- #ifdef DTRACEPIPE_SUPPORT
- case NE_DTRACEPIPE:
- ctx_p->notifyenginefunct.add_watch_dir = dtracepipe_add_watch_dir;
- ctx_p->notifyenginefunct.wait = dtracepipe_wait;
- ctx_p->notifyenginefunct.handle = dtracepipe_handle;
- break;
- #endif
- #ifdef VERYPARANOID
- default:
- critical ( "Unknown FS monitor subsystem: %i", ctx_p->flags[MONITOR] );
- #endif
- }
- }
- #ifdef CLUSTER_SUPPORT
- // Initializing cluster subsystem
- if ( ctx_p->cluster_iface != NULL ) {
- ret = cluster_init ( ctx_p, &indexes );
- if ( ret ) {
- error ( "Cannot initialize cluster subsystem." );
- cluster_deinit();
- return ret;
- }
- }
- #endif
- #ifdef ENABLE_SOCKET
- // Creating control socket
- if ( ctx_p->socketpath != NULL )
- ret = control_run ( ctx_p );
- #endif
- if ( !ctx_p->flags[ONLYINITSYNC] ) {
- // Marking file tree for FS monitor
- debug ( 30, "Running recursive notify marking function" );
- ret = sync_mark_walk ( ctx_p, ctx_p->watchdir, &indexes );
- if ( ret ) return ret;
- }
- // "Infinite" loop of processling the events
- ret = sync_loop ( ctx_p, &indexes );
- if ( ret ) return ret;
- debug ( 1, "sync_loop() ended" );
- #ifdef ENABLE_SOCKET
- // Removing control socket
- if ( ctx_p->socketpath != NULL )
- control_cleanup ( ctx_p );
- #endif
- debug ( 1, "killing sighandler" );
- // TODO: Do cleanup of watching points
- pthread_kill ( pthread_sighandler, SIGINT );
- #ifdef VALGRIND
- pthread_join ( pthread_sighandler, NULL ); // TODO: fix a deadlock
- #endif
- // Killing children
- #ifdef THREADING_SUPPORT
- thread_cleanup ( ctx_p );
- #endif
- debug ( 2, "Deinitializing the FS monitor subsystem" );
- switch ( ctx_p->flags[MONITOR] ) {
- #ifdef INOTIFY_SUPPORT
- case NE_INOTIFY:
- inotify_deinit ( ctx_p );
- break;
- #endif
- #ifdef KQUEUE_SUPPORT
- case NE_KQUEUE:
- kqueue_deinit ( ctx_p );
- break;
- #endif
- #ifdef BSM_SUPPORT
- case NE_BSM:
- case NE_BSM_PREFETCH:
- bsm_deinit ( ctx_p );
- break;
- #endif
- #ifdef GIO_SUPPORT
- case NE_GIO:
- gio_deinit ( ctx_p );
- break;
- #endif
- #ifdef DTRACEPIPE_SUPPORT
- case NE_DTRACEPIPE:
- dtracepipe_deinit ( ctx_p );
- break;
- #endif
- }
- // Closing shared libraries
- if ( ctx_p->flags[MODE] == MODE_SO ) {
- int _ret;
- if ( ctx_p->handler_funct.deinit != NULL )
- if ( ( _ret = ctx_p->handler_funct.deinit() ) ) {
- error ( "Cannot deinit sync-handler module." );
- if ( !ret ) ret = _ret;
- }
- if ( dlclose ( ctx_p->handler_handle ) ) {
- error ( "Cannot unload shared object file \"%s\": %s",
- ctx_p->handlerfpath, dlerror() );
- if ( !ret ) ret = -1;
- }
- }
- // Cleaning up run-time routines
- rsync_escape_cleanup();
- // Removing hash-tables
- {
- int i;
- debug ( 3, "Closing hash tables" );
- g_hash_table_destroy ( indexes.wd2fpath_ht );
- g_hash_table_destroy ( indexes.fpath2wd_ht );
- g_hash_table_destroy ( indexes.fpath2ei_ht );
- g_hash_table_destroy ( indexes.exc_fpath_ht );
- g_hash_table_destroy ( indexes.out_lines_aggr_ht );
- g_hash_table_destroy ( indexes.fileinfo_ht );
- i = 0;
- while ( i < QUEUE_MAX ) {
- switch ( i ) {
- case QUEUE_LOCKWAIT:
- g_hash_table_destroy ( indexes.fpath2ei_coll_ht[i] );
- break;
- default:
- g_hash_table_destroy ( indexes.fpath2ei_coll_ht[i] );
- g_hash_table_destroy ( indexes.exc_fpath_coll_ht[i] );
- }
- i++;
- }
- }
- // Deinitializing cluster subsystem
- #ifdef CLUSTER_SUPPORT
- debug ( 3, "Deinitializing cluster subsystem" );
- if ( ctx_p->cluster_iface != NULL ) {
- int _ret;
- _ret = cluster_deinit();
- if ( _ret ) {
- error ( "Cannot deinitialize cluster subsystem.", strerror ( _ret ), _ret );
- ret = _ret;
- }
- }
- #endif
- // One second for another threads
- #ifdef VERYPARANOID
- debug ( 9, "sleep("TOSTR ( SLEEP_SECONDS ) ")" );
- sleep ( SLEEP_SECONDS );
- #endif
- if ( ctx_p->flags[EXITHOOK] ) {
- char *argv[] = { ctx_p->exithookfile, ctx_p->label, NULL};
- exec_argv ( argv, NULL );
- }
- // Cleaning up cgroups staff
- #ifdef CGROUP_SUPPORT
- debug ( 3, "Cleaning up cgroups staff" );
- if ( ctx_p->flags[FORBIDDEVICES] )
- error_on ( privileged_clsync_cgroup_deinit ( ctx_p ) );
- #endif
- debug ( 3, "privileged_deinit()" );
- ret |= privileged_deinit ( ctx_p );
- debug ( 3, "finish" );
- return ret;
- }
|