log.c 119 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * Copyright (C) 2010 Hewlett-Packard Development Company, L.P.
  5. * All rights reserved.
  6. *
  7. * License: GPL (version 3 or any later version).
  8. * See LICENSE for details.
  9. * END COPYRIGHT BLOCK **/
  10. #ifdef HAVE_CONFIG_H
  11. # include <config.h>
  12. #endif
  13. /*
  14. **
  15. ** log.c
  16. **
  17. ** Routines for writing access and error/debug logs
  18. **
  19. **
  20. ** History:
  21. ** As of DS 4.0, we support log rotation for the ACCESS/ERROR/AUDIT log.
  22. */
  23. #include "log.h"
  24. #include "fe.h"
  25. #include <pwd.h> /* getpwnam */
  26. #define _PSEP '/'
  27. /**************************************************************************
  28. * GLOBALS, defines, and ...
  29. *************************************************************************/
  30. /* main struct which contains all the information about logging */
  31. PRUintn logbuf_tsdindex;
  32. struct logbufinfo *logbuf_accum;
  33. static struct logging_opts loginfo;
  34. static int detached=0;
  35. /* used to lock the timestamp info used by vslapd_log_access */
  36. static PRLock *ts_time_lock = NULL;
  37. /*
  38. * Note: the order of the values in the slapi_log_map array must exactly
  39. * match that of the SLAPI_LOG_XXX #defines found in slapi-plugin.h (this is
  40. * so we can use the SLAPI_LOG_XXX values to index directly into the array).
  41. */
  42. static int slapi_log_map[] = {
  43. LDAP_DEBUG_ANY, /* SLAPI_LOG_FATAL */
  44. LDAP_DEBUG_TRACE, /* SLAPI_LOG_TRACE */
  45. LDAP_DEBUG_PACKETS, /* SLAPI_LOG_PACKETS */
  46. LDAP_DEBUG_ARGS, /* SLAPI_LOG_ARGS */
  47. LDAP_DEBUG_CONNS, /* SLAPI_LOG_CONNS */
  48. LDAP_DEBUG_BER, /* SLAPI_LOG_BER */
  49. LDAP_DEBUG_FILTER, /* SLAPI_LOG_FILTER */
  50. LDAP_DEBUG_CONFIG, /* SLAPI_LOG_CONFIG */
  51. LDAP_DEBUG_ACL, /* SLAPI_LOG_ACL */
  52. LDAP_DEBUG_SHELL, /* SLAPI_LOG_SHELL */
  53. LDAP_DEBUG_PARSE, /* SLAPI_LOG_PARSE */
  54. LDAP_DEBUG_HOUSE, /* SLAPI_LOG_HOUSE */
  55. LDAP_DEBUG_REPL, /* SLAPI_LOG_REPL */
  56. LDAP_DEBUG_CACHE, /* SLAPI_LOG_CACHE */
  57. LDAP_DEBUG_PLUGIN, /* SLAPI_LOG_PLUGIN */
  58. LDAP_DEBUG_TIMING, /* SLAPI_LOG_TIMING */
  59. LDAP_DEBUG_BACKLDBM, /* SLAPI_LOG_BACKLDBM */
  60. LDAP_DEBUG_ACLSUMMARY, /* SLAPI_LOG_ACLSUMMARY */
  61. LDAP_DEBUG_NUNCSTANS /* SLAPI_LOG_NUNCSTANS */
  62. };
  63. #define SLAPI_LOG_MIN SLAPI_LOG_FATAL /* from slapi-plugin.h */
  64. #define SLAPI_LOG_MAX SLAPI_LOG_NUNCSTANS /* from slapi-plugin.h */
  65. #define TBUFSIZE 50 /* size for time buffers */
  66. #define SLAPI_LOG_BUFSIZ 2048 /* size for data buffers */
  67. /**************************************************************************
  68. * PROTOTYPES
  69. *************************************************************************/
  70. static int log__open_accesslogfile(int logfile_type, int locked);
  71. static int log__open_errorlogfile(int logfile_type, int locked);
  72. static int log__open_auditlogfile(int logfile_type, int locked);
  73. static int log__needrotation(LOGFD fp, int logtype);
  74. static int log__delete_access_logfile();
  75. static int log__delete_error_logfile(int locked);
  76. static int log__delete_audit_logfile();
  77. static int log__access_rotationinfof(char *pathname);
  78. static int log__error_rotationinfof(char *pathname);
  79. static int log__audit_rotationinfof(char *pathname);
  80. static int log__extract_logheader (FILE *fp, long *f_ctime, PRInt64 *f_size);
  81. static int log__check_prevlogs (FILE *fp, char *filename);
  82. static PRInt64 log__getfilesize(LOGFD fp);
  83. static PRInt64 log__getfilesize_with_filename(char *filename);
  84. static int log__enough_freespace(char *path);
  85. static int vslapd_log_error(LOGFD fp, char *subsystem, char *fmt, va_list ap, int locked );
  86. static int vslapd_log_access(char *fmt, va_list ap );
  87. static void log_convert_time (time_t ctime, char *tbuf, int type);
  88. static time_t log_reverse_convert_time (char *tbuf);
  89. static LogBufferInfo *log_create_buffer(size_t sz);
  90. static void log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2);
  91. static void log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now);
  92. static void log_write_title(LOGFD fp);
  93. static void log__error_emergency(const char *errstr, int reopen, int locked);
  94. static void vslapd_log_emergency_error(LOGFD fp, const char *msg, int locked);
  95. static int
  96. slapd_log_error_proc_internal(
  97. char *subsystem, /* omitted if NULL */
  98. char *fmt,
  99. va_list ap_err,
  100. va_list ap_file);
  101. /*
  102. * these macros are used for opening a log file, closing a log file, and
  103. * writing out to a log file. we have to do this because currently NSPR
  104. * is extremely under-performant on NT, while fopen/fwrite fail on several
  105. * unix platforms if there are more than 128 files open.
  106. *
  107. * LOG_OPEN_APPEND(fd, filename, mode) returns true if successful. 'fd' should
  108. * be of type LOGFD (check log.h). the file is open for appending to.
  109. * LOG_OPEN_WRITE(fd, filename, mode) is the same but truncates the file and
  110. * starts writing at the beginning of the file.
  111. * LOG_WRITE(fd, buffer, size, headersize) writes into a LOGFD
  112. * LOG_WRITE_NOW(fd, buffer, size, headersize, err) writes into a LOGFD and
  113. * flushes the buffer if necessary
  114. * LOG_CLOSE(fd) closes the logfile
  115. */
  116. #define LOG_OPEN_APPEND(fd, filename, mode) \
  117. (((fd) = PR_Open((filename), PR_WRONLY | PR_APPEND | PR_CREATE_FILE , \
  118. mode)) != NULL)
  119. #define LOG_OPEN_WRITE(fd, filename, mode) \
  120. (((fd) = PR_Open((filename), PR_WRONLY | PR_TRUNCATE | \
  121. PR_CREATE_FILE, mode)) != NULL)
  122. #define LOG_WRITE(fd, buffer, size, headersize) \
  123. if ( slapi_write_buffer((fd), (buffer), (size)) != (size) ) \
  124. { \
  125. PRErrorCode prerr = PR_GetError(); \
  126. syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer)+(headersize) ); \
  127. }
  128. #define LOG_WRITE_NOW(fd, buffer, size, headersize, err) do {\
  129. (err) = 0; \
  130. if ( slapi_write_buffer((fd), (buffer), (size)) != (size) ) \
  131. { \
  132. PRErrorCode prerr = PR_GetError(); \
  133. syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer)+(headersize) ); \
  134. (err) = prerr; \
  135. } \
  136. /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ \
  137. PR_Sync(fd); \
  138. } while (0)
  139. #define LOG_WRITE_NOW_NO_ERR(fd, buffer, size, headersize) do {\
  140. if ( slapi_write_buffer((fd), (buffer), (size)) != (size) ) \
  141. { \
  142. PRErrorCode prerr = PR_GetError(); \
  143. syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer)+(headersize) ); \
  144. } \
  145. /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ \
  146. PR_Sync(fd); \
  147. } while (0)
  148. #define LOG_CLOSE(fd) \
  149. PR_Close((fd))
  150. /******************************************************************************
  151. * Set the access level
  152. ******************************************************************************/
  153. void g_set_accesslog_level(int val)
  154. {
  155. LOG_ACCESS_LOCK_WRITE( );
  156. loginfo.log_access_level = val;
  157. LOG_ACCESS_UNLOCK_WRITE();
  158. }
  159. /******************************************************************************
  160. * Set whether the process is alive or dead
  161. * If it is detached, then we write the error in 'stderr'
  162. ******************************************************************************/
  163. void g_set_detached(int val)
  164. {
  165. detached = val;
  166. }
  167. /******************************************************************************
  168. * Tell me whether logging begins or not
  169. ******************************************************************************/
  170. void g_log_init(int log_enabled)
  171. {
  172. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  173. ts_time_lock = PR_NewLock();
  174. if (! ts_time_lock)
  175. exit(-1);
  176. /* ACCESS LOG */
  177. loginfo.log_access_state = 0;
  178. loginfo.log_access_mode = SLAPD_DEFAULT_FILE_MODE;
  179. loginfo.log_access_maxnumlogs = 1;
  180. loginfo.log_access_maxlogsize = -1;
  181. loginfo.log_access_rotationsync_enabled = 0;
  182. loginfo.log_access_rotationsynchour = -1;
  183. loginfo.log_access_rotationsyncmin = -1;
  184. loginfo.log_access_rotationsyncclock = -1;
  185. loginfo.log_access_rotationtime = 1; /* default: 1 */
  186. loginfo.log_access_rotationunit = LOG_UNIT_DAYS; /* default: day */
  187. loginfo.log_access_rotationtime_secs = 86400; /* default: 1 day */
  188. loginfo.log_access_maxdiskspace = -1;
  189. loginfo.log_access_minfreespace = -1;
  190. loginfo.log_access_exptime = -1; /* default: -1 */
  191. loginfo.log_access_exptimeunit = LOG_UNIT_MONTHS; /* default: month */
  192. loginfo.log_access_exptime_secs = -1; /* default: -1 */
  193. loginfo.log_access_level = LDAP_DEBUG_STATS;
  194. loginfo.log_access_ctime = 0L;
  195. loginfo.log_access_fdes = NULL;
  196. loginfo.log_access_file = NULL;
  197. loginfo.log_accessinfo_file = NULL;
  198. loginfo.log_numof_access_logs = 1;
  199. loginfo.log_access_logchain = NULL;
  200. loginfo.log_access_buffer = log_create_buffer(LOG_BUFFER_MAXSIZE);
  201. if (loginfo.log_access_buffer == NULL)
  202. exit(-1);
  203. if ((loginfo.log_access_buffer->lock = PR_NewLock())== NULL )
  204. exit (-1);
  205. slapdFrontendConfig->accessloglevel = LDAP_DEBUG_STATS;
  206. /* ERROR LOG */
  207. loginfo.log_error_state = 0;
  208. loginfo.log_error_mode = SLAPD_DEFAULT_FILE_MODE;
  209. loginfo.log_error_maxnumlogs = 1;
  210. loginfo.log_error_maxlogsize = -1;
  211. loginfo.log_error_rotationsync_enabled = 0;
  212. loginfo.log_error_rotationsynchour = -1;
  213. loginfo.log_error_rotationsyncmin = -1;
  214. loginfo.log_error_rotationsyncclock = -1;
  215. loginfo.log_error_rotationtime = 1; /* default: 1 */
  216. loginfo.log_error_rotationunit = LOG_UNIT_WEEKS; /* default: week */
  217. loginfo.log_error_rotationtime_secs = 604800; /* default: 1 week */
  218. loginfo.log_error_maxdiskspace = -1;
  219. loginfo.log_error_minfreespace = -1;
  220. loginfo.log_error_exptime = -1; /* default: -1 */
  221. loginfo.log_error_exptimeunit = LOG_UNIT_MONTHS; /* default: month */
  222. loginfo.log_error_exptime_secs = -1; /* default: -1 */
  223. loginfo.log_error_ctime = 0L;
  224. loginfo.log_error_file = NULL;
  225. loginfo.log_errorinfo_file = NULL;
  226. loginfo.log_error_fdes = NULL;
  227. loginfo.log_numof_error_logs = 1;
  228. loginfo.log_error_logchain = NULL;
  229. if ((loginfo.log_error_rwlock =slapi_new_rwlock())== NULL ) {
  230. exit (-1);
  231. }
  232. /* AUDIT LOG */
  233. loginfo.log_audit_state = 0;
  234. loginfo.log_audit_mode = SLAPD_DEFAULT_FILE_MODE;
  235. loginfo.log_audit_maxnumlogs = 1;
  236. loginfo.log_audit_maxlogsize = -1;
  237. loginfo.log_audit_rotationsync_enabled = 0;
  238. loginfo.log_audit_rotationsynchour = -1;
  239. loginfo.log_audit_rotationsyncmin = -1;
  240. loginfo.log_audit_rotationsyncclock = -1;
  241. loginfo.log_audit_rotationtime = 1; /* default: 1 */
  242. loginfo.log_audit_rotationunit = LOG_UNIT_WEEKS; /* default: week */
  243. loginfo.log_audit_rotationtime_secs = 604800; /* default: 1 week */
  244. loginfo.log_audit_maxdiskspace = -1;
  245. loginfo.log_audit_minfreespace = -1;
  246. loginfo.log_audit_exptime = -1; /* default: -1 */
  247. loginfo.log_audit_exptimeunit = LOG_UNIT_WEEKS; /* default: week */
  248. loginfo.log_audit_exptime_secs = -1; /* default: -1 */
  249. loginfo.log_audit_ctime = 0L;
  250. loginfo.log_audit_file = NULL;
  251. loginfo.log_auditinfo_file = NULL;
  252. loginfo.log_numof_audit_logs = 1;
  253. loginfo.log_audit_fdes = NULL;
  254. loginfo.log_audit_logchain = NULL;
  255. if ((loginfo.log_audit_rwlock =slapi_new_rwlock())== NULL ) {
  256. exit (-1);
  257. }
  258. }
  259. /******************************************************************************
  260. * Tell me if log is enabled or disabled
  261. ******************************************************************************/
  262. int
  263. log_set_logging(const char *attrname, char *value, int logtype, char *errorbuf, int apply)
  264. {
  265. int v;
  266. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  267. if ( NULL == value ) {
  268. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  269. "%s: NULL value; valid values "
  270. "are \"on\" or \"off\"", attrname );
  271. return LDAP_OPERATIONS_ERROR;
  272. }
  273. if (strcasecmp(value, "on") == 0) {
  274. v = LOGGING_ENABLED;
  275. }
  276. else if (strcasecmp(value, "off") == 0 ) {
  277. v = 0;
  278. }
  279. else {
  280. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  281. "%s: invalid value \"%s\", valid values "
  282. "are \"on\" or \"off\"", attrname, value );
  283. return LDAP_OPERATIONS_ERROR;
  284. }
  285. if ( !apply ){
  286. return LDAP_SUCCESS;
  287. }
  288. switch (logtype) {
  289. case SLAPD_ACCESS_LOG:
  290. LOG_ACCESS_LOCK_WRITE( );
  291. fe_cfg->accesslog_logging_enabled = v;
  292. if(v) {
  293. loginfo.log_access_state |= LOGGING_ENABLED;
  294. }
  295. else {
  296. loginfo.log_access_state &= ~LOGGING_ENABLED;
  297. }
  298. LOG_ACCESS_UNLOCK_WRITE();
  299. break;
  300. case SLAPD_ERROR_LOG:
  301. LOG_ERROR_LOCK_WRITE( );
  302. fe_cfg->errorlog_logging_enabled = v;
  303. if (v) {
  304. loginfo.log_error_state |= LOGGING_ENABLED;
  305. }
  306. else {
  307. loginfo.log_error_state &= ~LOGGING_ENABLED;
  308. }
  309. LOG_ERROR_UNLOCK_WRITE();
  310. break;
  311. case SLAPD_AUDIT_LOG:
  312. LOG_AUDIT_LOCK_WRITE( );
  313. fe_cfg->auditlog_logging_enabled = v;
  314. if (v) {
  315. loginfo.log_audit_state |= LOGGING_ENABLED;
  316. }
  317. else {
  318. loginfo.log_audit_state &= ~LOGGING_ENABLED;
  319. }
  320. LOG_AUDIT_UNLOCK_WRITE();
  321. break;
  322. }
  323. return LDAP_SUCCESS;
  324. }
  325. /******************************************************************************
  326. * Tell me the access log file name inc path
  327. ******************************************************************************/
  328. char *
  329. g_get_access_log () {
  330. char *logfile = NULL;
  331. LOG_ACCESS_LOCK_READ();
  332. if ( loginfo.log_access_file)
  333. logfile = slapi_ch_strdup (loginfo.log_access_file);
  334. LOG_ACCESS_UNLOCK_READ();
  335. return logfile;
  336. }
  337. /******************************************************************************
  338. * Point to a new access logdir
  339. *
  340. * Returns:
  341. * LDAP_SUCCESS -- success
  342. * LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
  343. * LDAP_LOCAL_ERRO -- some error
  344. ******************************************************************************/
  345. int
  346. log_update_accesslogdir(char *pathname, int apply)
  347. {
  348. int rv = LDAP_SUCCESS;
  349. LOGFD fp;
  350. /* try to open the file, we may have a incorrect path */
  351. if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_access_mode)) {
  352. LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
  353. "errno %d (%s)\n",
  354. pathname, errno, slapd_system_strerror(errno));
  355. /* stay with the current log file */
  356. return LDAP_UNWILLING_TO_PERFORM;
  357. }
  358. LOG_CLOSE(fp);
  359. /* skip the rest if we aren't doing this for real */
  360. if ( !apply ) {
  361. return LDAP_SUCCESS;
  362. }
  363. /*
  364. ** The user has changed the access log directory. That means we
  365. ** need to start fresh.
  366. */
  367. LOG_ACCESS_LOCK_WRITE ();
  368. if (loginfo.log_access_fdes) {
  369. LogFileInfo *logp, *d_logp;
  370. LDAPDebug(LDAP_DEBUG_TRACE,
  371. "LOGINFO:Closing the access log file. "
  372. "Moving to a new access log file (%s)\n", pathname,0,0);
  373. LOG_CLOSE(loginfo.log_access_fdes);
  374. loginfo.log_access_fdes = 0;
  375. loginfo.log_access_ctime = 0;
  376. logp = loginfo.log_access_logchain;
  377. while (logp) {
  378. d_logp = logp;
  379. logp = logp->l_next;
  380. slapi_ch_free((void**)&d_logp);
  381. }
  382. loginfo.log_access_logchain = NULL;
  383. slapi_ch_free((void**)&loginfo.log_access_file);
  384. loginfo.log_access_file = NULL;
  385. loginfo.log_numof_access_logs = 1;
  386. }
  387. /* Now open the new access log file */
  388. if ( access_log_openf (pathname, 1 /* locked */)) {
  389. rv = LDAP_LOCAL_ERROR; /* error Unable to use the new dir */
  390. }
  391. LOG_ACCESS_UNLOCK_WRITE();
  392. return rv;
  393. }
  394. /******************************************************************************
  395. * Tell me the error log file name inc path
  396. ******************************************************************************/
  397. char *
  398. g_get_error_log() {
  399. char *logfile = NULL;
  400. LOG_ERROR_LOCK_READ();
  401. if ( loginfo.log_error_file)
  402. logfile = slapi_ch_strdup (loginfo.log_error_file);
  403. LOG_ERROR_UNLOCK_READ();
  404. return logfile;
  405. }
  406. /******************************************************************************
  407. * Point to a new error logdir
  408. *
  409. * Returns:
  410. * LDAP_SUCCESS -- success
  411. * LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
  412. * LDAP_LOCAL_ERRO -- some error
  413. ******************************************************************************/
  414. int
  415. log_update_errorlogdir(char *pathname, int apply)
  416. {
  417. int rv = LDAP_SUCCESS;
  418. LOGFD fp;
  419. /* try to open the file, we may have a incorrect path */
  420. if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_error_mode)) {
  421. char buffer[SLAPI_LOG_BUFSIZ];
  422. PRErrorCode prerr = PR_GetError();
  423. /* stay with the current log file */
  424. PR_snprintf(buffer, sizeof(buffer),
  425. "Failed to open file %s. error %d (%s). Exiting...",
  426. pathname, prerr, slapd_pr_strerror(prerr));
  427. log__error_emergency(buffer, 0, 0);
  428. return LDAP_UNWILLING_TO_PERFORM;
  429. }
  430. LOG_CLOSE(fp);
  431. /* skip the rest if we aren't doing this for real */
  432. if ( !apply ) {
  433. return LDAP_SUCCESS;
  434. }
  435. /*
  436. ** The user has changed the error log directory. That means we
  437. ** need to start fresh.
  438. */
  439. LOG_ERROR_LOCK_WRITE ();
  440. if (loginfo.log_error_fdes) {
  441. LogFileInfo *logp, *d_logp;
  442. LOG_CLOSE(loginfo.log_error_fdes);
  443. loginfo.log_error_fdes = 0;
  444. loginfo.log_error_ctime = 0;
  445. logp = loginfo.log_error_logchain;
  446. while (logp) {
  447. d_logp = logp;
  448. logp = logp->l_next;
  449. slapi_ch_free((void**)&d_logp);
  450. }
  451. loginfo.log_error_logchain = NULL;
  452. slapi_ch_free((void**)&loginfo.log_error_file);
  453. loginfo.log_error_file = NULL;
  454. loginfo.log_numof_error_logs = 1;
  455. }
  456. /* Now open the new errorlog */
  457. if ( error_log_openf (pathname, 1 /* obtained lock */)) {
  458. rv = LDAP_LOCAL_ERROR; /* error: Unable to use the new dir */
  459. }
  460. LOG_ERROR_UNLOCK_WRITE();
  461. return rv;
  462. }
  463. /******************************************************************************
  464. * Tell me the audit log file name inc path
  465. ******************************************************************************/
  466. char *
  467. g_get_audit_log() {
  468. char *logfile = NULL;
  469. LOG_AUDIT_LOCK_READ();
  470. if ( loginfo.log_audit_file)
  471. logfile = slapi_ch_strdup (loginfo.log_audit_file);
  472. LOG_AUDIT_UNLOCK_READ();
  473. return logfile;
  474. }
  475. /******************************************************************************
  476. * Point to a new audit logdir
  477. *
  478. * Returns:
  479. * LDAP_SUCCESS -- success
  480. * LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
  481. * LDAP_LOCAL_ERRO -- some error
  482. ******************************************************************************/
  483. int
  484. log_update_auditlogdir(char *pathname, int apply)
  485. {
  486. int rv = LDAP_SUCCESS;
  487. LOGFD fp;
  488. /* try to open the file, we may have a incorrect path */
  489. if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_audit_mode)) {
  490. LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
  491. "errno %d (%s)\n",
  492. pathname, errno, slapd_system_strerror(errno));
  493. /* stay with the current log file */
  494. return LDAP_UNWILLING_TO_PERFORM;
  495. }
  496. LOG_CLOSE(fp);
  497. /* skip the rest if we aren't doing this for real */
  498. if ( !apply ) {
  499. return LDAP_SUCCESS;
  500. }
  501. /*
  502. ** The user has changed the audit log directory. That means we
  503. ** need to start fresh.
  504. */
  505. LOG_AUDIT_LOCK_WRITE ();
  506. if (loginfo.log_audit_fdes) {
  507. LogFileInfo *logp, *d_logp;
  508. LDAPDebug(LDAP_DEBUG_TRACE,
  509. "LOGINFO:Closing the audit log file. "
  510. "Moving to a new audit file (%s)\n", pathname,0,0);
  511. LOG_CLOSE(loginfo.log_audit_fdes);
  512. loginfo.log_audit_fdes = 0;
  513. loginfo.log_audit_ctime = 0;
  514. logp = loginfo.log_audit_logchain;
  515. while (logp) {
  516. d_logp = logp;
  517. logp = logp->l_next;
  518. slapi_ch_free((void**)&d_logp);
  519. }
  520. loginfo.log_audit_logchain = NULL;
  521. slapi_ch_free((void**)&loginfo.log_audit_file);
  522. loginfo.log_audit_file = NULL;
  523. loginfo.log_numof_audit_logs = 1;
  524. }
  525. /* Now open the new auditlog */
  526. if ( audit_log_openf (pathname, 1 /* locked */)) {
  527. rv = LDAP_LOCAL_ERROR; /* error: Unable to use the new dir */
  528. }
  529. LOG_AUDIT_UNLOCK_WRITE();
  530. return rv;
  531. }
  532. int
  533. log_set_mode (const char *attrname, char *value, int logtype, char *errorbuf, int apply)
  534. {
  535. int v = 0;
  536. int retval = LDAP_SUCCESS;
  537. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  538. if ( NULL == value ) {
  539. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  540. "%s: null value; valid values "
  541. "are are of the format \"yz-yz-yz-\" where y could be 'r' or '-',"
  542. " and z could be 'w' or '-'", attrname );
  543. return LDAP_OPERATIONS_ERROR;
  544. }
  545. if ( !apply ){
  546. return LDAP_SUCCESS;
  547. }
  548. v = strtol (value, NULL, 8);
  549. switch (logtype) {
  550. case SLAPD_ACCESS_LOG:
  551. LOG_ACCESS_LOCK_WRITE( );
  552. if (loginfo.log_access_file &&
  553. ( chmod( loginfo.log_access_file, v ) != 0) ) {
  554. int oserr = errno;
  555. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  556. "%s: Failed to chmod access log file to %s: errno %d (%s)",
  557. attrname, value, oserr, slapd_system_strerror(oserr) );
  558. retval = LDAP_UNWILLING_TO_PERFORM;
  559. } else { /* only apply the changes if no file or if successful */
  560. slapi_ch_free ( (void **) &fe_cfg->accesslog_mode );
  561. fe_cfg->accesslog_mode = slapi_ch_strdup (value);
  562. loginfo.log_access_mode = v;
  563. }
  564. LOG_ACCESS_UNLOCK_WRITE();
  565. break;
  566. case SLAPD_ERROR_LOG:
  567. LOG_ERROR_LOCK_WRITE( );
  568. if (loginfo.log_error_file &&
  569. ( chmod( loginfo.log_error_file, v ) != 0) ) {
  570. int oserr = errno;
  571. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  572. "%s: Failed to chmod error log file to %s: errno %d (%s)",
  573. attrname, value, oserr, slapd_system_strerror(oserr) );
  574. retval = LDAP_UNWILLING_TO_PERFORM;
  575. } else { /* only apply the changes if no file or if successful */
  576. slapi_ch_free ( (void **) &fe_cfg->errorlog_mode );
  577. fe_cfg->errorlog_mode = slapi_ch_strdup (value);
  578. loginfo.log_error_mode = v;
  579. }
  580. LOG_ERROR_UNLOCK_WRITE();
  581. break;
  582. case SLAPD_AUDIT_LOG:
  583. LOG_AUDIT_LOCK_WRITE( );
  584. if (loginfo.log_audit_file &&
  585. ( chmod( loginfo.log_audit_file, v ) != 0) ) {
  586. int oserr = errno;
  587. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  588. "%s: Failed to chmod audit log file to %s: errno %d (%s)",
  589. attrname, value, oserr, slapd_system_strerror(oserr) );
  590. retval = LDAP_UNWILLING_TO_PERFORM;
  591. } else { /* only apply the changes if no file or if successful */
  592. slapi_ch_free ( (void **) &fe_cfg->auditlog_mode );
  593. fe_cfg->auditlog_mode = slapi_ch_strdup (value);
  594. loginfo.log_audit_mode = v;
  595. }
  596. LOG_AUDIT_UNLOCK_WRITE();
  597. break;
  598. }
  599. return retval;
  600. }
  601. /******************************************************************************
  602. * MAX NUMBER OF LOGS
  603. ******************************************************************************/
  604. int
  605. log_set_numlogsperdir(const char *attrname, char *numlogs_str, int logtype, char *returntext, int apply)
  606. {
  607. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  608. int rv = LDAP_SUCCESS;
  609. int numlogs;
  610. if ( logtype != SLAPD_ACCESS_LOG &&
  611. logtype != SLAPD_ERROR_LOG &&
  612. logtype != SLAPD_AUDIT_LOG ) {
  613. rv = LDAP_OPERATIONS_ERROR;
  614. PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  615. "%s: invalid log type %d", attrname, logtype );
  616. }
  617. if ( !apply || !numlogs_str || !*numlogs_str) {
  618. return rv;
  619. }
  620. numlogs = atoi(numlogs_str);
  621. if (numlogs >= 1) {
  622. switch (logtype) {
  623. case SLAPD_ACCESS_LOG:
  624. LOG_ACCESS_LOCK_WRITE( );
  625. loginfo.log_access_maxnumlogs = numlogs;
  626. fe_cfg->accesslog_maxnumlogs = numlogs;
  627. LOG_ACCESS_UNLOCK_WRITE();
  628. break;
  629. case SLAPD_ERROR_LOG:
  630. LOG_ERROR_LOCK_WRITE( );
  631. loginfo.log_error_maxnumlogs = numlogs;
  632. fe_cfg->errorlog_maxnumlogs = numlogs;
  633. LOG_ERROR_UNLOCK_WRITE();
  634. break;
  635. case SLAPD_AUDIT_LOG:
  636. LOG_AUDIT_LOCK_WRITE( );
  637. loginfo.log_audit_maxnumlogs = numlogs;
  638. fe_cfg->auditlog_maxnumlogs = numlogs;
  639. LOG_AUDIT_UNLOCK_WRITE();
  640. break;
  641. default:
  642. rv = LDAP_OPERATIONS_ERROR;
  643. LDAPDebug( LDAP_DEBUG_ANY,
  644. "log_set_numlogsperdir: invalid log type %d", logtype,0,0 );
  645. }
  646. }
  647. return rv;
  648. }
  649. /******************************************************************************
  650. * LOG SIZE
  651. * Return Values:
  652. * LDAP_OPERATIONS_ERROR -- fail
  653. * LDAP_SUCCESS -- success
  654. *
  655. * NOTE: The config struct should contain the maxlogsize in MB and not in bytes.
  656. ******************************************************************************/
  657. int
  658. log_set_logsize(const char *attrname, char *logsize_str, int logtype, char *returntext, int apply)
  659. {
  660. int rv = LDAP_SUCCESS;
  661. PRInt64 mdiskspace= 0; /* in bytes */
  662. PRInt64 max_logsize; /* in bytes */
  663. int logsize; /* in megabytes */
  664. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  665. if (!apply || !logsize_str || !*logsize_str)
  666. return rv;
  667. logsize = atoi(logsize_str);
  668. /* convert it to bytes */
  669. max_logsize = (PRInt64)logsize * LOG_MB_IN_BYTES;
  670. if (max_logsize <= 0) {
  671. max_logsize = -1;
  672. }
  673. switch (logtype) {
  674. case SLAPD_ACCESS_LOG:
  675. LOG_ACCESS_LOCK_WRITE( );
  676. mdiskspace = loginfo.log_access_maxdiskspace;
  677. break;
  678. case SLAPD_ERROR_LOG:
  679. LOG_ERROR_LOCK_WRITE( );
  680. mdiskspace = loginfo.log_error_maxdiskspace;
  681. break;
  682. case SLAPD_AUDIT_LOG:
  683. LOG_AUDIT_LOCK_WRITE( );
  684. mdiskspace = loginfo.log_audit_maxdiskspace;
  685. break;
  686. default:
  687. PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  688. "%s: invalid logtype %d", attrname, logtype );
  689. rv = LDAP_OPERATIONS_ERROR;
  690. }
  691. if ((max_logsize > mdiskspace) && (mdiskspace != -1))
  692. rv = 2;
  693. switch (logtype) {
  694. case SLAPD_ACCESS_LOG:
  695. if (!rv && apply) {
  696. loginfo.log_access_maxlogsize = max_logsize;
  697. fe_cfg->accesslog_maxlogsize = logsize;
  698. }
  699. LOG_ACCESS_UNLOCK_WRITE();
  700. break;
  701. case SLAPD_ERROR_LOG:
  702. if (!rv && apply) {
  703. loginfo.log_error_maxlogsize = max_logsize;
  704. fe_cfg->errorlog_maxlogsize = logsize;
  705. }
  706. LOG_ERROR_UNLOCK_WRITE();
  707. break;
  708. case SLAPD_AUDIT_LOG:
  709. if (!rv && apply) {
  710. loginfo.log_audit_maxlogsize = max_logsize;
  711. fe_cfg->auditlog_maxlogsize = logsize;
  712. }
  713. LOG_AUDIT_UNLOCK_WRITE();
  714. break;
  715. default:
  716. rv = 1;
  717. }
  718. /* logsize is in MB */
  719. if (rv == 2) {
  720. LDAPDebug (LDAP_DEBUG_ANY,
  721. "Invalid value for Maximum log size:"
  722. "Maxlogsize:%d (MB) exceeds Maxdisksize:%d (MB)\n",
  723. logsize, mdiskspace/LOG_MB_IN_BYTES,0);
  724. rv = LDAP_OPERATIONS_ERROR;
  725. }
  726. return rv;
  727. }
  728. time_t
  729. log_get_rotationsyncclock(int synchour, int syncmin)
  730. {
  731. struct tm *currtm;
  732. time_t currclock;
  733. time_t syncclock;
  734. int hours, minutes;
  735. time( &currclock);
  736. currtm = localtime( &currclock );
  737. if ( syncmin < currtm->tm_min ) {
  738. minutes = syncmin + 60 - currtm->tm_min;
  739. hours = synchour - 1 - currtm->tm_hour;
  740. } else {
  741. minutes = syncmin - currtm->tm_min;
  742. hours = synchour - currtm->tm_hour;
  743. }
  744. if ( hours < 0 ) hours += 24;
  745. syncclock = currclock + hours * 3600 + minutes * 60;
  746. return syncclock;
  747. }
  748. int
  749. log_set_rotationsync_enabled(const char *attrname, char *value, int logtype, char *errorbuf, int apply)
  750. {
  751. int v;
  752. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  753. if ( NULL == value ) {
  754. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  755. "%s: NULL value; valid values "
  756. "are \"on\" or \"off\"", attrname );
  757. return LDAP_OPERATIONS_ERROR;
  758. }
  759. if (strcasecmp(value, "on") == 0) {
  760. v = LDAP_ON;
  761. }
  762. else if (strcasecmp(value, "off") == 0 ) {
  763. v = LDAP_OFF;
  764. }
  765. else {
  766. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  767. "%s: invalid value \"%s\", valid values "
  768. "are \"on\" or \"off\"", attrname, value );
  769. return LDAP_OPERATIONS_ERROR;
  770. }
  771. if ( !apply ){
  772. return LDAP_SUCCESS;
  773. }
  774. switch (logtype) {
  775. case SLAPD_ACCESS_LOG:
  776. LOG_ACCESS_LOCK_WRITE( );
  777. fe_cfg->accesslog_rotationsync_enabled = v;
  778. loginfo.log_access_rotationsync_enabled = v;
  779. LOG_ACCESS_UNLOCK_WRITE();
  780. break;
  781. case SLAPD_ERROR_LOG:
  782. LOG_ERROR_LOCK_WRITE( );
  783. fe_cfg->errorlog_rotationsync_enabled = v;
  784. loginfo.log_error_rotationsync_enabled = v;
  785. LOG_ERROR_UNLOCK_WRITE();
  786. break;
  787. case SLAPD_AUDIT_LOG:
  788. LOG_AUDIT_LOCK_WRITE( );
  789. fe_cfg->auditlog_rotationsync_enabled = v;
  790. loginfo.log_audit_rotationsync_enabled = v;
  791. LOG_AUDIT_UNLOCK_WRITE();
  792. break;
  793. }
  794. return LDAP_SUCCESS;
  795. }
  796. int
  797. log_set_rotationsynchour(const char *attrname, char *rhour_str, int logtype, char *returntext, int apply)
  798. {
  799. int rhour = -1;
  800. int rv = LDAP_SUCCESS;
  801. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  802. if ( logtype != SLAPD_ACCESS_LOG &&
  803. logtype != SLAPD_ERROR_LOG &&
  804. logtype != SLAPD_AUDIT_LOG ) {
  805. PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  806. "%s: invalid log type: %d", attrname, logtype );
  807. return LDAP_OPERATIONS_ERROR;
  808. }
  809. /* return if we aren't doing this for real */
  810. if ( !apply ) {
  811. return rv;
  812. }
  813. if ( rhour_str && *rhour_str != '\0' )
  814. rhour = atol( rhour_str );
  815. if ( rhour > 23 )
  816. rhour = rhour % 24;
  817. switch (logtype) {
  818. case SLAPD_ACCESS_LOG:
  819. LOG_ACCESS_LOCK_WRITE( );
  820. loginfo.log_access_rotationsynchour = rhour;
  821. loginfo.log_access_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_access_rotationsyncmin );
  822. fe_cfg->accesslog_rotationsynchour = rhour;
  823. LOG_ACCESS_UNLOCK_WRITE();
  824. break;
  825. case SLAPD_ERROR_LOG:
  826. LOG_ERROR_LOCK_WRITE( );
  827. loginfo.log_error_rotationsynchour = rhour;
  828. loginfo.log_error_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_error_rotationsyncmin );
  829. fe_cfg->errorlog_rotationsynchour = rhour;
  830. LOG_ERROR_UNLOCK_WRITE();
  831. break;
  832. case SLAPD_AUDIT_LOG:
  833. LOG_AUDIT_LOCK_WRITE( );
  834. loginfo.log_audit_rotationsynchour = rhour;
  835. loginfo.log_audit_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_audit_rotationsyncmin );
  836. fe_cfg->auditlog_rotationsynchour = rhour;
  837. LOG_AUDIT_UNLOCK_WRITE();
  838. break;
  839. }
  840. return rv;
  841. }
  842. int
  843. log_set_rotationsyncmin(const char *attrname, char *rmin_str, int logtype, char *returntext, int apply)
  844. {
  845. int rmin = -1;
  846. int rv = LDAP_SUCCESS;
  847. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  848. if ( logtype != SLAPD_ACCESS_LOG &&
  849. logtype != SLAPD_ERROR_LOG &&
  850. logtype != SLAPD_AUDIT_LOG ) {
  851. PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  852. "%s: invalid log type: %d", attrname, logtype );
  853. return LDAP_OPERATIONS_ERROR;
  854. }
  855. /* return if we aren't doing this for real */
  856. if ( !apply ) {
  857. return rv;
  858. }
  859. if ( rmin_str && *rmin_str != '\0' )
  860. rmin = atol( rmin_str );
  861. if ( rmin > 59 )
  862. rmin = rmin % 60;
  863. switch (logtype) {
  864. case SLAPD_ACCESS_LOG:
  865. LOG_ACCESS_LOCK_WRITE( );
  866. loginfo.log_access_rotationsyncmin = rmin;
  867. fe_cfg->accesslog_rotationsyncmin = rmin;
  868. loginfo.log_access_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_access_rotationsynchour, rmin );
  869. LOG_ACCESS_UNLOCK_WRITE();
  870. break;
  871. case SLAPD_ERROR_LOG:
  872. LOG_ERROR_LOCK_WRITE( );
  873. loginfo.log_error_rotationsyncmin = rmin;
  874. loginfo.log_error_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_error_rotationsynchour, rmin );
  875. fe_cfg->errorlog_rotationsyncmin = rmin;
  876. LOG_ERROR_UNLOCK_WRITE();
  877. break;
  878. case SLAPD_AUDIT_LOG:
  879. LOG_AUDIT_LOCK_WRITE( );
  880. loginfo.log_audit_rotationsyncmin = rmin;
  881. fe_cfg->auditlog_rotationsyncmin = rmin;
  882. loginfo.log_audit_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_audit_rotationsynchour, rmin );
  883. LOG_AUDIT_UNLOCK_WRITE();
  884. break;
  885. }
  886. return rv;
  887. }
  888. /******************************************************************************
  889. * ROTATION TIME
  890. * Return Values:
  891. * 1 -- fail
  892. * 0 -- success
  893. ******************************************************************************/
  894. int
  895. log_set_rotationtime(const char *attrname, char *rtime_str, int logtype, char *returntext, int apply)
  896. {
  897. int runit= 0;
  898. int value, rtime;
  899. int rv = LDAP_SUCCESS;
  900. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  901. if ( logtype != SLAPD_ACCESS_LOG &&
  902. logtype != SLAPD_ERROR_LOG &&
  903. logtype != SLAPD_AUDIT_LOG ) {
  904. PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  905. "%s: invalid log type: %d", attrname, logtype );
  906. return LDAP_OPERATIONS_ERROR;
  907. }
  908. /* return if we aren't doing this for real */
  909. if ( !apply || !rtime_str || !*rtime_str) {
  910. return rv;
  911. }
  912. rtime = atoi(rtime_str);
  913. if (0 == rtime) {
  914. rtime = -1; /* Value Range: -1 | 1 to PR_INT32_MAX */
  915. }
  916. switch (logtype) {
  917. case SLAPD_ACCESS_LOG:
  918. LOG_ACCESS_LOCK_WRITE( );
  919. loginfo.log_access_rotationtime = rtime;
  920. runit = loginfo.log_access_rotationunit;
  921. break;
  922. case SLAPD_ERROR_LOG:
  923. LOG_ERROR_LOCK_WRITE( );
  924. loginfo.log_error_rotationtime = rtime;
  925. runit = loginfo.log_error_rotationunit;
  926. break;
  927. case SLAPD_AUDIT_LOG:
  928. LOG_AUDIT_LOCK_WRITE( );
  929. loginfo.log_audit_rotationtime = rtime;
  930. runit = loginfo.log_audit_rotationunit;
  931. break;
  932. }
  933. /* find out the rotation unit we have se right now */
  934. if (runit == LOG_UNIT_MONTHS) {
  935. value = 31 * 24 * 60 * 60 * rtime;
  936. } else if (runit == LOG_UNIT_WEEKS) {
  937. value = 7 * 24 * 60 * 60 * rtime;
  938. } else if (runit == LOG_UNIT_DAYS ) {
  939. value = 24 * 60 * 60 * rtime;
  940. } else if (runit == LOG_UNIT_HOURS) {
  941. value = 3600 * rtime;
  942. } else if (runit == LOG_UNIT_MINS) {
  943. value = 60 * rtime;
  944. } else {
  945. /* In this case we don't rotate */
  946. value = -1;
  947. }
  948. if (rtime > 0 && value < 0) {
  949. value = PR_INT32_MAX; /* overflown */
  950. }
  951. switch (logtype) {
  952. case SLAPD_ACCESS_LOG:
  953. fe_cfg->accesslog_rotationtime = rtime;
  954. loginfo.log_access_rotationtime_secs = value;
  955. LOG_ACCESS_UNLOCK_WRITE();
  956. break;
  957. case SLAPD_ERROR_LOG:
  958. fe_cfg->errorlog_rotationtime = rtime;
  959. loginfo.log_error_rotationtime_secs = value;
  960. LOG_ERROR_UNLOCK_WRITE();
  961. break;
  962. case SLAPD_AUDIT_LOG:
  963. fe_cfg->auditlog_rotationtime = rtime;
  964. loginfo.log_audit_rotationtime_secs = value;
  965. LOG_AUDIT_UNLOCK_WRITE();
  966. break;
  967. }
  968. return rv;
  969. }
  970. /******************************************************************************
  971. * ROTATION TIME UNIT
  972. * Return Values:
  973. * 1 -- fail
  974. * 0 -- success
  975. ******************************************************************************/
  976. int log_set_rotationtimeunit(const char *attrname, char *runit, int logtype, char *errorbuf, int apply)
  977. {
  978. int origvalue = 0, value = 0;
  979. int runitType;
  980. int rv = 0;
  981. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  982. if ( logtype != SLAPD_ACCESS_LOG &&
  983. logtype != SLAPD_ERROR_LOG &&
  984. logtype != SLAPD_AUDIT_LOG ) {
  985. PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  986. "%s: invalid log type: %d", attrname, logtype );
  987. return LDAP_OPERATIONS_ERROR;
  988. }
  989. if ( (strcasecmp(runit, "month") == 0) ||
  990. (strcasecmp(runit, "week") == 0) ||
  991. (strcasecmp(runit, "day") == 0) ||
  992. (strcasecmp(runit, "hour") == 0) ||
  993. (strcasecmp(runit, "minute") == 0)) {
  994. /* all good values */
  995. } else {
  996. PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  997. "%s: unknown unit \"%s\"", attrname, runit );
  998. rv = LDAP_OPERATIONS_ERROR;
  999. }
  1000. /* return if we aren't doing this for real */
  1001. if ( !apply ) {
  1002. return rv;
  1003. }
  1004. switch (logtype) {
  1005. case SLAPD_ACCESS_LOG:
  1006. LOG_ACCESS_LOCK_WRITE( );
  1007. origvalue = loginfo.log_access_rotationtime;
  1008. break;
  1009. case SLAPD_ERROR_LOG:
  1010. LOG_ERROR_LOCK_WRITE( );
  1011. origvalue = loginfo.log_error_rotationtime;
  1012. break;
  1013. case SLAPD_AUDIT_LOG:
  1014. LOG_AUDIT_LOCK_WRITE( );
  1015. origvalue = loginfo.log_audit_rotationtime;
  1016. break;
  1017. }
  1018. if (strcasecmp(runit, "month") == 0) {
  1019. runitType = LOG_UNIT_MONTHS;
  1020. value = origvalue * 31 * 24 * 60 * 60;
  1021. } else if (strcasecmp(runit, "week") == 0) {
  1022. runitType = LOG_UNIT_WEEKS;
  1023. value = origvalue * 7 * 24 * 60 * 60;
  1024. } else if (strcasecmp(runit, "day") == 0) {
  1025. runitType = LOG_UNIT_DAYS;
  1026. value = origvalue * 24 * 60 * 60;
  1027. } else if (strcasecmp(runit, "hour") == 0) {
  1028. runitType = LOG_UNIT_HOURS;
  1029. value = origvalue * 3600;
  1030. } else if (strcasecmp(runit, "minute") == 0) {
  1031. runitType = LOG_UNIT_MINS;
  1032. value = origvalue * 60;
  1033. } else {
  1034. /* In this case we don't rotate */
  1035. runitType = LOG_UNIT_UNKNOWN;
  1036. value = -1;
  1037. }
  1038. if (origvalue > 0 && value < 0) {
  1039. value = PR_INT32_MAX; /* overflown */
  1040. }
  1041. switch (logtype) {
  1042. case SLAPD_ACCESS_LOG:
  1043. loginfo.log_access_rotationtime_secs = value;
  1044. loginfo.log_access_rotationunit = runitType;
  1045. slapi_ch_free ( (void **) &fe_cfg->accesslog_rotationunit);
  1046. fe_cfg->accesslog_rotationunit = slapi_ch_strdup ( runit );
  1047. LOG_ACCESS_UNLOCK_WRITE();
  1048. break;
  1049. case SLAPD_ERROR_LOG:
  1050. loginfo.log_error_rotationtime_secs = value;
  1051. loginfo.log_error_rotationunit = runitType;
  1052. slapi_ch_free ( (void **) &fe_cfg->errorlog_rotationunit) ;
  1053. fe_cfg->errorlog_rotationunit = slapi_ch_strdup ( runit );
  1054. LOG_ERROR_UNLOCK_WRITE();
  1055. break;
  1056. case SLAPD_AUDIT_LOG:
  1057. loginfo.log_audit_rotationtime_secs = value;
  1058. loginfo.log_audit_rotationunit = runitType;
  1059. slapi_ch_free ( (void **) &fe_cfg->auditlog_rotationunit);
  1060. fe_cfg->auditlog_rotationunit = slapi_ch_strdup ( runit );
  1061. LOG_AUDIT_UNLOCK_WRITE();
  1062. break;
  1063. }
  1064. return rv;
  1065. }
  1066. /******************************************************************************
  1067. * MAXIMUM DISK SPACE
  1068. * Return Values:
  1069. * 1 -- fail
  1070. * 0 -- success
  1071. *
  1072. * NOTE:
  1073. * The config struct should contain the value in MB and not in bytes.
  1074. ******************************************************************************/
  1075. int
  1076. log_set_maxdiskspace(const char *attrname, char *maxdiskspace_str, int logtype, char *errorbuf, int apply)
  1077. {
  1078. int rv = 0;
  1079. PRInt64 mlogsize = 0; /* in bytes */
  1080. PRInt64 maxdiskspace; /* in bytes */
  1081. int s_maxdiskspace; /* in megabytes */
  1082. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  1083. if ( logtype != SLAPD_ACCESS_LOG &&
  1084. logtype != SLAPD_ERROR_LOG &&
  1085. logtype != SLAPD_AUDIT_LOG ) {
  1086. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  1087. "%s: invalid log type: %d", attrname, logtype );
  1088. return LDAP_OPERATIONS_ERROR;
  1089. }
  1090. if (!apply || !maxdiskspace_str || !*maxdiskspace_str)
  1091. return rv;
  1092. s_maxdiskspace = atoi(maxdiskspace_str);
  1093. /* Disk space are in MB but store in bytes */
  1094. switch (logtype) {
  1095. case SLAPD_ACCESS_LOG:
  1096. LOG_ACCESS_LOCK_WRITE( );
  1097. mlogsize = loginfo.log_access_maxlogsize;
  1098. break;
  1099. case SLAPD_ERROR_LOG:
  1100. LOG_ERROR_LOCK_WRITE( );
  1101. mlogsize = loginfo.log_error_maxlogsize;
  1102. break;
  1103. case SLAPD_AUDIT_LOG:
  1104. LOG_AUDIT_LOCK_WRITE( );
  1105. mlogsize = loginfo.log_audit_maxlogsize;
  1106. break;
  1107. }
  1108. maxdiskspace = (PRInt64)s_maxdiskspace * LOG_MB_IN_BYTES;
  1109. if (maxdiskspace < 0) {
  1110. maxdiskspace = -1;
  1111. } else if (maxdiskspace < mlogsize) {
  1112. rv = LDAP_OPERATIONS_ERROR;
  1113. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  1114. "%s: \"%d (MB)\" is less than max log size \"%d (MB)\"",
  1115. attrname, s_maxdiskspace, (int)(mlogsize/LOG_MB_IN_BYTES) );
  1116. }
  1117. switch (logtype) {
  1118. case SLAPD_ACCESS_LOG:
  1119. if (rv== 0 && apply) {
  1120. loginfo.log_access_maxdiskspace = maxdiskspace; /* in bytes */
  1121. fe_cfg->accesslog_maxdiskspace = s_maxdiskspace; /* in megabytes */
  1122. }
  1123. LOG_ACCESS_UNLOCK_WRITE();
  1124. break;
  1125. case SLAPD_ERROR_LOG:
  1126. if (rv== 0 && apply) {
  1127. loginfo.log_error_maxdiskspace = maxdiskspace; /* in bytes */
  1128. fe_cfg->errorlog_maxdiskspace = s_maxdiskspace; /* in megabytes */
  1129. }
  1130. LOG_ERROR_UNLOCK_WRITE();
  1131. break;
  1132. case SLAPD_AUDIT_LOG:
  1133. if (rv== 0 && apply) {
  1134. loginfo.log_audit_maxdiskspace = maxdiskspace; /* in bytes */
  1135. fe_cfg->auditlog_maxdiskspace = s_maxdiskspace; /* in megabytes */
  1136. }
  1137. LOG_AUDIT_UNLOCK_WRITE();
  1138. break;
  1139. }
  1140. return rv;
  1141. }
  1142. /******************************************************************************
  1143. * MINIMUM FREE SPACE
  1144. * Return Values:
  1145. * 1 -- fail
  1146. * 0 -- success
  1147. ******************************************************************************/
  1148. int
  1149. log_set_mindiskspace(const char *attrname, char *minfreespace_str, int logtype, char *errorbuf, int apply)
  1150. {
  1151. int rv=LDAP_SUCCESS;
  1152. int minfreespace; /* in megabytes */
  1153. PRInt64 minfreespaceB; /* in bytes */
  1154. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  1155. if ( logtype != SLAPD_ACCESS_LOG &&
  1156. logtype != SLAPD_ERROR_LOG &&
  1157. logtype != SLAPD_AUDIT_LOG ) {
  1158. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  1159. "%s: invalid log type: %d", attrname, logtype );
  1160. rv = LDAP_OPERATIONS_ERROR;
  1161. }
  1162. /* return if we aren't doing this for real */
  1163. if ( !apply || !minfreespace_str || !*minfreespace_str) {
  1164. return rv;
  1165. }
  1166. minfreespace = atoi(minfreespace_str);
  1167. /* Disk space are in MB but store in bytes */
  1168. if (minfreespace >= 1 ) {
  1169. minfreespaceB = (PRInt64)minfreespace * LOG_MB_IN_BYTES;
  1170. switch (logtype) {
  1171. case SLAPD_ACCESS_LOG:
  1172. LOG_ACCESS_LOCK_WRITE( );
  1173. loginfo.log_access_minfreespace = minfreespaceB;
  1174. fe_cfg->accesslog_minfreespace = minfreespace;
  1175. LOG_ACCESS_UNLOCK_WRITE();
  1176. break;
  1177. case SLAPD_ERROR_LOG:
  1178. LOG_ERROR_LOCK_WRITE( );
  1179. loginfo.log_error_minfreespace = minfreespaceB;
  1180. fe_cfg->errorlog_minfreespace = minfreespace;
  1181. LOG_ERROR_UNLOCK_WRITE();
  1182. break;
  1183. case SLAPD_AUDIT_LOG:
  1184. LOG_AUDIT_LOCK_WRITE( );
  1185. loginfo.log_audit_minfreespace = minfreespaceB;
  1186. fe_cfg->auditlog_minfreespace = minfreespace;
  1187. LOG_AUDIT_UNLOCK_WRITE();
  1188. break;
  1189. default:
  1190. rv = 1;
  1191. }
  1192. }
  1193. return rv;
  1194. }
  1195. /******************************************************************************
  1196. * LOG EXPIRATION TIME
  1197. * Return Values:
  1198. * 1 -- fail
  1199. * 0 -- success
  1200. ******************************************************************************/
  1201. int
  1202. log_set_expirationtime(const char *attrname, char *exptime_str, int logtype, char *errorbuf, int apply)
  1203. {
  1204. int eunit, value, exptime;
  1205. int rsec=0;
  1206. int rv = 0;
  1207. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  1208. if ( logtype != SLAPD_ACCESS_LOG &&
  1209. logtype != SLAPD_ERROR_LOG &&
  1210. logtype != SLAPD_AUDIT_LOG ) {
  1211. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  1212. "%s: invalid log type: %d", attrname, logtype );
  1213. rv = LDAP_OPERATIONS_ERROR;
  1214. }
  1215. /* return if we aren't doing this for real */
  1216. if ( !apply || !exptime_str || !*exptime_str) {
  1217. return rv;
  1218. }
  1219. exptime = atoi(exptime_str); /* <= 0: no exptime */
  1220. switch (logtype) {
  1221. case SLAPD_ACCESS_LOG:
  1222. LOG_ACCESS_LOCK_WRITE( );
  1223. loginfo.log_access_exptime = exptime;
  1224. eunit = loginfo.log_access_exptimeunit;
  1225. rsec = loginfo.log_access_rotationtime_secs;
  1226. break;
  1227. case SLAPD_ERROR_LOG:
  1228. LOG_ERROR_LOCK_WRITE( );
  1229. loginfo.log_error_exptime = exptime;
  1230. eunit = loginfo.log_error_exptimeunit;
  1231. rsec = loginfo.log_error_rotationtime_secs;
  1232. break;
  1233. case SLAPD_AUDIT_LOG:
  1234. LOG_AUDIT_LOCK_WRITE( );
  1235. loginfo.log_audit_exptime = exptime;
  1236. eunit = loginfo.log_audit_exptimeunit;
  1237. rsec = loginfo.log_audit_rotationtime_secs;
  1238. break;
  1239. default:
  1240. rv = 1;
  1241. eunit = -1;
  1242. }
  1243. value = -1; /* never expires, by default */
  1244. if (exptime > 0) {
  1245. if (eunit == LOG_UNIT_MONTHS) {
  1246. value = 31 * 24 * 60 * 60 * exptime;
  1247. } else if (eunit == LOG_UNIT_WEEKS) {
  1248. value = 7 * 24 * 60 * 60 * exptime;
  1249. } else if (eunit == LOG_UNIT_DAYS) {
  1250. value = 24 * 60 * 60 * exptime;
  1251. }
  1252. }
  1253. if (value > 0 && value < rsec) {
  1254. value = rsec;
  1255. } else if (exptime > 0 && value < -1) {
  1256. /* value is overflown */
  1257. value = PR_INT32_MAX;
  1258. }
  1259. switch (logtype) {
  1260. case SLAPD_ACCESS_LOG:
  1261. loginfo.log_access_exptime_secs = value;
  1262. fe_cfg->accesslog_exptime = exptime;
  1263. LOG_ACCESS_UNLOCK_WRITE();
  1264. break;
  1265. case SLAPD_ERROR_LOG:
  1266. loginfo.log_error_exptime_secs = value;
  1267. fe_cfg->errorlog_exptime = exptime;
  1268. LOG_ERROR_UNLOCK_WRITE();
  1269. break;
  1270. case SLAPD_AUDIT_LOG:
  1271. loginfo.log_audit_exptime_secs = value;
  1272. fe_cfg->auditlog_exptime = exptime;
  1273. LOG_AUDIT_UNLOCK_WRITE();
  1274. break;
  1275. default:
  1276. rv = 1;
  1277. }
  1278. return rv;
  1279. }
  1280. /******************************************************************************
  1281. * LOG EXPIRATION TIME UNIT
  1282. * Return Values:
  1283. * 1 -- fail
  1284. * 0 -- success
  1285. ******************************************************************************/
  1286. int
  1287. log_set_expirationtimeunit(const char *attrname, char *expunit, int logtype, char *errorbuf, int apply)
  1288. {
  1289. int value = 0;
  1290. int rv = 0;
  1291. int exptime = 0, rsecs = 0;
  1292. int *exptimeunitp = NULL;
  1293. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  1294. if ( logtype != SLAPD_ACCESS_LOG &&
  1295. logtype != SLAPD_ERROR_LOG &&
  1296. logtype != SLAPD_AUDIT_LOG ) {
  1297. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  1298. "%s: invalid log type: %d", attrname, logtype );
  1299. return LDAP_OPERATIONS_ERROR;
  1300. }
  1301. if ( NULL == expunit ) {
  1302. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  1303. "%s: NULL value", attrname );
  1304. return LDAP_OPERATIONS_ERROR;
  1305. }
  1306. if ( (strcasecmp(expunit, "month") == 0) ||
  1307. (strcasecmp(expunit, "week") == 0) ||
  1308. (strcasecmp(expunit, "day") == 0)) {
  1309. /* we have good values */
  1310. } else {
  1311. PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
  1312. "%s: invalid time unit \"%s\"", attrname, expunit );
  1313. rv = LDAP_OPERATIONS_ERROR;;
  1314. }
  1315. /* return if we aren't doing this for real */
  1316. if ( !apply ) {
  1317. return rv;
  1318. }
  1319. switch (logtype) {
  1320. case SLAPD_ACCESS_LOG:
  1321. LOG_ACCESS_LOCK_WRITE( );
  1322. exptime = loginfo.log_access_exptime;
  1323. rsecs = loginfo.log_access_rotationtime_secs;
  1324. exptimeunitp = &(loginfo.log_access_exptimeunit);
  1325. break;
  1326. case SLAPD_ERROR_LOG:
  1327. LOG_ERROR_LOCK_WRITE( );
  1328. exptime = loginfo.log_error_exptime;
  1329. rsecs = loginfo.log_error_rotationtime_secs;
  1330. exptimeunitp = &(loginfo.log_error_exptimeunit);
  1331. break;
  1332. case SLAPD_AUDIT_LOG:
  1333. LOG_AUDIT_LOCK_WRITE( );
  1334. exptime = loginfo.log_audit_exptime;
  1335. rsecs = loginfo.log_audit_rotationtime_secs;
  1336. exptimeunitp = &(loginfo.log_audit_exptimeunit);
  1337. break;
  1338. }
  1339. value = -1;
  1340. if (strcasecmp(expunit, "month") == 0) {
  1341. if (exptime > 0) {
  1342. value = 31 * 24 * 60 * 60 * exptime;
  1343. }
  1344. if (exptimeunitp) {
  1345. *exptimeunitp = LOG_UNIT_MONTHS;
  1346. }
  1347. } else if (strcasecmp(expunit, "week") == 0) {
  1348. if (exptime > 0) {
  1349. value = 7 * 24 * 60 * 60 * exptime;
  1350. }
  1351. if (exptimeunitp) {
  1352. *exptimeunitp = LOG_UNIT_WEEKS;
  1353. }
  1354. } else if (strcasecmp(expunit, "day") == 0) {
  1355. if (exptime > 0) {
  1356. value = 24 * 60 * 60 * exptime;
  1357. }
  1358. if (exptimeunitp) {
  1359. *exptimeunitp = LOG_UNIT_DAYS;
  1360. }
  1361. }
  1362. if ((value > 0) && value < rsecs) {
  1363. value = rsecs;
  1364. }
  1365. switch (logtype) {
  1366. case SLAPD_ACCESS_LOG:
  1367. loginfo.log_access_exptime_secs = value;
  1368. slapi_ch_free ( (void **) &(fe_cfg->accesslog_exptimeunit) );
  1369. fe_cfg->accesslog_exptimeunit = slapi_ch_strdup ( expunit );
  1370. LOG_ACCESS_UNLOCK_WRITE();
  1371. break;
  1372. case SLAPD_ERROR_LOG:
  1373. loginfo.log_error_exptime_secs = value;
  1374. slapi_ch_free ( (void **) &(fe_cfg->errorlog_exptimeunit) );
  1375. fe_cfg->errorlog_exptimeunit = slapi_ch_strdup ( expunit );
  1376. LOG_ERROR_UNLOCK_WRITE();
  1377. break;
  1378. case SLAPD_AUDIT_LOG:
  1379. loginfo.log_audit_exptime_secs = value;
  1380. slapi_ch_free ( (void **) &(fe_cfg->auditlog_exptimeunit) );
  1381. fe_cfg->auditlog_exptimeunit = slapi_ch_strdup ( expunit );
  1382. LOG_AUDIT_UNLOCK_WRITE();
  1383. break;
  1384. }
  1385. return rv;
  1386. }
  1387. /******************************************************************************
  1388. * Write title line in log file
  1389. *****************************************************************************/
  1390. static void
  1391. log_write_title (LOGFD fp)
  1392. {
  1393. slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
  1394. char *buildnum = config_get_buildnum();
  1395. char buff[512];
  1396. int bufflen = sizeof(buff);
  1397. PR_snprintf(buff, bufflen, "\t%s B%s\n",
  1398. fe_cfg->versionstring ? fe_cfg->versionstring : CAPBRAND "-Directory/" DS_PACKAGE_VERSION,
  1399. buildnum ? buildnum : "");
  1400. LOG_WRITE_NOW_NO_ERR(fp, buff, strlen(buff), 0);
  1401. if (fe_cfg->localhost) {
  1402. PR_snprintf(buff, bufflen, "\t%s:%d (%s)\n\n",
  1403. fe_cfg->localhost,
  1404. fe_cfg->security ? fe_cfg->secureport : fe_cfg->port,
  1405. fe_cfg->configdir ? fe_cfg->configdir : "");
  1406. }
  1407. else {
  1408. /* If fe_cfg->localhost is not set, ignore fe_cfg->port since
  1409. * it is the default and might be misleading.
  1410. */
  1411. PR_snprintf(buff, bufflen, "\t<host>:<port> (%s)\n\n",
  1412. fe_cfg->configdir ? fe_cfg->configdir : "");
  1413. }
  1414. LOG_WRITE_NOW_NO_ERR(fp, buff, strlen(buff), 0);
  1415. slapi_ch_free((void **)&buildnum);
  1416. }
  1417. /******************************************************************************
  1418. * init function for the error log
  1419. * Returns:
  1420. * 0 - success
  1421. * 1 - fail
  1422. ******************************************************************************/
  1423. int error_log_openf( char *pathname, int locked)
  1424. {
  1425. int rv = 0;
  1426. int logfile_type =0;
  1427. if (!locked) LOG_ERROR_LOCK_WRITE ();
  1428. /* save the file name */
  1429. slapi_ch_free_string(&loginfo.log_error_file);
  1430. loginfo.log_error_file = slapi_ch_strdup(pathname);
  1431. /* store the rotation info fiel path name */
  1432. slapi_ch_free_string(&loginfo.log_errorinfo_file);
  1433. loginfo.log_errorinfo_file = slapi_ch_smprintf("%s.rotationinfo", pathname);
  1434. /*
  1435. ** Check if we have a log file already. If we have it then
  1436. ** we need to parse the header info and update the loginfo
  1437. ** struct.
  1438. */
  1439. logfile_type = log__error_rotationinfof(loginfo.log_errorinfo_file);
  1440. if (log__open_errorlogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
  1441. rv = 1;
  1442. }
  1443. if (!locked) LOG_ERROR_UNLOCK_WRITE();
  1444. return rv;
  1445. }
  1446. /******************************************************************************
  1447. * init function for the audit log
  1448. * Returns:
  1449. * 0 - success
  1450. * 1 - fail
  1451. ******************************************************************************/
  1452. int
  1453. audit_log_openf( char *pathname, int locked)
  1454. {
  1455. int rv=0;
  1456. int logfile_type = 0;
  1457. if (!locked) LOG_AUDIT_LOCK_WRITE( );
  1458. /* store the path name */
  1459. slapi_ch_free_string(&loginfo.log_audit_file);
  1460. loginfo.log_audit_file = slapi_ch_strdup ( pathname );
  1461. /* store the rotation info file path name */
  1462. slapi_ch_free_string(&loginfo.log_auditinfo_file);
  1463. loginfo.log_auditinfo_file = slapi_ch_smprintf("%s.rotationinfo", pathname);
  1464. /*
  1465. ** Check if we have a log file already. If we have it then
  1466. ** we need to parse the header info and update the loginfo
  1467. ** struct.
  1468. */
  1469. logfile_type = log__audit_rotationinfof(loginfo.log_auditinfo_file);
  1470. if (log__open_auditlogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
  1471. rv = 1;
  1472. }
  1473. if (!locked) LOG_AUDIT_UNLOCK_WRITE();
  1474. return rv;
  1475. }
  1476. /******************************************************************************
  1477. * write in the audit log
  1478. ******************************************************************************/
  1479. int
  1480. slapd_log_audit_proc (
  1481. char *buffer,
  1482. int buf_len)
  1483. {
  1484. if ( (loginfo.log_audit_state & LOGGING_ENABLED) && (loginfo.log_audit_file != NULL) ){
  1485. LOG_AUDIT_LOCK_WRITE( );
  1486. if (log__needrotation(loginfo.log_audit_fdes,
  1487. SLAPD_AUDIT_LOG) == LOG_ROTATE) {
  1488. if (log__open_auditlogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
  1489. LDAPDebug(LDAP_DEBUG_ANY,
  1490. "LOGINFO: Unable to open audit file:%s\n",
  1491. loginfo.log_audit_file,0,0);
  1492. LOG_AUDIT_UNLOCK_WRITE();
  1493. return 0;
  1494. }
  1495. while (loginfo.log_audit_rotationsyncclock <= loginfo.log_audit_ctime) {
  1496. loginfo.log_audit_rotationsyncclock += PR_ABS(loginfo.log_audit_rotationtime_secs);
  1497. }
  1498. }
  1499. if (loginfo.log_audit_state & LOGGING_NEED_TITLE) {
  1500. log_write_title( loginfo.log_audit_fdes);
  1501. loginfo.log_audit_state &= ~LOGGING_NEED_TITLE;
  1502. }
  1503. LOG_WRITE_NOW_NO_ERR(loginfo.log_audit_fdes, buffer, buf_len, 0);
  1504. LOG_AUDIT_UNLOCK_WRITE();
  1505. return 0;
  1506. }
  1507. return 0;
  1508. }
  1509. /******************************************************************************
  1510. * write in the error log
  1511. ******************************************************************************/
  1512. int
  1513. slapd_log_error_proc(
  1514. char *subsystem, /* omitted if NULL */
  1515. char *fmt,
  1516. ... )
  1517. {
  1518. va_list ap_err;
  1519. va_list ap_file;
  1520. va_start( ap_err, fmt );
  1521. va_start( ap_file, fmt );
  1522. slapd_log_error_proc_internal(subsystem, fmt, ap_err, ap_file);
  1523. va_end(ap_err);
  1524. va_end(ap_file);
  1525. return 0;
  1526. }
  1527. static int
  1528. slapd_log_error_proc_internal(
  1529. char *subsystem, /* omitted if NULL */
  1530. char *fmt,
  1531. va_list ap_err,
  1532. va_list ap_file)
  1533. {
  1534. int rc = 0;
  1535. if ( (loginfo.log_error_state & LOGGING_ENABLED) && (loginfo.log_error_file != NULL) ) {
  1536. LOG_ERROR_LOCK_WRITE( );
  1537. if (log__needrotation(loginfo.log_error_fdes,
  1538. SLAPD_ERROR_LOG) == LOG_ROTATE) {
  1539. if (log__open_errorlogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
  1540. LOG_ERROR_UNLOCK_WRITE();
  1541. /* shouldn't continue. error is syslog'ed in open_errorlogfile */
  1542. g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
  1543. return 0;
  1544. }
  1545. while (loginfo.log_error_rotationsyncclock <= loginfo.log_error_ctime) {
  1546. loginfo.log_error_rotationsyncclock += PR_ABS(loginfo.log_error_rotationtime_secs);
  1547. }
  1548. }
  1549. if (!(detached)) {
  1550. rc = vslapd_log_error( NULL, subsystem, fmt, ap_err, 1 );
  1551. }
  1552. if ( loginfo.log_error_fdes != NULL ) {
  1553. if (loginfo.log_error_state & LOGGING_NEED_TITLE) {
  1554. log_write_title(loginfo.log_error_fdes);
  1555. loginfo.log_error_state &= ~LOGGING_NEED_TITLE;
  1556. }
  1557. rc = vslapd_log_error( loginfo.log_error_fdes, subsystem, fmt, ap_file, 1 );
  1558. }
  1559. LOG_ERROR_UNLOCK_WRITE();
  1560. } else {
  1561. /* log the problem in the stderr */
  1562. rc = vslapd_log_error( NULL, subsystem, fmt, ap_err, 0 );
  1563. }
  1564. return( rc );
  1565. }
  1566. /*
  1567. * Directly write the already formatted message to the error log
  1568. */
  1569. static void
  1570. vslapd_log_emergency_error(LOGFD fp, const char *msg, int locked)
  1571. {
  1572. time_t tnl;
  1573. long tz;
  1574. struct tm *tmsp, tms;
  1575. char tbuf[ TBUFSIZE ];
  1576. char buffer[SLAPI_LOG_BUFSIZ];
  1577. char sign;
  1578. int size;
  1579. tnl = current_time();
  1580. (void)localtime_r( &tnl, &tms );
  1581. tmsp = &tms;
  1582. #ifdef BSD_TIME
  1583. tz = tmsp->tm_gmtoff;
  1584. #else /* BSD_TIME */
  1585. tz = - timezone;
  1586. if ( tmsp->tm_isdst ) {
  1587. tz += 3600;
  1588. }
  1589. #endif /* BSD_TIME */
  1590. sign = ( tz >= 0 ? '+' : '-' );
  1591. if ( tz < 0 ) {
  1592. tz = -tz;
  1593. }
  1594. (void)strftime( tbuf, (size_t)TBUFSIZE, "%d/%b/%Y:%H:%M:%S", tmsp);
  1595. sprintf( buffer, "[%s %c%02d%02d] - %s", tbuf, sign, (int)( tz / 3600 ), (int)( tz % 3600 ), msg);
  1596. size = strlen(buffer);
  1597. if(!locked)
  1598. LOG_ERROR_LOCK_WRITE();
  1599. slapi_write_buffer((fp), (buffer), (size));
  1600. PR_Sync(fp);
  1601. if(!locked)
  1602. LOG_ERROR_UNLOCK_WRITE();
  1603. }
  1604. static int
  1605. vslapd_log_error(
  1606. LOGFD fp,
  1607. char *subsystem, /* omitted if NULL */
  1608. char *fmt,
  1609. va_list ap,
  1610. int locked )
  1611. {
  1612. time_t tnl;
  1613. long tz;
  1614. struct tm *tmsp, tms;
  1615. char tbuf[ TBUFSIZE ];
  1616. char sign;
  1617. char buffer[SLAPI_LOG_BUFSIZ];
  1618. int blen;
  1619. char *vbuf;
  1620. int header_len = 0;
  1621. int err = 0;
  1622. tnl = current_time();
  1623. (void)localtime_r( &tnl, &tms );
  1624. tmsp = &tms;
  1625. #ifdef BSD_TIME
  1626. tz = tmsp->tm_gmtoff;
  1627. #else /* BSD_TIME */
  1628. tz = - timezone;
  1629. if ( tmsp->tm_isdst ) {
  1630. tz += 3600;
  1631. }
  1632. #endif /* BSD_TIME */
  1633. sign = ( tz >= 0 ? '+' : '-' );
  1634. if ( tz < 0 ) {
  1635. tz = -tz;
  1636. }
  1637. (void)strftime( tbuf, (size_t)TBUFSIZE, "%d/%b/%Y:%H:%M:%S", tmsp);
  1638. sprintf( buffer, "[%s %c%02d%02d]%s%s - ", tbuf, sign,
  1639. (int)( tz / 3600 ), (int)( tz % 3600 ),
  1640. subsystem ? " " : "",
  1641. subsystem ? subsystem : "");
  1642. /* Bug 561525: to be able to remove timestamp to not over pollute syslog, we may need
  1643. to skip the timestamp part of the message.
  1644. The size of the header is:
  1645. the size of the time string
  1646. + size of space
  1647. + size of one char (sign)
  1648. + size of 2 char
  1649. + size of 2 char
  1650. + size of [
  1651. + size of ]
  1652. */
  1653. header_len = strlen(tbuf) + 8;
  1654. if ((vbuf = PR_vsmprintf(fmt, ap)) == NULL) {
  1655. return -1;
  1656. }
  1657. blen = strlen(buffer);
  1658. PR_snprintf (buffer+blen, sizeof(buffer)-blen, "%s", vbuf);
  1659. buffer[sizeof(buffer)-1] = '\0';
  1660. if (fp)
  1661. #if 0
  1662. LOG_WRITE_NOW(fp, buffer, strlen(buffer), header_len, err);
  1663. #else
  1664. do {
  1665. int size = strlen(buffer);
  1666. (err) = 0;
  1667. if ( slapi_write_buffer((fp), (buffer), (size)) != (size) )
  1668. {
  1669. PRErrorCode prerr = PR_GetError();
  1670. syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer)+(header_len) );
  1671. (err) = prerr;
  1672. }
  1673. /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */
  1674. PR_Sync(fp);
  1675. } while (0);
  1676. #endif
  1677. else /* stderr is always unbuffered */
  1678. fprintf(stderr, "%s", buffer);
  1679. if (err) {
  1680. PR_snprintf(buffer, sizeof(buffer),
  1681. "Writing to the errors log failed. Exiting...");
  1682. log__error_emergency(buffer, 1, locked);
  1683. /* failed to write to the errors log. should not continue. */
  1684. g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
  1685. }
  1686. PR_smprintf_free (vbuf);
  1687. return( 0 );
  1688. }
  1689. int
  1690. slapi_log_error( int severity, char *subsystem, char *fmt, ... )
  1691. {
  1692. va_list ap1;
  1693. va_list ap2;
  1694. int rc;
  1695. if ( severity < SLAPI_LOG_MIN || severity > SLAPI_LOG_MAX ) {
  1696. (void)slapd_log_error_proc( subsystem,
  1697. "slapi_log_error: invalid severity %d (message %s)\n",
  1698. severity, fmt );
  1699. return( -1 );
  1700. }
  1701. if ( slapd_ldap_debug & slapi_log_map[ severity ] ) {
  1702. va_start( ap1, fmt );
  1703. va_start( ap2, fmt );
  1704. rc = slapd_log_error_proc_internal( subsystem, fmt, ap1, ap2 );
  1705. va_end( ap1 );
  1706. va_end( ap2 );
  1707. } else {
  1708. rc = 0; /* nothing to be logged --> always return success */
  1709. }
  1710. return( rc );
  1711. }
  1712. int
  1713. slapi_log_error_ext(int severity, char *subsystem, char *fmt, va_list varg1, va_list varg2)
  1714. {
  1715. int rc = 0;
  1716. if ( severity < SLAPI_LOG_MIN || severity > SLAPI_LOG_MAX ) {
  1717. (void)slapd_log_error_proc( subsystem, "slapi_log_error: invalid severity %d (message %s)\n",
  1718. severity, fmt );
  1719. return( -1 );
  1720. }
  1721. if ( slapd_ldap_debug & slapi_log_map[ severity ] )
  1722. {
  1723. rc = slapd_log_error_proc_internal( subsystem, fmt, varg1, varg2 );
  1724. } else {
  1725. rc = 0; /* nothing to be logged --> always return success */
  1726. }
  1727. return( rc );
  1728. }
  1729. int
  1730. slapi_is_loglevel_set ( const int loglevel )
  1731. {
  1732. return ( slapd_ldap_debug & slapi_log_map[ loglevel ] ? 1 : 0);
  1733. }
  1734. /******************************************************************************
  1735. * write in the access log
  1736. ******************************************************************************/
  1737. static int vslapd_log_access(char *fmt, va_list ap)
  1738. {
  1739. time_t tnl;
  1740. long tz;
  1741. struct tm *tmsp, tms;
  1742. char tbuf[ TBUFSIZE ];
  1743. char sign;
  1744. char buffer[SLAPI_LOG_BUFSIZ];
  1745. char vbuf[SLAPI_LOG_BUFSIZ];
  1746. int blen, vlen;
  1747. /* info needed to keep us from calling localtime/strftime so often: */
  1748. static time_t old_time = 0;
  1749. static char old_tbuf[SLAPI_LOG_BUFSIZ];
  1750. static int old_blen = 0;
  1751. tnl = current_time();
  1752. /* check if we can use the old strftime buffer */
  1753. PR_Lock(ts_time_lock);
  1754. if (tnl == old_time) {
  1755. strcpy(buffer, old_tbuf);
  1756. blen = old_blen;
  1757. PR_Unlock(ts_time_lock);
  1758. } else {
  1759. /* nope... painstakingly create the new strftime buffer */
  1760. (void)localtime_r( &tnl, &tms );
  1761. tmsp = &tms;
  1762. #ifdef BSD_TIME
  1763. tz = tmsp->tm_gmtoff;
  1764. #else /* BSD_TIME */
  1765. tz = - timezone;
  1766. if ( tmsp->tm_isdst ) {
  1767. tz += 3600;
  1768. }
  1769. #endif /* BSD_TIME */
  1770. sign = ( tz >= 0 ? '+' : '-' );
  1771. if ( tz < 0 ) {
  1772. tz = -tz;
  1773. }
  1774. (void)strftime( tbuf, (size_t)TBUFSIZE, "%d/%b/%Y:%H:%M:%S", tmsp);
  1775. sprintf( buffer, "[%s %c%02d%02d] ", tbuf, sign,
  1776. (int)( tz / 3600 ), (int)( tz % 3600));
  1777. old_time = tnl;
  1778. strcpy(old_tbuf, buffer);
  1779. blen = strlen(buffer);
  1780. old_blen = blen;
  1781. PR_Unlock(ts_time_lock);
  1782. }
  1783. vlen = PR_vsnprintf(vbuf, SLAPI_LOG_BUFSIZ, fmt, ap);
  1784. if (! vlen) {
  1785. return -1;
  1786. }
  1787. if (SLAPI_LOG_BUFSIZ - blen < vlen) {
  1788. return -1;
  1789. }
  1790. log_append_buffer2(tnl, loginfo.log_access_buffer, buffer, blen, vbuf, vlen);
  1791. return( 0 );
  1792. }
  1793. int
  1794. slapi_log_access( int level,
  1795. char *fmt,
  1796. ... )
  1797. {
  1798. va_list ap;
  1799. int rc=0;
  1800. if (!(loginfo.log_access_state & LOGGING_ENABLED)) {
  1801. return 0;
  1802. }
  1803. va_start( ap, fmt );
  1804. if (( level & loginfo.log_access_level ) &&
  1805. ( loginfo.log_access_fdes != NULL ) && (loginfo.log_access_file != NULL) ) {
  1806. rc = vslapd_log_access(fmt, ap);
  1807. }
  1808. va_end( ap );
  1809. return( rc );
  1810. }
  1811. /******************************************************************************
  1812. * access_log_openf
  1813. *
  1814. * Open the access log file
  1815. *
  1816. * Returns:
  1817. * 0 -- success
  1818. * 1 -- fail
  1819. ******************************************************************************/
  1820. int access_log_openf(char *pathname, int locked)
  1821. {
  1822. int rv=0;
  1823. int logfile_type = 0;
  1824. if (!locked) LOG_ACCESS_LOCK_WRITE( );
  1825. /* store the path name */
  1826. slapi_ch_free_string(&loginfo.log_access_file);
  1827. loginfo.log_access_file = slapi_ch_strdup ( pathname );
  1828. /* store the rotation info fiel path name */
  1829. slapi_ch_free_string(&loginfo.log_accessinfo_file);
  1830. loginfo.log_accessinfo_file = slapi_ch_smprintf("%s.rotationinfo", pathname);
  1831. /*
  1832. ** Check if we have a log file already. If we have it then
  1833. ** we need to parse the header info and update the loginfo
  1834. ** struct.
  1835. */
  1836. logfile_type = log__access_rotationinfof(loginfo.log_accessinfo_file);
  1837. if (log__open_accesslogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
  1838. rv = 1;
  1839. }
  1840. if (!locked) LOG_ACCESS_UNLOCK_WRITE();
  1841. return rv;
  1842. }
  1843. /******************************************************************************
  1844. * log__open_accesslogfile
  1845. *
  1846. * Open a new log file. If we have run out of the max logs we can have
  1847. * then delete the oldest file.
  1848. ******************************************************************************/
  1849. static int
  1850. log__open_accesslogfile(int logfile_state, int locked)
  1851. {
  1852. time_t now;
  1853. LOGFD fp;
  1854. LOGFD fpinfo = NULL;
  1855. char tbuf[TBUFSIZE];
  1856. struct logfileinfo *logp;
  1857. char buffer[BUFSIZ];
  1858. if (!locked) LOG_ACCESS_LOCK_WRITE( );
  1859. /*
  1860. ** Here we are trying to create a new log file.
  1861. ** If we alredy have one, then we need to rename it as
  1862. ** "filename.time", close it and update it's information
  1863. ** in the array stack.
  1864. */
  1865. if (loginfo.log_access_fdes != NULL) {
  1866. struct logfileinfo *log;
  1867. char newfile[BUFSIZ];
  1868. PRInt64 f_size;
  1869. /* get rid of the old one */
  1870. if ((f_size = log__getfilesize(loginfo.log_access_fdes)) == -1) {
  1871. /* Then assume that we have the max size (in bytes) */
  1872. f_size = loginfo.log_access_maxlogsize;
  1873. }
  1874. /* Check if I have to delete any old file, delete it if it is required.
  1875. ** If there is just one file, then access and access.rotation files
  1876. ** are deleted. After that we start fresh
  1877. */
  1878. while (log__delete_access_logfile());
  1879. /* close the file */
  1880. LOG_CLOSE(loginfo.log_access_fdes);
  1881. /*
  1882. * loginfo.log_access_fdes is not set to NULL here, otherwise
  1883. * slapi_log_access() will not send a message to the access log
  1884. * if it is called between this point and where this field is
  1885. * set again after calling LOG_OPEN_APPEND.
  1886. */
  1887. if ( loginfo.log_access_maxnumlogs > 1 ) {
  1888. log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
  1889. log->l_ctime = loginfo.log_access_ctime;
  1890. log->l_size = f_size;
  1891. log_convert_time (log->l_ctime, tbuf, 1 /*short */);
  1892. PR_snprintf(newfile, sizeof(newfile), "%s.%s", loginfo.log_access_file, tbuf);
  1893. if (PR_Rename (loginfo.log_access_file, newfile) != PR_SUCCESS) {
  1894. PRErrorCode prerr = PR_GetError();
  1895. /* Make "FILE EXISTS" error an exception.
  1896. Even if PR_Rename fails with the error, we continue logging.
  1897. */
  1898. if (PR_FILE_EXISTS_ERROR != prerr) {
  1899. loginfo.log_access_fdes = NULL;
  1900. if (!locked) LOG_ACCESS_UNLOCK_WRITE();
  1901. slapi_ch_free((void**)&log);
  1902. return LOG_UNABLE_TO_OPENFILE;
  1903. }
  1904. }
  1905. /* add the log to the chain */
  1906. log->l_next = loginfo.log_access_logchain;
  1907. loginfo.log_access_logchain = log;
  1908. loginfo.log_numof_access_logs++;
  1909. }
  1910. }
  1911. /* open a new log file */
  1912. if (! LOG_OPEN_APPEND(fp, loginfo.log_access_file, loginfo.log_access_mode)) {
  1913. int oserr = errno;
  1914. loginfo.log_access_fdes = NULL;
  1915. if (!locked) LOG_ACCESS_UNLOCK_WRITE();
  1916. LDAPDebug(LDAP_DEBUG_ANY, "access file open %s failed errno %d (%s)\n",
  1917. loginfo.log_access_file, oserr, slapd_system_strerror(oserr));
  1918. return LOG_UNABLE_TO_OPENFILE;
  1919. }
  1920. loginfo.log_access_fdes = fp;
  1921. if (logfile_state == LOGFILE_REOPENED) {
  1922. /* we have all the information */
  1923. if (!locked) LOG_ACCESS_UNLOCK_WRITE( );
  1924. return LOG_SUCCESS;
  1925. }
  1926. loginfo.log_access_state |= LOGGING_NEED_TITLE;
  1927. if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_accessinfo_file, loginfo.log_access_mode)) {
  1928. int oserr = errno;
  1929. if (!locked) LOG_ACCESS_UNLOCK_WRITE();
  1930. LDAPDebug( LDAP_DEBUG_ANY, "accessinfo file open %s failed errno %d (%s)\n",
  1931. loginfo.log_accessinfo_file,
  1932. oserr, slapd_system_strerror(oserr));
  1933. return LOG_UNABLE_TO_OPENFILE;
  1934. }
  1935. /* write the header in the log */
  1936. now = current_time();
  1937. log_convert_time (now, tbuf, 2 /* long */);
  1938. PR_snprintf (buffer,sizeof(buffer),"LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
  1939. LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
  1940. logp = loginfo.log_access_logchain;
  1941. while ( logp) {
  1942. log_convert_time (logp->l_ctime, tbuf, 1 /*short*/);
  1943. PR_snprintf(buffer, sizeof(buffer), "LOGINFO:%s%s.%s (%lu) (%"
  1944. NSPRI64 "d)\n", PREVLOGFILE, loginfo.log_access_file, tbuf,
  1945. logp->l_ctime, logp->l_size);
  1946. LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
  1947. logp = logp->l_next;
  1948. }
  1949. /* Close the info file. We need only when we need to rotate to the
  1950. ** next log file.
  1951. */
  1952. if (fpinfo) LOG_CLOSE(fpinfo);
  1953. /* This is now the current access log */
  1954. loginfo.log_access_ctime = now;
  1955. if (!locked) LOG_ACCESS_UNLOCK_WRITE( );
  1956. return LOG_SUCCESS;
  1957. }
  1958. /******************************************************************************
  1959. * log__needrotation
  1960. *
  1961. * Do we need to rotate the log file ?
  1962. * Find out based on rotation time and the max log size;
  1963. *
  1964. * Return:
  1965. * LOG_CONTINUE -- Use the same one
  1966. * LOG_ROTATE -- log need to be rotated
  1967. *
  1968. * Note:
  1969. * A READ LOCK is obtained.
  1970. ********************************************************************************/
  1971. #define LOG_SIZE_EXCEEDED 1
  1972. #define LOG_EXPIRED 2
  1973. static int
  1974. log__needrotation(LOGFD fp, int logtype)
  1975. {
  1976. time_t curr_time;
  1977. time_t log_createtime= 0;
  1978. time_t syncclock = 0;
  1979. int type = LOG_CONTINUE;
  1980. PRInt64 f_size = 0;
  1981. PRInt64 maxlogsize;
  1982. int nlogs;
  1983. int rotationtime_secs = -1;
  1984. int sync_enabled = 0, timeunit = 0;
  1985. if (fp == NULL) {
  1986. return LOG_ROTATE;
  1987. }
  1988. switch (logtype) {
  1989. case SLAPD_ACCESS_LOG:
  1990. nlogs = loginfo.log_access_maxnumlogs;
  1991. maxlogsize = loginfo.log_access_maxlogsize;
  1992. sync_enabled = loginfo.log_access_rotationsync_enabled;
  1993. syncclock = loginfo.log_access_rotationsyncclock;
  1994. timeunit = loginfo.log_access_rotationunit;
  1995. rotationtime_secs = loginfo.log_access_rotationtime_secs;
  1996. log_createtime = loginfo.log_access_ctime;
  1997. break;
  1998. case SLAPD_ERROR_LOG:
  1999. nlogs = loginfo.log_error_maxnumlogs;
  2000. maxlogsize = loginfo.log_error_maxlogsize;
  2001. sync_enabled = loginfo.log_error_rotationsync_enabled;
  2002. syncclock = loginfo.log_error_rotationsyncclock;
  2003. timeunit = loginfo.log_error_rotationunit;
  2004. rotationtime_secs = loginfo.log_error_rotationtime_secs;
  2005. log_createtime = loginfo.log_error_ctime;
  2006. break;
  2007. case SLAPD_AUDIT_LOG:
  2008. nlogs = loginfo.log_audit_maxnumlogs;
  2009. maxlogsize = loginfo.log_audit_maxlogsize;
  2010. sync_enabled = loginfo.log_audit_rotationsync_enabled;
  2011. syncclock = loginfo.log_audit_rotationsyncclock;
  2012. timeunit = loginfo.log_audit_rotationunit;
  2013. rotationtime_secs = loginfo.log_audit_rotationtime_secs;
  2014. log_createtime = loginfo.log_audit_ctime;
  2015. break;
  2016. default: /* error */
  2017. maxlogsize = -1;
  2018. nlogs = 1;
  2019. }
  2020. /* If we have one log then can't rotate at all */
  2021. if (nlogs == 1)
  2022. return LOG_CONTINUE;
  2023. if ((f_size = log__getfilesize(fp)) == -1) {
  2024. /* The next option is to rotate based on the rotation time */
  2025. f_size = 0;
  2026. }
  2027. /* If the log size is more than the limit, then it's time to rotate. */
  2028. if ((maxlogsize > 0) && (f_size >= maxlogsize)) {
  2029. type = LOG_SIZE_EXCEEDED;
  2030. goto log_rotate;
  2031. }
  2032. /* If rotation interval <= 0 then can't rotate by time */
  2033. if (rotationtime_secs <= 0)
  2034. return LOG_CONTINUE;
  2035. /*
  2036. ** If the log is older than the time allowed to be active,
  2037. ** then it's time to move on (i.e., rotate).
  2038. */
  2039. time (&curr_time);
  2040. if ( !sync_enabled || timeunit == LOG_UNIT_HOURS || timeunit == LOG_UNIT_MINS ) {
  2041. if (curr_time - log_createtime > rotationtime_secs) {
  2042. type = LOG_EXPIRED;
  2043. goto log_rotate;
  2044. }
  2045. } else if (curr_time > syncclock) {
  2046. type = LOG_EXPIRED;
  2047. goto log_rotate;
  2048. }
  2049. log_rotate:
  2050. /*
  2051. ** Don't send messages to the error log whilst we're rotating it.
  2052. ** This'll lead to a recursive call to the logging function, and
  2053. ** an assertion trying to relock the write lock.
  2054. */
  2055. if (logtype!=SLAPD_ERROR_LOG)
  2056. {
  2057. if (type == LOG_SIZE_EXCEEDED) {
  2058. LDAPDebug (LDAP_DEBUG_TRACE,
  2059. "LOGINFO:End of Log because size exceeded(Max:%"
  2060. NSPRI64 "d bytes) (Is:%" NSPRI64 "d bytes)\n",
  2061. maxlogsize, f_size, 0);
  2062. } else if ( type == LOG_EXPIRED) {
  2063. LDAPDebug(LDAP_DEBUG_TRACE,
  2064. "LOGINFO:End of Log because time exceeded(Max:%d secs) (Is:%ld secs)\n",
  2065. rotationtime_secs, curr_time - log_createtime,0);
  2066. }
  2067. }
  2068. return (type == LOG_CONTINUE) ? LOG_CONTINUE : LOG_ROTATE;
  2069. }
  2070. /******************************************************************************
  2071. * log__delete_access_logfile
  2072. *
  2073. * Do we need to delete a logfile. Find out if we need to delete the log
  2074. * file based on expiration time, max diskspace, and minfreespace.
  2075. * Delete the file if we need to.
  2076. *
  2077. * Assumption: A WRITE lock has been acquired for the ACCESS
  2078. ******************************************************************************/
  2079. static int
  2080. log__delete_access_logfile()
  2081. {
  2082. struct logfileinfo *logp = NULL;
  2083. struct logfileinfo *delete_logp = NULL;
  2084. struct logfileinfo *p_delete_logp = NULL;
  2085. struct logfileinfo *prev_logp = NULL;
  2086. PRInt64 total_size=0;
  2087. time_t cur_time;
  2088. PRInt64 f_size;
  2089. int numoflogs=loginfo.log_numof_access_logs;
  2090. int rv = 0;
  2091. char *logstr;
  2092. char buffer[BUFSIZ];
  2093. char tbuf[TBUFSIZE];
  2094. /* If we have only one log, then will delete this one */
  2095. if (loginfo.log_access_maxnumlogs == 1) {
  2096. LOG_CLOSE(loginfo.log_access_fdes);
  2097. loginfo.log_access_fdes = NULL;
  2098. PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_access_file);
  2099. if (PR_Delete(buffer) != PR_SUCCESS) {
  2100. LDAPDebug(LDAP_DEBUG_TRACE,
  2101. "LOGINFO:Unable to remove file:%s\n", loginfo.log_access_file,0,0);
  2102. }
  2103. /* Delete the rotation file also. */
  2104. PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_access_file);
  2105. if (PR_Delete(buffer) != PR_SUCCESS) {
  2106. LDAPDebug(LDAP_DEBUG_TRACE,
  2107. "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_access_file,0,0);
  2108. }
  2109. return 0;
  2110. }
  2111. /* If we have already the maximum number of log files, we
  2112. ** have to delete one any how.
  2113. */
  2114. if (++numoflogs > loginfo.log_access_maxnumlogs) {
  2115. logstr = "Exceeded max number of logs allowed";
  2116. goto delete_logfile;
  2117. }
  2118. /* Now check based on the maxdiskspace */
  2119. if (loginfo.log_access_maxdiskspace > 0) {
  2120. logp = loginfo.log_access_logchain;
  2121. while (logp) {
  2122. total_size += logp->l_size;
  2123. logp = logp->l_next;
  2124. }
  2125. if ((f_size = log__getfilesize(loginfo.log_access_fdes)) == -1) {
  2126. /* then just assume the max size */
  2127. total_size += loginfo.log_access_maxlogsize;
  2128. } else {
  2129. total_size += f_size;
  2130. }
  2131. /* If we have exceeded the max disk space or we have less than the
  2132. ** minimum, then we have to delete a file.
  2133. */
  2134. if (total_size >= loginfo.log_access_maxdiskspace) {
  2135. logstr = "exceeded maximum log disk space";
  2136. goto delete_logfile;
  2137. }
  2138. }
  2139. /* Now check based on the free space */
  2140. if ( loginfo.log_access_minfreespace > 0) {
  2141. rv = log__enough_freespace(loginfo.log_access_file);
  2142. if ( rv == 0) {
  2143. /* Not enough free space */
  2144. logstr = "Not enough free disk space";
  2145. goto delete_logfile;
  2146. }
  2147. }
  2148. /* Now check based on the expiration time */
  2149. if ( loginfo.log_access_exptime_secs > 0 ) {
  2150. /* is the file old enough */
  2151. time (&cur_time);
  2152. prev_logp = logp = loginfo.log_access_logchain;
  2153. while (logp) {
  2154. if ((cur_time - logp->l_ctime) > loginfo.log_access_exptime_secs) {
  2155. delete_logp = logp;
  2156. p_delete_logp = prev_logp;
  2157. logstr = "The file is older than the log expiration time";
  2158. goto delete_logfile;
  2159. }
  2160. prev_logp = logp;
  2161. logp = logp->l_next;
  2162. }
  2163. }
  2164. /* No log files to delete */
  2165. return 0;
  2166. delete_logfile:
  2167. if (delete_logp == NULL) {
  2168. time_t oldest;
  2169. time(&oldest);
  2170. prev_logp = logp = loginfo.log_access_logchain;
  2171. while (logp) {
  2172. if (logp->l_ctime <= oldest) {
  2173. oldest = logp->l_ctime;
  2174. delete_logp = logp;
  2175. p_delete_logp = prev_logp;
  2176. }
  2177. prev_logp = logp;
  2178. logp = logp->l_next;
  2179. }
  2180. /* We might face this case if we have only one log file and
  2181. ** trying to delete it because of deletion requirement.
  2182. */
  2183. if (!delete_logp) {
  2184. return 0;
  2185. }
  2186. }
  2187. if (p_delete_logp == delete_logp) {
  2188. /* then we are deleteing the first one */
  2189. loginfo.log_access_logchain = delete_logp->l_next;
  2190. } else {
  2191. p_delete_logp->l_next = delete_logp->l_next;
  2192. }
  2193. /* Delete the access file */
  2194. log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
  2195. PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_access_file, tbuf);
  2196. if (PR_Delete(buffer) != PR_SUCCESS) {
  2197. LDAPDebug(LDAP_DEBUG_TRACE,
  2198. "LOGINFO:Unable to remove file:%s.%s\n",
  2199. loginfo.log_access_file,tbuf,0);
  2200. } else {
  2201. LDAPDebug(LDAP_DEBUG_TRACE,
  2202. "LOGINFO:Removed file:%s.%s because of (%s)\n",
  2203. loginfo.log_access_file, tbuf,
  2204. logstr);
  2205. }
  2206. slapi_ch_free((void**)&delete_logp);
  2207. loginfo.log_numof_access_logs--;
  2208. return 1;
  2209. }
  2210. /*
  2211. * This function is used by the disk monitoring thread (daemon.c)
  2212. *
  2213. * When we get close to running out of disk space we delete the rotated logs
  2214. * as a last resort to help keep the server up and running.
  2215. */
  2216. void
  2217. log__delete_rotated_logs()
  2218. {
  2219. struct logfileinfo *logp = NULL;
  2220. char buffer[BUFSIZ];
  2221. char tbuf[TBUFSIZE];
  2222. /*
  2223. * Access Log
  2224. */
  2225. logp = loginfo.log_access_logchain;
  2226. while (logp) {
  2227. tbuf[0] = buffer[0] = '\0';
  2228. log_convert_time (logp->l_ctime, tbuf, 1);
  2229. PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_access_file, tbuf);
  2230. LDAPDebug(LDAP_DEBUG_ANY,"Deleted Rotated Log: %s\n",buffer,0,0);
  2231. if (PR_Delete(buffer) != PR_SUCCESS) {
  2232. logp = logp->l_next;
  2233. continue;
  2234. }
  2235. loginfo.log_numof_access_logs--;
  2236. logp = logp->l_next;
  2237. }
  2238. /*
  2239. * Audit Log
  2240. */
  2241. logp = loginfo.log_audit_logchain;
  2242. while (logp) {
  2243. tbuf[0] = buffer[0] = '\0';
  2244. log_convert_time (logp->l_ctime, tbuf, 1);
  2245. PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_audit_file, tbuf);
  2246. if (PR_Delete(buffer) != PR_SUCCESS) {
  2247. logp = logp->l_next;
  2248. continue;
  2249. }
  2250. loginfo.log_numof_audit_logs--;
  2251. logp = logp->l_next;
  2252. }
  2253. /*
  2254. * Error log
  2255. */
  2256. logp = loginfo.log_error_logchain;
  2257. while (logp) {
  2258. tbuf[0] = buffer[0] = '\0';
  2259. log_convert_time (logp->l_ctime, tbuf, 1);
  2260. PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_error_file, tbuf);
  2261. if (PR_Delete(buffer) != PR_SUCCESS) {
  2262. logp = logp->l_next;
  2263. continue;
  2264. }
  2265. loginfo.log_numof_error_logs--;
  2266. logp = logp->l_next;
  2267. }
  2268. }
  2269. #define ERRORSLOG 1
  2270. #define ACCESSLOG 2
  2271. #define AUDITLOG 3
  2272. static int
  2273. log__fix_rotationinfof(char *pathname)
  2274. {
  2275. char *logsdir = NULL;
  2276. time_t now;
  2277. PRDir *dirptr = NULL;
  2278. PRDirEntry *dirent = NULL;
  2279. PRDirFlags dirflags = PR_SKIP_BOTH & PR_SKIP_HIDDEN;
  2280. char *log_type = NULL;
  2281. int log_type_id;
  2282. int rval = LOG_ERROR;
  2283. char *p;
  2284. char *rotated_log = NULL;
  2285. int rotated_log_len = 0;
  2286. /* rotation info file is broken; can't trust the contents */
  2287. time (&now);
  2288. loginfo.log_error_ctime = now;
  2289. logsdir = slapi_ch_strdup(pathname);
  2290. p = strrchr(logsdir, _PSEP);
  2291. if (NULL == p) /* pathname is not path/filename.rotationinfo; do nothing */
  2292. goto done;
  2293. *p = '\0';
  2294. log_type = ++p;
  2295. p = strchr(log_type, '.');
  2296. if (NULL == p) /* file is not rotationinfo; do nothing */
  2297. goto done;
  2298. *p = '\0';
  2299. if (0 == strcmp(log_type, "errors"))
  2300. log_type_id = ERRORSLOG;
  2301. else if (0 == strcmp(log_type, "access"))
  2302. log_type_id = ACCESSLOG;
  2303. else if (0 == strcmp(log_type, "audit"))
  2304. log_type_id = AUDITLOG;
  2305. else
  2306. goto done; /* file is not errors nor access nor audit; do nothing */
  2307. if (!(dirptr = PR_OpenDir(logsdir)))
  2308. goto done;
  2309. switch (log_type_id) {
  2310. case ERRORSLOG:
  2311. loginfo.log_numof_error_logs = 0;
  2312. loginfo.log_error_logchain = NULL;
  2313. break;
  2314. case ACCESSLOG:
  2315. loginfo.log_numof_access_logs = 0;
  2316. loginfo.log_access_logchain = NULL;
  2317. break;
  2318. case AUDITLOG:
  2319. loginfo.log_numof_audit_logs = 0;
  2320. loginfo.log_audit_logchain = NULL;
  2321. break;
  2322. }
  2323. /* length of (pathname + .YYYYMMDD-hhmmss)
  2324. * pathname includes ".rotationinfo", but that's fine. */
  2325. rotated_log_len = strlen(pathname) + 17;
  2326. rotated_log = (char *)slapi_ch_malloc(rotated_log_len);
  2327. /* read the directory entries into a linked list */
  2328. for (dirent = PR_ReadDir(dirptr, dirflags); dirent ;
  2329. dirent = PR_ReadDir(dirptr, dirflags)) {
  2330. if (0 == strcmp(log_type, dirent->name)) {
  2331. switch (log_type_id) {
  2332. case ERRORSLOG:
  2333. loginfo.log_numof_error_logs++;
  2334. break;
  2335. case ACCESSLOG:
  2336. loginfo.log_numof_access_logs++;
  2337. break;
  2338. case AUDITLOG:
  2339. loginfo.log_numof_audit_logs++;
  2340. break;
  2341. }
  2342. } else if (0 == strncmp(log_type, dirent->name, strlen(log_type)) &&
  2343. (p = strrchr(dirent->name, '.')) != NULL &&
  2344. 15 == strlen(++p) &&
  2345. NULL != strchr(p, '-')) { /* e.g., errors.20051123-165135 */
  2346. struct logfileinfo *logp;
  2347. char *q;
  2348. int ignoreit = 0;
  2349. for (q = p; q && *q; q++) {
  2350. if (*q != '-' && !isdigit(*q))
  2351. ignoreit = 1;
  2352. }
  2353. if (ignoreit)
  2354. continue;
  2355. logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
  2356. logp->l_ctime = log_reverse_convert_time(p);
  2357. PR_snprintf(rotated_log, rotated_log_len, "%s/%s",
  2358. logsdir, dirent->name);
  2359. switch (log_type_id) {
  2360. case ERRORSLOG:
  2361. logp->l_size = log__getfilesize_with_filename(rotated_log);
  2362. logp->l_next = loginfo.log_error_logchain;
  2363. loginfo.log_error_logchain = logp;
  2364. loginfo.log_numof_error_logs++;
  2365. break;
  2366. case ACCESSLOG:
  2367. logp->l_size = log__getfilesize_with_filename(rotated_log);
  2368. logp->l_next = loginfo.log_access_logchain;
  2369. loginfo.log_access_logchain = logp;
  2370. loginfo.log_numof_access_logs++;
  2371. break;
  2372. case AUDITLOG:
  2373. logp->l_size = log__getfilesize_with_filename(rotated_log);
  2374. logp->l_next = loginfo.log_audit_logchain;
  2375. loginfo.log_audit_logchain = logp;
  2376. loginfo.log_numof_audit_logs++;
  2377. break;
  2378. }
  2379. }
  2380. }
  2381. rval = LOG_SUCCESS;
  2382. done:
  2383. if (NULL != dirptr)
  2384. PR_CloseDir(dirptr);
  2385. slapi_ch_free_string(&logsdir);
  2386. slapi_ch_free_string(&rotated_log);
  2387. return rval;
  2388. }
  2389. #undef ERRORSLOG
  2390. #undef ACCESSLOG
  2391. #undef AUDITLOG
  2392. /******************************************************************************
  2393. * log__access_rotationinfof
  2394. *
  2395. * Try to open the log file. If we have one already, then try to read the
  2396. * header and update the information.
  2397. *
  2398. * Assumption: Lock has been acquired already
  2399. ******************************************************************************/
  2400. static int
  2401. log__access_rotationinfof(char *pathname)
  2402. {
  2403. long f_ctime;
  2404. PRInt64 f_size;
  2405. int main_log = 1;
  2406. time_t now;
  2407. FILE *fp;
  2408. int rval, logfile_type = LOGFILE_REOPENED;
  2409. /*
  2410. ** Okay -- I confess, we want to use NSPR calls but I want to
  2411. ** use fgets and not use PR_Read() and implement a complicated
  2412. ** parsing module. Since this will be called only during the startup
  2413. ** and never aftre that, we can live by it.
  2414. */
  2415. if ((fp = fopen (pathname, "r")) == NULL) {
  2416. return LOGFILE_NEW;
  2417. }
  2418. loginfo.log_numof_access_logs = 0;
  2419. /*
  2420. ** We have reopened the log access file. Now we need to read the
  2421. ** log file info and update the values.
  2422. */
  2423. while ((rval = log__extract_logheader(fp, &f_ctime, &f_size)) == LOG_CONTINUE) {
  2424. /* first we would get the main log info */
  2425. if (f_ctime == 0 && f_size == 0)
  2426. continue;
  2427. time (&now);
  2428. if (main_log) {
  2429. if (f_ctime > 0L)
  2430. loginfo.log_access_ctime = f_ctime;
  2431. else {
  2432. loginfo.log_access_ctime = now;
  2433. }
  2434. main_log = 0;
  2435. } else {
  2436. struct logfileinfo *logp;
  2437. logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
  2438. if (f_ctime > 0L)
  2439. logp->l_ctime = f_ctime;
  2440. else
  2441. logp->l_ctime = now;
  2442. if (f_size > 0)
  2443. logp->l_size = f_size;
  2444. else {
  2445. /* make it the max log size */
  2446. logp->l_size = loginfo.log_access_maxlogsize;
  2447. }
  2448. logp->l_next = loginfo.log_access_logchain;
  2449. loginfo.log_access_logchain = logp;
  2450. }
  2451. loginfo.log_numof_access_logs++;
  2452. }
  2453. if (LOG_DONE == rval)
  2454. rval = log__check_prevlogs(fp, pathname);
  2455. fclose (fp);
  2456. if (LOG_ERROR == rval)
  2457. if (LOG_SUCCESS == log__fix_rotationinfof(pathname))
  2458. logfile_type = LOGFILE_NEW;
  2459. /* Check if there is a rotation overdue */
  2460. if (loginfo.log_access_rotationsync_enabled &&
  2461. loginfo.log_access_rotationunit != LOG_UNIT_HOURS &&
  2462. loginfo.log_access_rotationunit != LOG_UNIT_MINS &&
  2463. loginfo.log_access_ctime < loginfo.log_access_rotationsyncclock - PR_ABS(loginfo.log_access_rotationtime_secs)) {
  2464. loginfo.log_access_rotationsyncclock -= PR_ABS(loginfo.log_access_rotationtime_secs);
  2465. }
  2466. return logfile_type;
  2467. }
  2468. /*
  2469. * log__check_prevlogs
  2470. *
  2471. * check if a given prev log file (e.g., /var/log/dirsrv/slapd-fe/logs/errors.20051201-101347)
  2472. * is found in the rotationinfo file.
  2473. */
  2474. static int
  2475. log__check_prevlogs (FILE *fp, char *pathname)
  2476. {
  2477. char buf[BUFSIZ], *p;
  2478. char *logsdir = NULL;
  2479. int rval = LOG_CONTINUE;
  2480. char *log_type = NULL;
  2481. PRDir *dirptr = NULL;
  2482. PRDirEntry *dirent = NULL;
  2483. PRDirFlags dirflags = PR_SKIP_BOTH & PR_SKIP_HIDDEN;
  2484. logsdir = slapi_ch_strdup(pathname);
  2485. p = strrchr(logsdir, _PSEP);
  2486. if (NULL == p) /* pathname is not path/filename.rotationinfo; do nothing */
  2487. goto done;
  2488. *p = '\0';
  2489. log_type = ++p;
  2490. p = strchr(log_type, '.');
  2491. if (NULL == p) /* file is not rotationinfo; do nothing */
  2492. goto done;
  2493. *p = '\0';
  2494. if (0 != strcmp(log_type, "errors") &&
  2495. 0 != strcmp(log_type, "access") &&
  2496. 0 != strcmp(log_type, "audit"))
  2497. goto done; /* file is not errors nor access nor audit; do nothing */
  2498. if (!(dirptr = PR_OpenDir(logsdir)))
  2499. goto done;
  2500. for (dirent = PR_ReadDir(dirptr, dirflags); dirent ;
  2501. dirent = PR_ReadDir(dirptr, dirflags)) {
  2502. if (0 == strncmp(log_type, dirent->name, strlen(log_type)) &&
  2503. (p = strrchr(dirent->name, '.')) != NULL &&
  2504. 15 == strlen(++p) &&
  2505. NULL != strchr(p, '-')) { /* e.g., errors.20051123-165135 */
  2506. char *q;
  2507. int ignoreit = 0;
  2508. for (q = p; q && *q; q++) {
  2509. if (*q != '-' && !isdigit(*q))
  2510. ignoreit = 1;
  2511. }
  2512. if (ignoreit)
  2513. continue;
  2514. fseek(fp, 0 ,SEEK_SET);
  2515. buf[BUFSIZ-1] = '\0';
  2516. rval = LOG_ERROR; /* pessmistic default */
  2517. while (fgets(buf, BUFSIZ - 1, fp)) {
  2518. if (strstr(buf, dirent->name)) {
  2519. rval = LOG_CONTINUE; /* found in .rotationinfo */
  2520. break;
  2521. }
  2522. }
  2523. if(LOG_ERROR == rval) {
  2524. goto done;
  2525. }
  2526. }
  2527. }
  2528. done:
  2529. if (NULL != dirptr)
  2530. PR_CloseDir(dirptr);
  2531. slapi_ch_free_string(&logsdir);
  2532. return rval;
  2533. }
  2534. /******************************************************************************
  2535. * log__extract_logheader
  2536. *
  2537. * Extract each LOGINFO heder line. From there extract the time and
  2538. * size info of all the old log files.
  2539. ******************************************************************************/
  2540. static int
  2541. log__extract_logheader (FILE *fp, long *f_ctime, PRInt64 *f_size)
  2542. {
  2543. char buf[BUFSIZ];
  2544. char *p, *s, *next;
  2545. if (NULL == f_ctime || NULL == f_size) {
  2546. return LOG_ERROR;
  2547. }
  2548. *f_ctime = 0L;
  2549. *f_size = 0L;
  2550. if ( fp == NULL)
  2551. return LOG_ERROR;
  2552. buf[BUFSIZ-1] = '\0'; /* for safety */
  2553. if (fgets(buf, BUFSIZ - 1, fp) == NULL) {
  2554. return LOG_DONE;
  2555. }
  2556. if ((p=strstr(buf, "LOGINFO")) == NULL) {
  2557. return LOG_ERROR;
  2558. }
  2559. s = p;
  2560. if ((p = strchr(p, '(')) == NULL) {
  2561. return LOG_CONTINUE;
  2562. }
  2563. if ((next= strchr(p, ')')) == NULL) {
  2564. return LOG_CONTINUE;
  2565. }
  2566. p++;
  2567. s = next;
  2568. next++;
  2569. *s = '\0';
  2570. /* Now p must hold the ctime value */
  2571. *f_ctime = strtol(p, (char **)NULL, 0);
  2572. if ((p = strchr(next, '(')) == NULL) {
  2573. /* that's fine -- it means we have no size info */
  2574. *f_size = 0L;
  2575. return LOG_CONTINUE;
  2576. }
  2577. if ((next= strchr(p, ')')) == NULL) {
  2578. return LOG_CONTINUE;
  2579. }
  2580. p++;
  2581. *next = '\0';
  2582. /* Now p must hold the size value */
  2583. *f_size = strtoll(p, (char **)NULL, 0);
  2584. /* check if the Previous Log file really exists */
  2585. if ((p = strstr(buf, PREVLOGFILE)) != NULL) {
  2586. p += strlen(PREVLOGFILE);
  2587. s = strchr(p, ' ');
  2588. if (NULL == s) {
  2589. s = strchr(p, '(');
  2590. if (NULL != s) {
  2591. *s = '\0';
  2592. }
  2593. } else {
  2594. *s = '\0';
  2595. }
  2596. if (PR_SUCCESS != PR_Access(p, PR_ACCESS_EXISTS)) {
  2597. return LOG_ERROR;
  2598. }
  2599. }
  2600. return LOG_CONTINUE;
  2601. }
  2602. /******************************************************************************
  2603. * log__getfilesize
  2604. * Get the file size
  2605. *
  2606. * Assumption: Lock has been acquired already.
  2607. ******************************************************************************/
  2608. /* this kinda has to be diff't on each platform :( */
  2609. /* using an int implies that all logfiles will be under 2G. this is
  2610. * probably a safe assumption for now.
  2611. */
  2612. static PRInt64
  2613. log__getfilesize(LOGFD fp)
  2614. {
  2615. PRFileInfo64 info;
  2616. if (PR_GetOpenFileInfo64 (fp, &info) == PR_FAILURE) {
  2617. return -1;
  2618. }
  2619. return (PRInt64)info.size; /* type of size is PROffset64 */
  2620. }
  2621. static PRInt64
  2622. log__getfilesize_with_filename(char *filename)
  2623. {
  2624. PRFileInfo64 info;
  2625. if (PR_GetFileInfo64 ((const char *)filename, &info) == PR_FAILURE) {
  2626. return -1;
  2627. }
  2628. return (PRInt64)info.size; /* type of size is PROffset64 */
  2629. }
  2630. /******************************************************************************
  2631. * log__enough_freespace
  2632. *
  2633. * Returns:
  2634. * 1 - we have enough space
  2635. * 0 - No the avialable space is less than recomended
  2636. * Assumption: Lock has been acquired already.
  2637. ******************************************************************************/
  2638. static int
  2639. log__enough_freespace(char *path)
  2640. {
  2641. #ifdef LINUX
  2642. struct statfs buf;
  2643. #else
  2644. struct statvfs buf;
  2645. #endif /* LINUX */
  2646. PRInt64 freeBytes;
  2647. PRInt64 tmpval;
  2648. #ifdef LINUX
  2649. if (statfs(path, &buf) == -1)
  2650. #else
  2651. if (statvfs(path, &buf) == -1)
  2652. #endif
  2653. {
  2654. char buffer[BUFSIZ];
  2655. PR_snprintf(buffer, sizeof(buffer),
  2656. "log__enough_freespace: Unable to get the free space (errno:%d)\n",
  2657. errno);
  2658. log__error_emergency(buffer, 0, 1);
  2659. return 1;
  2660. } else {
  2661. LL_UI2L(freeBytes, buf.f_bavail);
  2662. LL_UI2L(tmpval, buf.f_bsize);
  2663. LL_MUL(freeBytes, freeBytes, tmpval);
  2664. /* freeBytes = buf.f_bavail * buf.f_bsize; */
  2665. }
  2666. LL_UI2L(tmpval, loginfo.log_access_minfreespace);
  2667. if (LL_UCMP(freeBytes, <, tmpval)) {
  2668. /* if (freeBytes < loginfo.log_access_minfreespace) { */
  2669. return 0;
  2670. }
  2671. return 1;
  2672. }
  2673. /******************************************************************************
  2674. * log__getaccesslist
  2675. * Update the previous access files in the slapdFrontendConfig_t.
  2676. * Returns:
  2677. * num > 1 -- how many are there
  2678. * 0 -- otherwise
  2679. ******************************************************************************/
  2680. char **
  2681. log_get_loglist(int logtype)
  2682. {
  2683. char **list=NULL;
  2684. int num, i;
  2685. LogFileInfo *logp = NULL;
  2686. char buf[BUFSIZ];
  2687. char tbuf[TBUFSIZE];
  2688. char *file;
  2689. switch (logtype) {
  2690. case SLAPD_ACCESS_LOG:
  2691. LOG_ACCESS_LOCK_READ( );
  2692. num = loginfo.log_numof_access_logs;
  2693. logp = loginfo.log_access_logchain;
  2694. file = loginfo.log_access_file;
  2695. break;
  2696. case SLAPD_ERROR_LOG:
  2697. LOG_ERROR_LOCK_READ( );
  2698. num = loginfo.log_numof_error_logs;
  2699. logp = loginfo.log_error_logchain;
  2700. file = loginfo.log_error_file;
  2701. break;
  2702. case SLAPD_AUDIT_LOG:
  2703. LOG_AUDIT_LOCK_READ( );
  2704. num = loginfo.log_numof_audit_logs;
  2705. logp = loginfo.log_audit_logchain;
  2706. file = loginfo.log_audit_file;
  2707. break;
  2708. default:
  2709. return NULL;
  2710. }
  2711. list = (char **) slapi_ch_calloc(1, (num + 1) * sizeof(char *));
  2712. i = 0;
  2713. while (logp) {
  2714. log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
  2715. PR_snprintf(buf, sizeof(buf), "%s.%s", file, tbuf);
  2716. list[i] = slapi_ch_strdup(buf);
  2717. i++;
  2718. if (i == num) { /* mismatch b/w num and logchain;
  2719. cut the chain and save the process */
  2720. break;
  2721. }
  2722. logp = logp->l_next;
  2723. }
  2724. list[i] = NULL;
  2725. switch (logtype) {
  2726. case SLAPD_ACCESS_LOG:
  2727. LOG_ACCESS_UNLOCK_READ();
  2728. break;
  2729. case SLAPD_ERROR_LOG:
  2730. LOG_ERROR_UNLOCK_READ();
  2731. break;
  2732. case SLAPD_AUDIT_LOG:
  2733. LOG_AUDIT_UNLOCK_READ();
  2734. break;
  2735. }
  2736. return list;
  2737. }
  2738. /******************************************************************************
  2739. * log__delete_error_logfile
  2740. *
  2741. * Do we need to delete a logfile. Find out if we need to delete the log
  2742. * file based on expiration time, max diskspace, and minfreespace.
  2743. * Delete the file if we need to.
  2744. *
  2745. * Assumption: A WRITE lock has been acquired for the error log.
  2746. ******************************************************************************/
  2747. static int
  2748. log__delete_error_logfile(int locked)
  2749. {
  2750. struct logfileinfo *logp = NULL;
  2751. struct logfileinfo *delete_logp = NULL;
  2752. struct logfileinfo *p_delete_logp = NULL;
  2753. struct logfileinfo *prev_logp = NULL;
  2754. PRInt64 total_size=0;
  2755. time_t cur_time;
  2756. PRInt64 f_size;
  2757. int numoflogs=loginfo.log_numof_error_logs;
  2758. int rv = 0;
  2759. char *logstr;
  2760. char buffer[BUFSIZ];
  2761. char tbuf[TBUFSIZE];
  2762. /* If we have only one log, then will delete this one */
  2763. if (loginfo.log_error_maxnumlogs == 1) {
  2764. LOG_CLOSE(loginfo.log_error_fdes);
  2765. loginfo.log_error_fdes = NULL;
  2766. PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_error_file);
  2767. if (PR_Delete(buffer) != PR_SUCCESS) {
  2768. if (!locked) {
  2769. /* if locked, we should not call LDAPDebug,
  2770. which tries to get a lock internally. */
  2771. LDAPDebug(LDAP_DEBUG_TRACE,
  2772. "LOGINFO:Unable to remove file:%s\n", loginfo.log_error_file,0,0);
  2773. }
  2774. }
  2775. /* Delete the rotation file also. */
  2776. PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_error_file);
  2777. if (PR_Delete(buffer) != PR_SUCCESS) {
  2778. if (!locked) {
  2779. /* if locked, we should not call LDAPDebug,
  2780. which tries to get a lock internally. */
  2781. LDAPDebug(LDAP_DEBUG_TRACE,
  2782. "LOGINFO:Unable to remove file:%s.rotationinfo\n",
  2783. loginfo.log_error_file,0,0);
  2784. }
  2785. }
  2786. return 0;
  2787. }
  2788. /* If we have already the maximum number of log files, we
  2789. ** have to delete one any how.
  2790. */
  2791. if (++numoflogs > loginfo.log_error_maxnumlogs) {
  2792. logstr = "Exceeded max number of logs allowed";
  2793. goto delete_logfile;
  2794. }
  2795. /* Now check based on the maxdiskspace */
  2796. if (loginfo.log_error_maxdiskspace > 0) {
  2797. logp = loginfo.log_error_logchain;
  2798. while (logp) {
  2799. total_size += logp->l_size;
  2800. logp = logp->l_next;
  2801. }
  2802. if ((f_size = log__getfilesize(loginfo.log_error_fdes)) == -1) {
  2803. /* then just assume the max size */
  2804. total_size += loginfo.log_error_maxlogsize;
  2805. } else {
  2806. total_size += f_size;
  2807. }
  2808. /* If we have exceeded the max disk space or we have less than the
  2809. ** minimum, then we have to delete a file.
  2810. */
  2811. if (total_size >= loginfo.log_error_maxdiskspace) {
  2812. logstr = "exceeded maximum log disk space";
  2813. goto delete_logfile;
  2814. }
  2815. }
  2816. /* Now check based on the free space */
  2817. if ( loginfo.log_error_minfreespace > 0) {
  2818. rv = log__enough_freespace(loginfo.log_error_file);
  2819. if ( rv == 0) {
  2820. /* Not enough free space */
  2821. logstr = "Not enough free disk space";
  2822. goto delete_logfile;
  2823. }
  2824. }
  2825. /* Now check based on the expiration time */
  2826. if ( loginfo.log_error_exptime_secs > 0 ) {
  2827. /* is the file old enough */
  2828. time (&cur_time);
  2829. prev_logp = logp = loginfo.log_error_logchain;
  2830. while (logp) {
  2831. if ((cur_time - logp->l_ctime) > loginfo.log_error_exptime_secs) {
  2832. delete_logp = logp;
  2833. p_delete_logp = prev_logp;
  2834. logstr = "The file is older than the log expiration time";
  2835. goto delete_logfile;
  2836. }
  2837. prev_logp = logp;
  2838. logp = logp->l_next;
  2839. }
  2840. }
  2841. /* No log files to delete */
  2842. return 0;
  2843. delete_logfile:
  2844. if (delete_logp == NULL) {
  2845. time_t oldest;
  2846. time(&oldest);
  2847. prev_logp = logp = loginfo.log_error_logchain;
  2848. while (logp) {
  2849. if (logp->l_ctime <= oldest) {
  2850. oldest = logp->l_ctime;
  2851. delete_logp = logp;
  2852. p_delete_logp = prev_logp;
  2853. }
  2854. prev_logp = logp;
  2855. logp = logp->l_next;
  2856. }
  2857. /* We might face this case if we have only one log file and
  2858. ** trying to delete it because of deletion requirement.
  2859. */
  2860. if (!delete_logp) {
  2861. return 0;
  2862. }
  2863. }
  2864. memset(tbuf, 0, sizeof(tbuf));
  2865. log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
  2866. if (!locked) {
  2867. /* if locked, we should not call LDAPDebug,
  2868. which tries to get a lock internally. */
  2869. LDAPDebug(LDAP_DEBUG_TRACE,
  2870. "LOGINFO:Removing file:%s.%s because of (%s)\n",
  2871. loginfo.log_error_file, tbuf,
  2872. logstr);
  2873. }
  2874. if (p_delete_logp == delete_logp) {
  2875. /* then we are deleteing the first one */
  2876. loginfo.log_error_logchain = delete_logp->l_next;
  2877. } else {
  2878. p_delete_logp->l_next = delete_logp->l_next;
  2879. }
  2880. /* Delete the error file */
  2881. PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_error_file, tbuf);
  2882. if (PR_Delete(buffer) != PR_SUCCESS) {
  2883. PRErrorCode prerr = PR_GetError();
  2884. PR_snprintf(buffer, sizeof(buffer),
  2885. "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
  2886. loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
  2887. log__error_emergency(buffer, 0, locked);
  2888. }
  2889. slapi_ch_free((void**)&delete_logp);
  2890. loginfo.log_numof_error_logs--;
  2891. return 1;
  2892. }
  2893. /******************************************************************************
  2894. * log__delete_audit_logfile
  2895. *
  2896. * Do we need to delete a logfile. Find out if we need to delete the log
  2897. * file based on expiration time, max diskspace, and minfreespace.
  2898. * Delete the file if we need to.
  2899. *
  2900. * Assumption: A WRITE lock has been acquired for the audit
  2901. ******************************************************************************/
  2902. static int
  2903. log__delete_audit_logfile()
  2904. {
  2905. struct logfileinfo *logp = NULL;
  2906. struct logfileinfo *delete_logp = NULL;
  2907. struct logfileinfo *p_delete_logp = NULL;
  2908. struct logfileinfo *prev_logp = NULL;
  2909. PRInt64 total_size=0;
  2910. time_t cur_time;
  2911. PRInt64 f_size;
  2912. int numoflogs=loginfo.log_numof_audit_logs;
  2913. int rv = 0;
  2914. char *logstr;
  2915. char buffer[BUFSIZ];
  2916. char tbuf[TBUFSIZE];
  2917. /* If we have only one log, then will delete this one */
  2918. if (loginfo.log_audit_maxnumlogs == 1) {
  2919. LOG_CLOSE(loginfo.log_audit_fdes);
  2920. loginfo.log_audit_fdes = NULL;
  2921. PR_snprintf(buffer, sizeof(buffer), "%s", loginfo.log_audit_file);
  2922. if (PR_Delete(buffer) != PR_SUCCESS) {
  2923. LDAPDebug(LDAP_DEBUG_TRACE,
  2924. "LOGINFO:Unable to remove file:%s\n", loginfo.log_audit_file,0,0);
  2925. }
  2926. /* Delete the rotation file also. */
  2927. PR_snprintf(buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_audit_file);
  2928. if (PR_Delete(buffer) != PR_SUCCESS) {
  2929. LDAPDebug(LDAP_DEBUG_TRACE,
  2930. "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_audit_file,0,0);
  2931. }
  2932. return 0;
  2933. }
  2934. /* If we have already the maximum number of log files, we
  2935. ** have to delete one any how.
  2936. */
  2937. if (++numoflogs > loginfo.log_audit_maxnumlogs) {
  2938. logstr = "Delete Error Log File: Exceeded max number of logs allowed";
  2939. goto delete_logfile;
  2940. }
  2941. /* Now check based on the maxdiskspace */
  2942. if (loginfo.log_audit_maxdiskspace > 0) {
  2943. logp = loginfo.log_audit_logchain;
  2944. while (logp) {
  2945. total_size += logp->l_size;
  2946. logp = logp->l_next;
  2947. }
  2948. if ((f_size = log__getfilesize(loginfo.log_audit_fdes)) == -1) {
  2949. /* then just assume the max size */
  2950. total_size += loginfo.log_audit_maxlogsize;
  2951. } else {
  2952. total_size += f_size;
  2953. }
  2954. /* If we have exceeded the max disk space or we have less than the
  2955. ** minimum, then we have to delete a file.
  2956. */
  2957. if (total_size >= loginfo.log_audit_maxdiskspace) {
  2958. logstr = "exceeded maximum log disk space";
  2959. goto delete_logfile;
  2960. }
  2961. }
  2962. /* Now check based on the free space */
  2963. if ( loginfo.log_audit_minfreespace > 0) {
  2964. rv = log__enough_freespace(loginfo.log_audit_file);
  2965. if ( rv == 0) {
  2966. /* Not enough free space */
  2967. logstr = "Not enough free disk space";
  2968. goto delete_logfile;
  2969. }
  2970. }
  2971. /* Now check based on the expiration time */
  2972. if ( loginfo.log_audit_exptime_secs > 0 ) {
  2973. /* is the file old enough */
  2974. time (&cur_time);
  2975. prev_logp = logp = loginfo.log_audit_logchain;
  2976. while (logp) {
  2977. if ((cur_time - logp->l_ctime) > loginfo.log_audit_exptime_secs) {
  2978. delete_logp = logp;
  2979. p_delete_logp = prev_logp;
  2980. logstr = "The file is older than the log expiration time";
  2981. goto delete_logfile;
  2982. }
  2983. prev_logp = logp;
  2984. logp = logp->l_next;
  2985. }
  2986. }
  2987. /* No log files to delete */
  2988. return 0;
  2989. delete_logfile:
  2990. if (delete_logp == NULL) {
  2991. time_t oldest;
  2992. time(&oldest);
  2993. prev_logp = logp = loginfo.log_audit_logchain;
  2994. while (logp) {
  2995. if (logp->l_ctime <= oldest) {
  2996. oldest = logp->l_ctime;
  2997. delete_logp = logp;
  2998. p_delete_logp = prev_logp;
  2999. }
  3000. prev_logp = logp;
  3001. logp = logp->l_next;
  3002. }
  3003. /* We might face this case if we have only one log file and
  3004. ** trying to delete it because of deletion requirement.
  3005. */
  3006. if (!delete_logp) {
  3007. return 0;
  3008. }
  3009. }
  3010. if (p_delete_logp == delete_logp) {
  3011. /* then we are deleteing the first one */
  3012. loginfo.log_audit_logchain = delete_logp->l_next;
  3013. } else {
  3014. p_delete_logp->l_next = delete_logp->l_next;
  3015. }
  3016. /* Delete the audit file */
  3017. log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
  3018. PR_snprintf(buffer, sizeof(buffer), "%s.%s", loginfo.log_audit_file, tbuf );
  3019. if (PR_Delete(buffer) != PR_SUCCESS) {
  3020. LDAPDebug(LDAP_DEBUG_TRACE,
  3021. "LOGINFO:Unable to remove file:%s.%s\n",
  3022. loginfo.log_audit_file, tbuf,0);
  3023. } else {
  3024. LDAPDebug(LDAP_DEBUG_TRACE,
  3025. "LOGINFO:Removed file:%s.%s because of (%s)\n",
  3026. loginfo.log_audit_file, tbuf,
  3027. logstr);
  3028. }
  3029. slapi_ch_free((void**)&delete_logp);
  3030. loginfo.log_numof_audit_logs--;
  3031. return 1;
  3032. }
  3033. /******************************************************************************
  3034. * log__error_rotationinfof
  3035. *
  3036. * Try to open the log file. If we have one already, then try to read the
  3037. * header and update the information.
  3038. *
  3039. * Assumption: Lock has been acquired already
  3040. ******************************************************************************/
  3041. static int
  3042. log__error_rotationinfof( char *pathname)
  3043. {
  3044. long f_ctime;
  3045. PRInt64 f_size;
  3046. int main_log = 1;
  3047. time_t now;
  3048. FILE *fp;
  3049. int rval, logfile_type = LOGFILE_REOPENED;
  3050. /*
  3051. ** Okay -- I confess, we want to use NSPR calls but I want to
  3052. ** use fgets and not use PR_Read() and implement a complicated
  3053. ** parsing module. Since this will be called only during the startup
  3054. ** and never aftre that, we can live by it.
  3055. */
  3056. if ((fp = fopen (pathname, "r")) == NULL) {
  3057. return LOGFILE_NEW;
  3058. }
  3059. loginfo.log_numof_error_logs = 0;
  3060. /*
  3061. ** We have reopened the log error file. Now we need to read the
  3062. ** log file info and update the values.
  3063. */
  3064. while ((rval = log__extract_logheader(fp, &f_ctime, &f_size)) == LOG_CONTINUE) {
  3065. /* first we would get the main log info */
  3066. if (f_ctime == 0 && f_size == 0)
  3067. continue;
  3068. time (&now);
  3069. if (main_log) {
  3070. if (f_ctime > 0L)
  3071. loginfo.log_error_ctime = f_ctime;
  3072. else {
  3073. loginfo.log_error_ctime = now;
  3074. }
  3075. main_log = 0;
  3076. } else {
  3077. struct logfileinfo *logp;
  3078. logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
  3079. if (f_ctime > 0L)
  3080. logp->l_ctime = f_ctime;
  3081. else
  3082. logp->l_ctime = now;
  3083. if (f_size > 0)
  3084. logp->l_size = f_size;
  3085. else {
  3086. /* make it the max log size */
  3087. logp->l_size = loginfo.log_error_maxlogsize;
  3088. }
  3089. logp->l_next = loginfo.log_error_logchain;
  3090. loginfo.log_error_logchain = logp;
  3091. }
  3092. loginfo.log_numof_error_logs++;
  3093. }
  3094. if (LOG_DONE == rval)
  3095. rval = log__check_prevlogs(fp, pathname);
  3096. fclose (fp);
  3097. if (LOG_ERROR == rval)
  3098. if (LOG_SUCCESS == log__fix_rotationinfof(pathname))
  3099. logfile_type = LOGFILE_NEW;
  3100. /* Check if there is a rotation overdue */
  3101. if (loginfo.log_error_rotationsync_enabled &&
  3102. loginfo.log_error_rotationunit != LOG_UNIT_HOURS &&
  3103. loginfo.log_error_rotationunit != LOG_UNIT_MINS &&
  3104. loginfo.log_error_ctime < loginfo.log_error_rotationsyncclock - PR_ABS(loginfo.log_error_rotationtime_secs)) {
  3105. loginfo.log_error_rotationsyncclock -= PR_ABS(loginfo.log_error_rotationtime_secs);
  3106. }
  3107. return logfile_type;
  3108. }
  3109. /******************************************************************************
  3110. * log__audit_rotationinfof
  3111. *
  3112. * Try to open the log file. If we have one already, then try to read the
  3113. * header and update the information.
  3114. *
  3115. * Assumption: Lock has been acquired already
  3116. ******************************************************************************/
  3117. static int
  3118. log__audit_rotationinfof( char *pathname)
  3119. {
  3120. long f_ctime;
  3121. PRInt64 f_size;
  3122. int main_log = 1;
  3123. time_t now;
  3124. FILE *fp;
  3125. int rval, logfile_type = LOGFILE_REOPENED;
  3126. /*
  3127. ** Okay -- I confess, we want to use NSPR calls but I want to
  3128. ** use fgets and not use PR_Read() and implement a complicated
  3129. ** parsing module. Since this will be called only during the startup
  3130. ** and never aftre that, we can live by it.
  3131. */
  3132. if ((fp = fopen (pathname, "r")) == NULL) {
  3133. return LOGFILE_NEW;
  3134. }
  3135. loginfo.log_numof_audit_logs = 0;
  3136. /*
  3137. ** We have reopened the log audit file. Now we need to read the
  3138. ** log file info and update the values.
  3139. */
  3140. while ((rval = log__extract_logheader(fp, &f_ctime, &f_size)) == LOG_CONTINUE) {
  3141. /* first we would get the main log info */
  3142. if (f_ctime == 0 && f_size == 0)
  3143. continue;
  3144. time (&now);
  3145. if (main_log) {
  3146. if (f_ctime > 0L)
  3147. loginfo.log_audit_ctime = f_ctime;
  3148. else {
  3149. loginfo.log_audit_ctime = now;
  3150. }
  3151. main_log = 0;
  3152. } else {
  3153. struct logfileinfo *logp;
  3154. logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
  3155. if (f_ctime > 0L)
  3156. logp->l_ctime = f_ctime;
  3157. else
  3158. logp->l_ctime = now;
  3159. if (f_size > 0)
  3160. logp->l_size = f_size;
  3161. else {
  3162. /* make it the max log size */
  3163. logp->l_size = loginfo.log_audit_maxlogsize;
  3164. }
  3165. logp->l_next = loginfo.log_audit_logchain;
  3166. loginfo.log_audit_logchain = logp;
  3167. }
  3168. loginfo.log_numof_audit_logs++;
  3169. }
  3170. if (LOG_DONE == rval)
  3171. rval = log__check_prevlogs(fp, pathname);
  3172. fclose (fp);
  3173. if (LOG_ERROR == rval)
  3174. if (LOG_SUCCESS == log__fix_rotationinfof(pathname))
  3175. logfile_type = LOGFILE_NEW;
  3176. /* Check if there is a rotation overdue */
  3177. if (loginfo.log_audit_rotationsync_enabled &&
  3178. loginfo.log_audit_rotationunit != LOG_UNIT_HOURS &&
  3179. loginfo.log_audit_rotationunit != LOG_UNIT_MINS &&
  3180. loginfo.log_audit_ctime < loginfo.log_audit_rotationsyncclock - PR_ABS(loginfo.log_audit_rotationtime_secs)) {
  3181. loginfo.log_audit_rotationsyncclock -= PR_ABS(loginfo.log_audit_rotationtime_secs);
  3182. }
  3183. return logfile_type;
  3184. }
  3185. static void
  3186. log__error_emergency(const char *errstr, int reopen, int locked)
  3187. {
  3188. syslog(LOG_ERR, "%s\n", errstr);
  3189. /* emergency open */
  3190. if (!reopen) {
  3191. return;
  3192. }
  3193. if (NULL != loginfo.log_error_fdes) {
  3194. LOG_CLOSE(loginfo.log_error_fdes);
  3195. }
  3196. if (! LOG_OPEN_APPEND(loginfo.log_error_fdes,
  3197. loginfo.log_error_file, loginfo.log_error_mode)) {
  3198. PRErrorCode prerr = PR_GetError();
  3199. syslog(LOG_ERR, "Failed to reopen errors log file, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n", prerr, slapd_pr_strerror(prerr));
  3200. } else {
  3201. vslapd_log_emergency_error(loginfo.log_error_fdes, errstr, locked);
  3202. }
  3203. return;
  3204. }
  3205. /******************************************************************************
  3206. * log__open_errorlogfile
  3207. *
  3208. * Open a new log file. If we have run out of the max logs we can have
  3209. * then delete the oldest file.
  3210. ******************************************************************************/
  3211. static int
  3212. log__open_errorlogfile(int logfile_state, int locked)
  3213. {
  3214. time_t now;
  3215. LOGFD fp = NULL;
  3216. LOGFD fpinfo = NULL;
  3217. char tbuf[TBUFSIZE];
  3218. struct logfileinfo *logp;
  3219. char buffer[BUFSIZ];
  3220. struct passwd *pw = NULL;
  3221. int rc = 0;
  3222. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  3223. if ( slapdFrontendConfig->localuser != NULL &&
  3224. slapdFrontendConfig->localuserinfo != NULL ) {
  3225. pw = slapdFrontendConfig->localuserinfo;
  3226. }
  3227. else {
  3228. PR_snprintf(buffer, sizeof(buffer),
  3229. "Invalid nsslapd-localuser. Cannot open the errors log. Exiting...");
  3230. log__error_emergency(buffer, 0, locked);
  3231. return LOG_UNABLE_TO_OPENFILE;
  3232. }
  3233. if (!locked) LOG_ERROR_LOCK_WRITE( );
  3234. /*
  3235. ** Here we are trying to create a new log file.
  3236. ** If we alredy have one, then we need to rename it as
  3237. ** "filename.time", close it and update it's information
  3238. ** in the array stack.
  3239. */
  3240. if (loginfo.log_error_fdes != NULL) {
  3241. struct logfileinfo *log;
  3242. char newfile[BUFSIZ];
  3243. PRInt64 f_size;
  3244. /* get rid of the old one */
  3245. if ((f_size = log__getfilesize(loginfo.log_error_fdes)) == -1) {
  3246. /* Then assume that we have the max size */
  3247. f_size = loginfo.log_error_maxlogsize;
  3248. }
  3249. /* Check if I have to delete any old file, delete it if it is required.*/
  3250. while (log__delete_error_logfile(1));
  3251. /* close the file */
  3252. if ( loginfo.log_error_fdes != NULL ) {
  3253. LOG_CLOSE(loginfo.log_error_fdes);
  3254. }
  3255. loginfo.log_error_fdes = NULL;
  3256. if ( loginfo.log_error_maxnumlogs > 1 ) {
  3257. log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
  3258. log->l_ctime = loginfo.log_error_ctime;
  3259. log->l_size = f_size;
  3260. log_convert_time (log->l_ctime, tbuf, 1/*short */);
  3261. PR_snprintf(newfile, sizeof(newfile), "%s.%s", loginfo.log_error_file, tbuf);
  3262. if (PR_Rename (loginfo.log_error_file, newfile) != PR_SUCCESS) {
  3263. PRErrorCode prerr = PR_GetError();
  3264. /* Make "FILE EXISTS" error an exception.
  3265. Even if PR_Rename fails with the error, we continue logging.
  3266. */
  3267. if (PR_FILE_EXISTS_ERROR != prerr) {
  3268. PR_snprintf(buffer, sizeof(buffer),
  3269. "Failed to rename errors log file, "
  3270. SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...",
  3271. prerr, slapd_pr_strerror(prerr));
  3272. log__error_emergency(buffer, 1, 1);
  3273. slapi_ch_free((void **)&log);
  3274. if (!locked) LOG_ERROR_UNLOCK_WRITE();
  3275. return LOG_UNABLE_TO_OPENFILE;
  3276. }
  3277. }
  3278. /* add the log to the chain */
  3279. log->l_next = loginfo.log_error_logchain;
  3280. loginfo.log_error_logchain = log;
  3281. loginfo.log_numof_error_logs++;
  3282. }
  3283. }
  3284. /* open a new log file */
  3285. if (! LOG_OPEN_APPEND(fp, loginfo.log_error_file, loginfo.log_error_mode)) {
  3286. PR_snprintf(buffer, sizeof(buffer),
  3287. "Failed to open errors log file %s: error %d (%s); Exiting...",
  3288. loginfo.log_error_file, errno, slapd_system_strerror(errno));
  3289. log__error_emergency(buffer, 1, locked);
  3290. if (!locked) LOG_ERROR_UNLOCK_WRITE();
  3291. /* failed to write to the errors log. should not continue. */
  3292. g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
  3293. /*if I have an old log file -- I should log a message
  3294. ** that I can't open the new file. Let the caller worry
  3295. ** about logging message.
  3296. */
  3297. return LOG_UNABLE_TO_OPENFILE;
  3298. }
  3299. /* make sure the logfile is owned by the localuser. If one of the
  3300. * alternate ns-slapd modes, such as db2bak, tries to log an error
  3301. * at startup, it will create the logfile as root!
  3302. */
  3303. if((rc = slapd_chown_if_not_owner(loginfo.log_error_file, pw->pw_uid, -1)) != 0){
  3304. PR_snprintf(buffer, sizeof(buffer),
  3305. "Failed to chown log file %s: error %d (%s); Exiting...",
  3306. loginfo.log_error_file, errno, slapd_system_strerror(errno));
  3307. log__error_emergency(buffer, 1, locked);
  3308. if (!locked) LOG_ERROR_UNLOCK_WRITE();
  3309. /* failed to write to the errors log. should not continue. */
  3310. g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
  3311. /*if I have an old log file -- I should log a message
  3312. ** that I can't open the new file. Let the caller worry
  3313. ** about logging message.
  3314. */
  3315. return LOG_UNABLE_TO_OPENFILE;
  3316. }
  3317. loginfo.log_error_fdes = fp;
  3318. if (logfile_state == LOGFILE_REOPENED) {
  3319. /* we have all the information */
  3320. if (!locked) LOG_ERROR_UNLOCK_WRITE( );
  3321. return LOG_SUCCESS;
  3322. }
  3323. loginfo.log_error_state |= LOGGING_NEED_TITLE;
  3324. if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_errorinfo_file, loginfo.log_error_mode)) {
  3325. PR_snprintf(buffer, sizeof(buffer),
  3326. "Failed to open/write to errors log file %s: error %d (%s). Exiting...",
  3327. loginfo.log_error_file, errno, slapd_system_strerror(errno));
  3328. log__error_emergency(buffer, 1, locked);
  3329. if (!locked) LOG_ERROR_UNLOCK_WRITE();
  3330. return LOG_UNABLE_TO_OPENFILE;
  3331. }
  3332. /* write the header in the log */
  3333. now = current_time();
  3334. log_convert_time (now, tbuf, 2 /*long */);
  3335. PR_snprintf(buffer, sizeof(buffer),"LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
  3336. LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
  3337. logp = loginfo.log_error_logchain;
  3338. while (logp) {
  3339. log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
  3340. PR_snprintf(buffer, sizeof(buffer), "LOGINFO:%s%s.%s (%lu) (%"
  3341. NSPRI64 "d)\n", PREVLOGFILE, loginfo.log_error_file, tbuf,
  3342. logp->l_ctime, logp->l_size);
  3343. LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
  3344. logp = logp->l_next;
  3345. }
  3346. /* Close the info file. We need only when we need to rotate to the
  3347. ** next log file.
  3348. */
  3349. if (fpinfo) LOG_CLOSE(fpinfo);
  3350. /* This is now the current error log */
  3351. loginfo.log_error_ctime = now;
  3352. if (!locked) LOG_ERROR_UNLOCK_WRITE( );
  3353. return LOG_SUCCESS;
  3354. }
  3355. /******************************************************************************
  3356. * log__open_auditlogfile
  3357. *
  3358. * Open a new log file. If we have run out of the max logs we can have
  3359. * then delete the oldest file.
  3360. ******************************************************************************/
  3361. static int
  3362. log__open_auditlogfile(int logfile_state, int locked)
  3363. {
  3364. time_t now;
  3365. LOGFD fp;
  3366. LOGFD fpinfo = NULL;
  3367. char tbuf[TBUFSIZE];
  3368. struct logfileinfo *logp;
  3369. char buffer[BUFSIZ];
  3370. if (!locked) LOG_AUDIT_LOCK_WRITE( );
  3371. /*
  3372. ** Here we are trying to create a new log file.
  3373. ** If we alredy have one, then we need to rename it as
  3374. ** "filename.time", close it and update it's information
  3375. ** in the array stack.
  3376. */
  3377. if (loginfo.log_audit_fdes != NULL) {
  3378. struct logfileinfo *log;
  3379. char newfile[BUFSIZ];
  3380. PRInt64 f_size;
  3381. /* get rid of the old one */
  3382. if ((f_size = log__getfilesize(loginfo.log_audit_fdes)) == -1) {
  3383. /* Then assume that we have the max size */
  3384. f_size = loginfo.log_audit_maxlogsize;
  3385. }
  3386. /* Check if I have to delete any old file, delete it if it is required. */
  3387. while (log__delete_audit_logfile());
  3388. /* close the file */
  3389. LOG_CLOSE(loginfo.log_audit_fdes);
  3390. loginfo.log_audit_fdes = NULL;
  3391. if ( loginfo.log_audit_maxnumlogs > 1 ) {
  3392. log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
  3393. log->l_ctime = loginfo.log_audit_ctime;
  3394. log->l_size = f_size;
  3395. log_convert_time (log->l_ctime, tbuf, 1 /*short */);
  3396. PR_snprintf(newfile, sizeof(newfile), "%s.%s", loginfo.log_audit_file, tbuf);
  3397. if (PR_Rename (loginfo.log_audit_file, newfile) != PR_SUCCESS) {
  3398. PRErrorCode prerr = PR_GetError();
  3399. /* Make "FILE EXISTS" error an exception.
  3400. Even if PR_Rename fails with the error, we continue logging.
  3401. */
  3402. if (PR_FILE_EXISTS_ERROR != prerr) {
  3403. if (!locked) LOG_AUDIT_UNLOCK_WRITE();
  3404. slapi_ch_free((void**)&log);
  3405. return LOG_UNABLE_TO_OPENFILE;
  3406. }
  3407. }
  3408. /* add the log to the chain */
  3409. log->l_next = loginfo.log_audit_logchain;
  3410. loginfo.log_audit_logchain = log;
  3411. loginfo.log_numof_audit_logs++;
  3412. }
  3413. }
  3414. /* open a new log file */
  3415. if (! LOG_OPEN_APPEND(fp, loginfo.log_audit_file, loginfo.log_audit_mode)) {
  3416. LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
  3417. "errno %d (%s)\n",
  3418. loginfo.log_audit_file, errno, slapd_system_strerror(errno));
  3419. if (!locked) LOG_AUDIT_UNLOCK_WRITE();
  3420. /*if I have an old log file -- I should log a message
  3421. ** that I can't open the new file. Let the caller worry
  3422. ** about logging message.
  3423. */
  3424. return LOG_UNABLE_TO_OPENFILE;
  3425. }
  3426. loginfo.log_audit_fdes = fp;
  3427. if (logfile_state == LOGFILE_REOPENED) {
  3428. /* we have all the information */
  3429. if (!locked) LOG_AUDIT_UNLOCK_WRITE();
  3430. return LOG_SUCCESS;
  3431. }
  3432. loginfo.log_audit_state |= LOGGING_NEED_TITLE;
  3433. if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_auditinfo_file, loginfo.log_audit_mode)) {
  3434. LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
  3435. "errno %d (%s)\n",
  3436. loginfo.log_auditinfo_file, errno, slapd_system_strerror(errno));
  3437. if (!locked) LOG_AUDIT_UNLOCK_WRITE();
  3438. return LOG_UNABLE_TO_OPENFILE;
  3439. }
  3440. /* write the header in the log */
  3441. now = current_time();
  3442. log_convert_time (now, tbuf, 2 /*long */);
  3443. PR_snprintf(buffer, sizeof(buffer), "LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
  3444. LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
  3445. logp = loginfo.log_audit_logchain;
  3446. while ( logp) {
  3447. log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
  3448. PR_snprintf(buffer, sizeof(buffer), "LOGINFO:%s%s.%s (%lu) (%"
  3449. NSPRI64 "d)\n", PREVLOGFILE, loginfo.log_audit_file, tbuf,
  3450. logp->l_ctime, logp->l_size);
  3451. LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
  3452. logp = logp->l_next;
  3453. }
  3454. /* Close the info file. We need only when we need to rotate to the
  3455. ** next log file.
  3456. */
  3457. if (fpinfo) LOG_CLOSE(fpinfo);
  3458. /* This is now the current audit log */
  3459. loginfo.log_audit_ctime = now;
  3460. if (!locked) LOG_AUDIT_UNLOCK_WRITE( );
  3461. return LOG_SUCCESS;
  3462. }
  3463. /*
  3464. ** Log Buffering
  3465. ** only supports access log at this time
  3466. */
  3467. static LogBufferInfo *log_create_buffer(size_t sz)
  3468. {
  3469. LogBufferInfo *lbi;
  3470. lbi = (LogBufferInfo *) slapi_ch_malloc(sizeof(LogBufferInfo));
  3471. lbi->top = (char *) slapi_ch_malloc(sz);
  3472. lbi->current = lbi->top;
  3473. lbi->maxsize = sz;
  3474. lbi->refcount = 0;
  3475. return lbi;
  3476. }
  3477. #if 0
  3478. /* for some reason, we never call this. */
  3479. static void log_destroy_buffer(LogBufferInfo *lbi)
  3480. {
  3481. slapi_ch_free((void *)&(lbi->top));
  3482. slapi_ch_free((void *)&lbi);
  3483. }
  3484. #endif
  3485. /*
  3486. Some notes about this function. It is written the
  3487. way it is for performance reasons.
  3488. Tests showed that on 4 processor systems, there is
  3489. significant contention for the
  3490. lbi->lock. This is because the lock was held for
  3491. the duration of the copy of the
  3492. log message into the buffer. Therefore the routine
  3493. was re-written to avoid holding
  3494. the lock for that time. Instead we gain the lock,
  3495. take a copy of the buffer pointer
  3496. where we need to copy our message, increase the
  3497. size, move the current pointer beyond
  3498. our portion of the buffer, then increment a reference
  3499. count.
  3500. Then we release the lock and do the actual copy
  3501. in to the reserved buffer area.
  3502. We then atomically decrement the reference count.
  3503. The reference count is used to ensure that when
  3504. the buffer is flushed to the
  3505. filesystem, there are no threads left copying
  3506. data into the buffer.
  3507. The wait on zero reference count is implemented
  3508. in the flush routine because
  3509. it is also called from log_access_flush().
  3510. Tests show this speeds up searches by 10% on 4-way systems.
  3511. */
  3512. static void log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2)
  3513. {
  3514. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  3515. size_t size = size1 + size2;
  3516. char* insert_point = NULL;
  3517. /* While holding the lock, we determine if there is space in the buffer for our payload,
  3518. and if we need to flush.
  3519. */
  3520. PR_Lock(lbi->lock);
  3521. if ( ((lbi->current - lbi->top) + size > lbi->maxsize) ||
  3522. (tnl >= loginfo.log_access_rotationsyncclock &&
  3523. loginfo.log_access_rotationsync_enabled) ) {
  3524. log_flush_buffer(lbi, SLAPD_ACCESS_LOG,
  3525. 0 /* do not sync to disk right now */ );
  3526. }
  3527. insert_point = lbi->current;
  3528. lbi->current += size;
  3529. /* Increment the copy refcount */
  3530. PR_AtomicIncrement(&(lbi->refcount));
  3531. PR_Unlock(lbi->lock);
  3532. /* Now we can copy without holding the lock */
  3533. memcpy(insert_point, msg1, size1);
  3534. memcpy(insert_point + size1, msg2, size2);
  3535. /* Decrement the copy refcount */
  3536. PR_AtomicDecrement(&(lbi->refcount));
  3537. /* If we are asked to sync to disk immediately, do so */
  3538. if (!slapdFrontendConfig->accesslogbuffering) {
  3539. PR_Lock(lbi->lock);
  3540. log_flush_buffer(lbi, SLAPD_ACCESS_LOG, 1 /* sync to disk now */ );
  3541. PR_Unlock(lbi->lock);
  3542. }
  3543. }
  3544. /* this function assumes the lock is already acquired */
  3545. /* if sync_now is non-zero, data is flushed to physical storage */
  3546. static void log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now)
  3547. {
  3548. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  3549. if (type == SLAPD_ACCESS_LOG) {
  3550. /* It is only safe to flush once any other threads which are copying are finished */
  3551. while (lbi->refcount > 0) {
  3552. /* It's ok to sleep for a while because we only flush every second or so */
  3553. DS_Sleep (PR_MillisecondsToInterval(1));
  3554. }
  3555. if ((lbi->current - lbi->top) == 0) return;
  3556. if (log__needrotation(loginfo.log_access_fdes,
  3557. SLAPD_ACCESS_LOG) == LOG_ROTATE) {
  3558. if (log__open_accesslogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
  3559. LDAPDebug(LDAP_DEBUG_ANY,
  3560. "LOGINFO: Unable to open access file:%s\n",
  3561. loginfo.log_access_file,0,0);
  3562. lbi->current = lbi->top; /* reset counter to prevent overwriting rest of lbi struct */
  3563. return;
  3564. }
  3565. while (loginfo.log_access_rotationsyncclock <= loginfo.log_access_ctime) {
  3566. loginfo.log_access_rotationsyncclock += PR_ABS(loginfo.log_access_rotationtime_secs);
  3567. }
  3568. }
  3569. if (loginfo.log_access_state & LOGGING_NEED_TITLE) {
  3570. log_write_title(loginfo.log_access_fdes);
  3571. loginfo.log_access_state &= ~LOGGING_NEED_TITLE;
  3572. }
  3573. if (!sync_now && slapdFrontendConfig->accesslogbuffering) {
  3574. LOG_WRITE(loginfo.log_access_fdes, lbi->top, lbi->current - lbi->top, 0);
  3575. } else {
  3576. LOG_WRITE_NOW_NO_ERR(loginfo.log_access_fdes, lbi->top,
  3577. lbi->current - lbi->top, 0);
  3578. }
  3579. lbi->current = lbi->top;
  3580. }
  3581. }
  3582. void log_access_flush()
  3583. {
  3584. LOG_ACCESS_LOCK_WRITE();
  3585. log_flush_buffer(loginfo.log_access_buffer, SLAPD_ACCESS_LOG,
  3586. 1 /* sync to disk now */ );
  3587. LOG_ACCESS_UNLOCK_WRITE();
  3588. }
  3589. /*
  3590. *
  3591. * log_convert_time
  3592. * returns the time converted into the string format.
  3593. *
  3594. */
  3595. static void
  3596. log_convert_time (time_t ctime, char *tbuf, int type)
  3597. {
  3598. struct tm *tmsp, tms;
  3599. (void)localtime_r( &ctime, &tms );
  3600. tmsp = &tms;
  3601. if (type == 1) /* get the short form */
  3602. (void) strftime (tbuf, (size_t) TBUFSIZE, "%Y%m%d-%H%M%S",tmsp);
  3603. else /* wants the long form */
  3604. (void) strftime (tbuf, (size_t) TBUFSIZE, "%d/%b/%Y:%H:%M:%S",tmsp);
  3605. }
  3606. /*
  3607. * log_reverse_convert_time
  3608. * convert the given string formatted time (output from log_convert_time)
  3609. * into time_t
  3610. */
  3611. static time_t
  3612. log_reverse_convert_time(char *tbuf)
  3613. {
  3614. struct tm tm = {0};
  3615. if (strchr(tbuf, '-') && strlen(tbuf) >= 15) {
  3616. /* short format: YYYYmmdd-HHMMSS
  3617. strptime requires whitespace or non-alpha characters between format
  3618. specifiers on some platforms, so convert to an ISO8601-like format
  3619. with separators */
  3620. char tbuf_with_sep[] = "yyyy-mm-dd HH:MM:SS";
  3621. if( sscanf(tbuf, "%4c%2c%2c-%2c%2c%2c", tbuf_with_sep,
  3622. tbuf_with_sep+5, tbuf_with_sep+8, tbuf_with_sep+11,
  3623. tbuf_with_sep+14, tbuf_with_sep+17) != 6 ) {
  3624. return 0;
  3625. }
  3626. strptime(tbuf_with_sep, "%Y-%m-%d %H:%M:%S", &tm);
  3627. } else if (strchr(tbuf, '/') && strchr(tbuf, ':')) { /* long format */
  3628. strptime(tbuf, "%d/%b/%Y:%H:%M:%S", &tm);
  3629. } else {
  3630. return 0;
  3631. }
  3632. tm.tm_isdst = -1;
  3633. return mktime(&tm);
  3634. }
  3635. int
  3636. check_log_max_size( char *maxdiskspace_str,
  3637. char *mlogsize_str,
  3638. int maxdiskspace, /* in megabytes */
  3639. int mlogsize, /* in megabytes */
  3640. char * returntext,
  3641. int logtype)
  3642. {
  3643. slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
  3644. int rc = LDAP_SUCCESS;
  3645. int current_mlogsize = -1; /* in megabytes */
  3646. int current_maxdiskspace = -1; /* in megabytes */
  3647. PRInt64 mlogsizeB; /* in bytes */
  3648. PRInt64 maxdiskspaceB; /* in bytes */
  3649. switch (logtype)
  3650. {
  3651. case SLAPD_ACCESS_LOG:
  3652. current_mlogsize = slapdFrontendConfig->accesslog_maxlogsize;
  3653. current_maxdiskspace = slapdFrontendConfig->accesslog_maxdiskspace;
  3654. break;
  3655. case SLAPD_ERROR_LOG:
  3656. current_mlogsize = slapdFrontendConfig->errorlog_maxlogsize;
  3657. current_maxdiskspace = slapdFrontendConfig->errorlog_maxdiskspace;
  3658. break;
  3659. case SLAPD_AUDIT_LOG:
  3660. current_mlogsize = slapdFrontendConfig->auditlog_maxlogsize;
  3661. current_maxdiskspace = slapdFrontendConfig->auditlog_maxdiskspace;
  3662. break;
  3663. default:
  3664. current_mlogsize = -1;
  3665. current_maxdiskspace = -1;
  3666. }
  3667. if ( maxdiskspace == -1 ) {
  3668. maxdiskspace = current_maxdiskspace;
  3669. }
  3670. if ( maxdiskspace == -1 ) {
  3671. maxdiskspaceB = -1;
  3672. } else {
  3673. maxdiskspaceB = (PRInt64)maxdiskspace * LOG_MB_IN_BYTES;
  3674. }
  3675. if ( mlogsize == -1 ) {
  3676. mlogsize = current_mlogsize;
  3677. }
  3678. if ( mlogsize == -1 ) {
  3679. mlogsizeB = -1;
  3680. } else {
  3681. mlogsizeB = (PRInt64)mlogsize * LOG_MB_IN_BYTES;
  3682. }
  3683. /* If maxdiskspace is negative, it is unlimited. There is
  3684. * no need to compate it to the logsize in this case. */
  3685. if (( maxdiskspace >= 0 ) && ( maxdiskspace < mlogsize ))
  3686. {
  3687. /* fail */
  3688. PR_snprintf ( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  3689. "%s: maxdiskspace \"%d (MB)\" is less than max log size \"%d (MB)\"",
  3690. maxdiskspace_str, maxdiskspace, mlogsize );
  3691. rc = LDAP_OPERATIONS_ERROR;
  3692. }
  3693. switch (logtype)
  3694. {
  3695. case SLAPD_ACCESS_LOG:
  3696. loginfo.log_access_maxlogsize = mlogsizeB;
  3697. loginfo.log_access_maxdiskspace = maxdiskspaceB;
  3698. break;
  3699. case SLAPD_ERROR_LOG:
  3700. loginfo.log_error_maxlogsize = mlogsizeB;
  3701. loginfo.log_error_maxdiskspace = maxdiskspaceB;
  3702. break;
  3703. case SLAPD_AUDIT_LOG:
  3704. loginfo.log_audit_maxlogsize = mlogsizeB;
  3705. loginfo.log_audit_maxdiskspace = maxdiskspaceB;
  3706. break;
  3707. default:
  3708. break;
  3709. }
  3710. return rc;
  3711. }
  3712. /************************************************************************************/
  3713. /* E N D */
  3714. /************************************************************************************/