logrotate.c 90 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811
  1. #include "queue.h"
  2. /* alloca() is defined in stdlib.h in NetBSD */
  3. #if !defined(__NetBSD__) && !defined(__FreeBSD__)
  4. #include <alloca.h>
  5. #endif
  6. #include <limits.h>
  7. #include <ctype.h>
  8. #include <dirent.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <popt.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <sys/stat.h>
  16. #include <sys/wait.h>
  17. #include <time.h>
  18. #include <unistd.h>
  19. #include <glob.h>
  20. #include <locale.h>
  21. #include <sys/types.h>
  22. #include <utime.h>
  23. #include <stdint.h>
  24. #include <libgen.h>
  25. #if defined(SunOS)
  26. #include <limits.h>
  27. #endif
  28. #if !defined(PATH_MAX) && defined(__FreeBSD__)
  29. #include <sys/param.h>
  30. #endif
  31. #include "log.h"
  32. #include "logrotate.h"
  33. static void *prev_context;
  34. #ifdef WITH_SELINUX
  35. #include <selinux/selinux.h>
  36. static int selinux_enabled = 0;
  37. static int selinux_enforce = 0;
  38. #endif
  39. #ifdef WITH_ACL
  40. #include "sys/acl.h"
  41. #define acl_type acl_t
  42. #else
  43. #define acl_type void *
  44. #endif
  45. static acl_type prev_acl = NULL;
  46. #if !defined(GLOB_ABORTED) && defined(GLOB_ABEND)
  47. #define GLOB_ABORTED GLOB_ABEND
  48. #endif
  49. #ifdef PATH_MAX
  50. #define STATEFILE_BUFFER_SIZE 2 * PATH_MAX + 16
  51. #else
  52. #define STATEFILE_BUFFER_SIZE 4096
  53. #endif
  54. #ifdef __hpux
  55. extern int asprintf(char **str, const char *fmt, ...);
  56. #endif
  57. /* Number of seconds in a day */
  58. #define DAY_SECONDS 86400
  59. struct logState {
  60. char *fn;
  61. struct tm lastRotated; /* only tm_hour, tm_mday, tm_mon, tm_year are good! */
  62. struct stat sb;
  63. int doRotate;
  64. int isUsed; /* True if there is real log file in system for this state. */
  65. LIST_ENTRY(logState) list;
  66. };
  67. struct logNames {
  68. char *firstRotated;
  69. char *disposeName;
  70. char *finalName;
  71. char *dirName;
  72. char *baseName;
  73. };
  74. struct compData {
  75. int prefix_len;
  76. const char *dformat;
  77. };
  78. static struct logStateList {
  79. LIST_HEAD(stateSet, logState) head;
  80. } **states;
  81. int numLogs = 0;
  82. int debug = 0;
  83. static unsigned int hashSize;
  84. static const char *mailCommand = DEFAULT_MAIL_COMMAND;
  85. static time_t nowSecs = 0;
  86. static uid_t save_euid;
  87. static gid_t save_egid;
  88. static int globerr(const char *pathname, int theerr)
  89. {
  90. message(MESS_ERROR, "error accessing %s: %s\n", pathname,
  91. strerror(theerr));
  92. /* We want the glob operation to continue, so return 0 */
  93. return 1;
  94. }
  95. #if defined(HAVE_STRPTIME) && defined(HAVE_QSORT)
  96. /* We could switch to qsort_r to get rid of this global variable,
  97. * but qsort_r is not portable enough (Linux vs. *BSD vs ...)... */
  98. static struct compData _compData;
  99. static int compGlobResult(const void *result1, const void *result2) {
  100. struct tm time_tmp;
  101. time_t t1, t2;
  102. const char *r1 = *(const char **)(result1);
  103. const char *r2 = *(const char **)(result2);
  104. memset(&time_tmp, 0, sizeof(struct tm));
  105. strptime(r1 + _compData.prefix_len, _compData.dformat, &time_tmp);
  106. t1 = mktime(&time_tmp);
  107. memset(&time_tmp, 0, sizeof(struct tm));
  108. strptime(r2 + _compData.prefix_len, _compData.dformat, &time_tmp);
  109. t2 = mktime(&time_tmp);
  110. if (t1 < t2) return -1;
  111. if (t1 > t2) return 1;
  112. return 0;
  113. }
  114. static void sortGlobResult(glob_t *result, int prefix_len, const char *dformat) {
  115. if (!dformat || *dformat == '\0') {
  116. return;
  117. }
  118. _compData.prefix_len = prefix_len;
  119. _compData.dformat = dformat;
  120. qsort(result->gl_pathv, result->gl_pathc, sizeof(char *), compGlobResult);
  121. }
  122. #else
  123. static void sortGlobResult(glob_t *result, int prefix_len, const char *dformat) {
  124. /* TODO */
  125. }
  126. #endif
  127. int switch_user(uid_t user, gid_t group) {
  128. save_egid = getegid();
  129. save_euid = geteuid();
  130. if (save_euid == user && save_egid == group)
  131. return 0;
  132. message(MESS_DEBUG, "switching euid to %u and egid to %u\n",
  133. (unsigned) user, (unsigned) group);
  134. if (setegid(group) || seteuid(user)) {
  135. message(MESS_ERROR, "error switching euid to %u and egid to %u: %s\n",
  136. (unsigned) user, (unsigned) group, strerror(errno));
  137. return 1;
  138. }
  139. return 0;
  140. }
  141. static int switch_user_permanently(const struct logInfo *log) {
  142. gid_t group = getegid();
  143. uid_t user = geteuid();
  144. if (!(log->flags & LOG_FLAG_SU)) {
  145. return 0;
  146. }
  147. if (getuid() == user && getgid() == group)
  148. return 0;
  149. /* switch to full root first */
  150. if (setgid(getgid()) || setuid(getuid())) {
  151. message(MESS_ERROR, "error getting rid of euid != uid\n");
  152. return 1;
  153. }
  154. message(MESS_DEBUG, "switching uid to %u and gid to %u\n",
  155. (unsigned) user, (unsigned) group);
  156. if (setgid(group) || setuid(user)) {
  157. message(MESS_ERROR, "error switching euid to %u and egid to %u: %s\n",
  158. (unsigned) user, (unsigned) group, strerror(errno));
  159. return 1;
  160. }
  161. return 0;
  162. }
  163. int switch_user_back(void) {
  164. return switch_user(save_euid, save_egid);
  165. }
  166. static int switch_user_back_permanently(void) {
  167. gid_t tmp_egid = save_egid;
  168. uid_t tmp_euid = save_euid;
  169. int ret = switch_user(save_euid, save_egid);
  170. save_euid = tmp_euid;
  171. save_egid = tmp_egid;
  172. return ret;
  173. }
  174. static void unescape(char *arg)
  175. {
  176. char *p = arg;
  177. char *next;
  178. char escaped;
  179. while ((next = strchr(p, '\\')) != NULL) {
  180. p = next;
  181. switch (p[1]) {
  182. case 'n':
  183. escaped = '\n';
  184. break;
  185. case '\\':
  186. escaped = '\\';
  187. break;
  188. default:
  189. ++p;
  190. continue;
  191. }
  192. /* Overwrite the backslash with the intended character,
  193. * and shift everything down one */
  194. *p++ = escaped;
  195. memmove(p, p+1, 1 + strlen(p+1));
  196. }
  197. }
  198. #define HASH_SIZE_MIN 64
  199. static int allocateHash(unsigned int hs)
  200. {
  201. unsigned int i;
  202. /* Enforce some reasonable minimum hash size */
  203. if (hs < HASH_SIZE_MIN)
  204. hs = HASH_SIZE_MIN;
  205. message(MESS_DEBUG, "Allocating hash table for state file, size %u entries\n",
  206. hs);
  207. states = calloc(hs, sizeof(struct logStateList *));
  208. if (states == NULL) {
  209. message(MESS_ERROR, "could not allocate memory for "
  210. "hash table\n");
  211. return 1;
  212. }
  213. for (i = 0; i < hs; i++) {
  214. states[i] = malloc(sizeof *states[0]);
  215. if (states[i] == NULL) {
  216. message(MESS_ERROR, "could not allocate memory for "
  217. "hash element\n");
  218. return 1;
  219. }
  220. LIST_INIT(&(states[i]->head));
  221. }
  222. hashSize = hs;
  223. return 0;
  224. }
  225. #define HASH_CONST 13
  226. static int hashIndex(const char *fn)
  227. {
  228. unsigned hash = 0;
  229. if (!hashSize)
  230. /* hash table not yet allocated */
  231. return -1;
  232. while (*fn) {
  233. hash *= HASH_CONST;
  234. hash += *fn++;
  235. }
  236. return hash % hashSize;
  237. }
  238. /* safe implementation of dup2(oldfd, nefd) followed by close(oldfd) */
  239. static int movefd(int oldfd, int newfd)
  240. {
  241. int rc;
  242. if (oldfd == newfd)
  243. /* avoid accidental close of newfd in case it is equal to oldfd */
  244. return 0;
  245. rc = dup2(oldfd, newfd);
  246. if (rc == 0)
  247. close(oldfd);
  248. return rc;
  249. }
  250. static int setSecCtx(int fdSrc, const char *src, void **pPrevCtx)
  251. {
  252. #ifdef WITH_SELINUX
  253. security_context_t srcCtx;
  254. *pPrevCtx = NULL;
  255. if (!selinux_enabled)
  256. /* pretend success */
  257. return 0;
  258. /* read security context of fdSrc */
  259. if (fgetfilecon_raw(fdSrc, &srcCtx) < 0) {
  260. if (errno == ENOTSUP)
  261. /* pretend success */
  262. return 0;
  263. message(MESS_ERROR, "getting file context %s: %s\n", src,
  264. strerror(errno));
  265. return selinux_enforce;
  266. }
  267. /* save default security context for restoreSecCtx() */
  268. if (getfscreatecon_raw((security_context_t *)pPrevCtx) < 0) {
  269. message(MESS_ERROR, "getting default context: %s\n", strerror(errno));
  270. return selinux_enforce;
  271. }
  272. /* set default security context to match fdSrc */
  273. if (setfscreatecon_raw(srcCtx) < 0) {
  274. message(MESS_ERROR, "setting default context to %s: %s\n", srcCtx,
  275. strerror(errno));
  276. freecon(srcCtx);
  277. return selinux_enforce;
  278. }
  279. message(MESS_DEBUG, "set default create context to %s\n", srcCtx);
  280. freecon(srcCtx);
  281. #else
  282. (void) fdSrc;
  283. (void) src;
  284. (void) pPrevCtx;
  285. #endif
  286. return 0;
  287. }
  288. static int setSecCtxByName(const char *src, void **pPrevCtx)
  289. {
  290. int hasErrors = 0;
  291. #ifdef WITH_SELINUX
  292. int fd = open(src, O_RDONLY | O_NOFOLLOW);
  293. if (fd < 0) {
  294. message(MESS_ERROR, "error opening %s: %s\n", src, strerror(errno));
  295. return 1;
  296. }
  297. hasErrors = setSecCtx(fd, src, pPrevCtx);
  298. close(fd);
  299. #else
  300. (void) src;
  301. (void) pPrevCtx;
  302. #endif
  303. return hasErrors;
  304. }
  305. static void restoreSecCtx(void **pPrevCtx)
  306. {
  307. #ifdef WITH_SELINUX
  308. const security_context_t prevCtx = (security_context_t) *pPrevCtx;
  309. if (!prevCtx)
  310. /* no security context saved for restoration */
  311. return;
  312. /* set default security context to the previously stored one */
  313. if (selinux_enabled && setfscreatecon_raw(prevCtx) < 0)
  314. message(MESS_ERROR, "setting default context to %s: %s\n", prevCtx,
  315. strerror(errno));
  316. /* free the memory allocated to save the security context */
  317. freecon(prevCtx);
  318. *pPrevCtx = NULL;
  319. #else
  320. (void) pPrevCtx;
  321. #endif
  322. }
  323. static struct logState *newState(const char *fn)
  324. {
  325. struct tm now = *localtime(&nowSecs);
  326. struct logState *new;
  327. time_t lr_time;
  328. message(MESS_DEBUG, "Creating new state\n");
  329. if ((new = malloc(sizeof(*new))) == NULL)
  330. return NULL;
  331. if ((new->fn = strdup(fn)) == NULL) {
  332. free(new);
  333. return NULL;
  334. }
  335. new->doRotate = 0;
  336. new->isUsed = 0;
  337. memset(&new->lastRotated, 0, sizeof(new->lastRotated));
  338. new->lastRotated.tm_hour = now.tm_hour;
  339. new->lastRotated.tm_mday = now.tm_mday;
  340. new->lastRotated.tm_mon = now.tm_mon;
  341. new->lastRotated.tm_year = now.tm_year;
  342. new->lastRotated.tm_isdst = now.tm_isdst;
  343. /* fill in the rest of the new->lastRotated fields */
  344. lr_time = mktime(&new->lastRotated);
  345. new->lastRotated = *localtime(&lr_time);
  346. return new;
  347. }
  348. static struct logState *findState(const char *fn)
  349. {
  350. const int i = hashIndex(fn);
  351. struct logState *p;
  352. if (i < 0)
  353. /* hash table not yet allocated */
  354. return NULL;
  355. for (p = states[i]->head.lh_first; p != NULL; p = p->list.le_next)
  356. if (!strcmp(fn, p->fn))
  357. break;
  358. /* new state */
  359. if (p == NULL) {
  360. if ((p = newState(fn)) == NULL)
  361. return NULL;
  362. LIST_INSERT_HEAD(&(states[i]->head), p, list);
  363. }
  364. return p;
  365. }
  366. static int runScript(struct logInfo *log, char *logfn, char *logrotfn, char *script)
  367. {
  368. int rc;
  369. if (debug) {
  370. message(MESS_DEBUG, "running script with args %s %s: \"%s\"\n",
  371. logfn, logrotfn, script);
  372. return 0;
  373. }
  374. if (!fork()) {
  375. if (log->flags & LOG_FLAG_SU) {
  376. if (switch_user_back_permanently() != 0) {
  377. exit(1);
  378. }
  379. }
  380. execl("/bin/sh", "sh", "-c", script, "logrotate_script", logfn, logrotfn, (char *) NULL);
  381. exit(1);
  382. }
  383. wait(&rc);
  384. return rc;
  385. }
  386. #ifdef WITH_ACL
  387. static int is_acl_well_supported(int err)
  388. {
  389. switch (err) {
  390. case ENOTSUP: /* no file system support */
  391. case EINVAL: /* acl does not point to a valid ACL */
  392. case ENOSYS: /* compatibility - acl_(g|s)et_fd(3) should never return this */
  393. case EBUSY: /* compatibility - acl_(g|s)et_fd(3) should never return this */
  394. return 0;
  395. default:
  396. return 1;
  397. }
  398. }
  399. #endif /* WITH_ACL */
  400. static int createOutputFile(char *fileName, int flags, struct stat *sb,
  401. acl_type acl, int force_mode)
  402. {
  403. int fd = -1;
  404. struct stat sb_create;
  405. int acl_set = 0;
  406. int i;
  407. for (i = 0; i < 2; ++i) {
  408. struct tm now;
  409. size_t fileName_size, buf_size;
  410. char *backupName, *ptr;
  411. fd = open(fileName, (flags | O_EXCL | O_NOFOLLOW),
  412. (S_IRUSR | S_IWUSR) & sb->st_mode);
  413. if ((fd >= 0) || (errno != EEXIST))
  414. break;
  415. /* the destination file already exists, while it should not */
  416. now = *localtime(&nowSecs);
  417. fileName_size = strlen(fileName);
  418. buf_size = fileName_size + sizeof("-YYYYMMDDHH.backup");
  419. backupName = alloca(buf_size);
  420. ptr = backupName;
  421. /* construct backupName starting with fileName */
  422. strcpy(ptr, fileName);
  423. ptr += fileName_size;
  424. buf_size -= fileName_size;
  425. /* append the -YYYYMMDDHH time stamp and the .backup suffix */
  426. ptr += strftime(ptr, buf_size, "-%Y%m%d%H", &now);
  427. strcpy(ptr, ".backup");
  428. message(MESS_ERROR, "destination %s already exists, renaming to %s\n",
  429. fileName, backupName);
  430. if (rename(fileName, backupName) != 0) {
  431. message(MESS_ERROR, "error renaming already existing output file"
  432. " %s to %s: %s\n", fileName, backupName, strerror(errno));
  433. return -1;
  434. }
  435. /* existing file renamed, try it once again */
  436. }
  437. if (fd < 0) {
  438. message(MESS_ERROR, "error creating output file %s: %s\n",
  439. fileName, strerror(errno));
  440. return -1;
  441. }
  442. if (fchmod(fd, (S_IRUSR | S_IWUSR) & sb->st_mode)) {
  443. message(MESS_ERROR, "error setting mode of %s: %s\n",
  444. fileName, strerror(errno));
  445. close(fd);
  446. return -1;
  447. }
  448. if (fstat(fd, &sb_create)) {
  449. message(MESS_ERROR, "fstat of %s failed: %s\n", fileName,
  450. strerror(errno));
  451. close(fd);
  452. return -1;
  453. }
  454. if ((sb_create.st_uid != sb->st_uid || sb_create.st_gid != sb->st_gid) &&
  455. fchown(fd, sb->st_uid, sb->st_gid)) {
  456. message(MESS_ERROR, "error setting owner of %s to uid %u and gid %u: %s\n",
  457. fileName, (unsigned) sb->st_uid, (unsigned) sb->st_gid, strerror(errno));
  458. close(fd);
  459. return -1;
  460. }
  461. #ifdef WITH_ACL
  462. if (!force_mode && acl) {
  463. if (acl_set_fd(fd, acl) == -1) {
  464. if (is_acl_well_supported(errno)) {
  465. message(MESS_ERROR, "setting ACL for %s: %s\n",
  466. fileName, strerror(errno));
  467. close(fd);
  468. return -1;
  469. }
  470. acl_set = 0;
  471. }
  472. else {
  473. acl_set = 1;
  474. }
  475. }
  476. #else
  477. (void) acl_set;
  478. #endif
  479. if (!acl_set || force_mode) {
  480. if (fchmod(fd, sb->st_mode)) {
  481. message(MESS_ERROR, "error setting mode of %s: %s\n",
  482. fileName, strerror(errno));
  483. close(fd);
  484. return -1;
  485. }
  486. }
  487. return fd;
  488. }
  489. #define DIGITS 12
  490. /* unlink, but try to call shred from GNU coreutils if LOG_FLAG_SHRED
  491. * is enabled (in that case fd needs to be a valid file descriptor) */
  492. static int shred_file(int fd, char *filename, struct logInfo *log)
  493. {
  494. char count[DIGITS]; /* that's a lot of shredding :) */
  495. const char **fullCommand;
  496. int id = 0;
  497. int status;
  498. if (log->preremove) {
  499. message(MESS_DEBUG, "running preremove script\n");
  500. if (runScript(log, filename, NULL, log->preremove)) {
  501. message(MESS_ERROR,
  502. "error running preremove script "
  503. "for %s of '%s'. Not removing this file.\n",
  504. filename, log->pattern);
  505. /* What ever was supposed to happen did not happen,
  506. * therefore do not unlink the file yet. */
  507. return 1;
  508. }
  509. }
  510. if (!(log->flags & LOG_FLAG_SHRED)) {
  511. goto unlink_file;
  512. }
  513. message(MESS_DEBUG, "Using shred to remove the file %s\n", filename);
  514. if (log->shred_cycles != 0) {
  515. fullCommand = alloca(sizeof(*fullCommand) * 6);
  516. }
  517. else {
  518. fullCommand = alloca(sizeof(*fullCommand) * 4);
  519. }
  520. fullCommand[id++] = "shred";
  521. fullCommand[id++] = "-u";
  522. if (log->shred_cycles != 0) {
  523. fullCommand[id++] = "-n";
  524. snprintf(count, DIGITS - 1, "%d", log->shred_cycles);
  525. fullCommand[id++] = count;
  526. }
  527. fullCommand[id++] = "-";
  528. fullCommand[id++] = NULL;
  529. if (!fork()) {
  530. movefd(fd, STDOUT_FILENO);
  531. if (switch_user_permanently(log) != 0) {
  532. exit(1);
  533. }
  534. execvp(fullCommand[0], (void *) fullCommand);
  535. exit(1);
  536. }
  537. wait(&status);
  538. if (!WIFEXITED(status) || WEXITSTATUS(status)) {
  539. message(MESS_ERROR, "Failed to shred %s\n, trying unlink", filename);
  540. return unlink(filename);
  541. }
  542. /* We have to unlink it after shred anyway,
  543. * because it doesn't remove the file itself */
  544. unlink_file:
  545. if (unlink(filename) == 0)
  546. return 0;
  547. if (errno != ENOENT)
  548. return 1;
  549. /* unlink of log file that no longer exists is not a fatal error */
  550. message(MESS_ERROR, "error unlinking log file %s: %s\n", filename,
  551. strerror(errno));
  552. return 0;
  553. }
  554. static int removeLogFile(char *name, struct logInfo *log)
  555. {
  556. int fd = -1;
  557. int result = 0;
  558. message(MESS_DEBUG, "removing old log %s\n", name);
  559. if (log->flags & LOG_FLAG_SHRED) {
  560. fd = open(name, O_RDWR | O_NOFOLLOW);
  561. if (fd < 0) {
  562. message(MESS_ERROR, "error opening %s: %s\n",
  563. name, strerror(errno));
  564. return 1;
  565. }
  566. }
  567. if (!debug && shred_file(fd, name, log)) {
  568. message(MESS_ERROR, "Failed to remove old log %s: %s\n",
  569. name, strerror(errno));
  570. result = 1;
  571. }
  572. if (fd != -1)
  573. close(fd);
  574. return result;
  575. }
  576. static void setAtimeMtime(const char *filename, const struct stat *sb)
  577. {
  578. /* If we can't change atime/mtime, it's not a disaster. It might
  579. possibly fail under SELinux. But do try to preserve the
  580. fractional part if we have utimensat(). */
  581. #if defined HAVE_UTIMENSAT && !defined(__APPLE__)
  582. struct timespec ts[2];
  583. ts[0] = sb->st_atim;
  584. ts[1] = sb->st_mtim;
  585. utimensat(AT_FDCWD, filename, ts, 0);
  586. #else
  587. struct utimbuf utim;
  588. utim.actime = sb->st_atime;
  589. utim.modtime = sb->st_mtime;
  590. utime(filename, &utim);
  591. #endif
  592. }
  593. static int compressLogFile(char *name, struct logInfo *log, struct stat *sb)
  594. {
  595. char *compressedName;
  596. char *envInFilename;
  597. const char **fullCommand;
  598. int inFile;
  599. int outFile;
  600. int i;
  601. int status;
  602. int compressPipe[2];
  603. char buff[4092];
  604. int error_printed = 0;
  605. void *prevCtx;
  606. message(MESS_DEBUG, "compressing log with: %s\n", log->compress_prog);
  607. if (debug)
  608. return 0;
  609. fullCommand = alloca(sizeof(*fullCommand) *
  610. (log->compress_options_count + 2));
  611. fullCommand[0] = log->compress_prog;
  612. for (i = 0; i < log->compress_options_count; i++)
  613. fullCommand[i + 1] = log->compress_options_list[i];
  614. fullCommand[log->compress_options_count + 1] = NULL;
  615. compressedName = alloca(strlen(name) + strlen(log->compress_ext) + 2);
  616. sprintf(compressedName, "%s%s", name, log->compress_ext);
  617. if ((inFile = open(name, O_RDWR | O_NOFOLLOW)) < 0) {
  618. message(MESS_ERROR, "unable to open %s for compression\n", name);
  619. return 1;
  620. }
  621. if (setSecCtx(inFile, name, &prevCtx) != 0) {
  622. /* error msg already printed */
  623. close(inFile);
  624. return 1;
  625. }
  626. #ifdef WITH_ACL
  627. if ((prev_acl = acl_get_fd(inFile)) == NULL) {
  628. if (is_acl_well_supported(errno)) {
  629. message(MESS_ERROR, "getting file ACL %s: %s\n",
  630. name, strerror(errno));
  631. restoreSecCtx(&prevCtx);
  632. close(inFile);
  633. return 1;
  634. }
  635. }
  636. #endif
  637. outFile =
  638. createOutputFile(compressedName, O_RDWR | O_CREAT, sb, prev_acl, 0);
  639. restoreSecCtx(&prevCtx);
  640. #ifdef WITH_ACL
  641. if (prev_acl) {
  642. acl_free(prev_acl);
  643. prev_acl = NULL;
  644. }
  645. #endif
  646. if (outFile < 0) {
  647. close(inFile);
  648. return 1;
  649. }
  650. /* pipe used to capture stderr of the compress process */
  651. if (pipe(compressPipe) < 0) {
  652. message(MESS_ERROR, "error opening pipe for compress: %s",
  653. strerror(errno));
  654. close(inFile);
  655. close(outFile);
  656. return 1;
  657. }
  658. if (!fork()) {
  659. /* close read end of pipe in the child process */
  660. close(compressPipe[0]);
  661. movefd(inFile, STDIN_FILENO);
  662. movefd(outFile, STDOUT_FILENO);
  663. if (switch_user_permanently(log) != 0) {
  664. exit(1);
  665. }
  666. movefd(compressPipe[1], STDERR_FILENO);
  667. envInFilename = alloca(strlen("LOGROTATE_COMPRESSED_FILENAME=") + strlen(name) + 2);
  668. sprintf(envInFilename, "LOGROTATE_COMPRESSED_FILENAME=%s", name);
  669. putenv(envInFilename);
  670. execvp(fullCommand[0], (void *) fullCommand);
  671. exit(1);
  672. }
  673. /* close write end of pipe in the parent process */
  674. close(compressPipe[1]);
  675. while ((i = read(compressPipe[0], buff, sizeof(buff) - 1)) > 0) {
  676. if (!error_printed) {
  677. error_printed = 1;
  678. message(MESS_ERROR, "Compressing program wrote following message "
  679. "to stderr when compressing log %s:\n", name);
  680. }
  681. buff[i] = '\0';
  682. fprintf(stderr, "%s", buff);
  683. }
  684. close(compressPipe[0]);
  685. wait(&status);
  686. fsync(outFile);
  687. close(outFile);
  688. if (!WIFEXITED(status) || WEXITSTATUS(status)) {
  689. message(MESS_ERROR, "failed to compress log %s\n", name);
  690. close(inFile);
  691. unlink(compressedName);
  692. return 1;
  693. }
  694. setAtimeMtime(compressedName, sb);
  695. shred_file(inFile, name, log);
  696. close(inFile);
  697. return 0;
  698. }
  699. static int mailLog(struct logInfo *log, char *logFile, const char *mailComm,
  700. char *uncompressCommand, char *address, char *subject)
  701. {
  702. int mailInput;
  703. pid_t mailChild, uncompressChild = 0;
  704. int mailStatus, uncompressStatus;
  705. int uncompressPipe[2];
  706. char * const mailArgv[] = { (char *) mailComm, (char *) "-s", subject, address, NULL };
  707. int rc = 0;
  708. if ((mailInput = open(logFile, O_RDONLY | O_NOFOLLOW)) < 0) {
  709. message(MESS_ERROR, "failed to open %s for mailing: %s\n", logFile,
  710. strerror(errno));
  711. return 1;
  712. }
  713. if (uncompressCommand) {
  714. /* pipe used to capture ouput of the uncompress process */
  715. if (pipe(uncompressPipe) < 0) {
  716. message(MESS_ERROR, "error opening pipe for uncompress: %s",
  717. strerror(errno));
  718. close(mailInput);
  719. return 1;
  720. }
  721. if (!(uncompressChild = fork())) {
  722. /* uncompress child */
  723. /* close read end of pipe in the child process */
  724. close(uncompressPipe[0]);
  725. movefd(mailInput, STDIN_FILENO);
  726. movefd(uncompressPipe[1], STDOUT_FILENO);
  727. if (switch_user_permanently(log) != 0) {
  728. exit(1);
  729. }
  730. execlp(uncompressCommand, uncompressCommand, (char *) NULL);
  731. exit(1);
  732. }
  733. close(mailInput);
  734. mailInput = uncompressPipe[0];
  735. close(uncompressPipe[1]);
  736. }
  737. if (!(mailChild = fork())) {
  738. movefd(mailInput, STDIN_FILENO);
  739. close(STDOUT_FILENO);
  740. /* mail command runs as root */
  741. if (log->flags & LOG_FLAG_SU) {
  742. if (switch_user_back_permanently() != 0) {
  743. exit(1);
  744. }
  745. }
  746. execvp(mailArgv[0], mailArgv);
  747. exit(1);
  748. }
  749. close(mailInput);
  750. waitpid(mailChild, &mailStatus, 0);
  751. if (!WIFEXITED(mailStatus) || WEXITSTATUS(mailStatus)) {
  752. message(MESS_ERROR, "mail command failed for %s\n", logFile);
  753. rc = 1;
  754. }
  755. if (uncompressCommand) {
  756. waitpid(uncompressChild, &uncompressStatus, 0);
  757. if (!WIFEXITED(uncompressStatus) || WEXITSTATUS(uncompressStatus)) {
  758. message(MESS_ERROR, "uncompress command failed mailing %s\n",
  759. logFile);
  760. rc = 1;
  761. }
  762. }
  763. return rc;
  764. }
  765. static int mailLogWrapper(char *mailFilename, const char *mailComm,
  766. int logNum, struct logInfo *log)
  767. {
  768. /* uncompress already compressed log files before mailing them */
  769. char *uncompress_prog = (log->flags & LOG_FLAG_COMPRESS)
  770. ? log->uncompress_prog
  771. : NULL;
  772. char *subject = mailFilename;
  773. if (log->flags & LOG_FLAG_MAILFIRST) {
  774. if (log->flags & LOG_FLAG_DELAYCOMPRESS)
  775. /* the log we are mailing has not been compressed yet */
  776. uncompress_prog = NULL;
  777. if (uncompress_prog)
  778. /* use correct subject when mailfirst is enabled */
  779. subject = log->files[logNum];
  780. }
  781. return mailLog(log, mailFilename, mailComm, uncompress_prog,
  782. log->logAddress, subject);
  783. }
  784. /* Use a heuristic to determine whether stat buffer SB comes from a file
  785. with sparse blocks. If the file has fewer blocks than would normally
  786. be needed for a file of its size, then at least one of the blocks in
  787. the file is a hole. In that case, return true. */
  788. static int is_probably_sparse(struct stat const *sb)
  789. {
  790. #if defined(HAVE_STRUCT_STAT_ST_BLOCKS) && defined(HAVE_STRUCT_STAT_ST_BLKSIZE)
  791. return (S_ISREG (sb->st_mode)
  792. && sb->st_blocks < sb->st_size / sb->st_blksize);
  793. #else
  794. return 0;
  795. #endif
  796. }
  797. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  798. /* Return whether the buffer consists entirely of NULs.
  799. Note the word after the buffer must be non NUL. */
  800. static int is_nul (void const *buf, size_t bufsize)
  801. {
  802. char const *cbuf = buf;
  803. char const *cp = buf;
  804. /* Find the first nonzero *byte*, or the sentinel. */
  805. while (*cp++ == 0)
  806. continue;
  807. return cbuf + bufsize < cp;
  808. }
  809. static size_t full_write(int fd, const void *buf, size_t count)
  810. {
  811. size_t total = 0;
  812. const char *ptr = (const char *) buf;
  813. while (count > 0)
  814. {
  815. size_t n_rw;
  816. for (;;)
  817. {
  818. n_rw = write (fd, buf, count);
  819. if (errno == EINTR)
  820. continue;
  821. else
  822. break;
  823. }
  824. if (n_rw == (size_t) -1)
  825. break;
  826. if (n_rw == 0)
  827. break;
  828. total += n_rw;
  829. ptr += n_rw;
  830. count -= n_rw;
  831. }
  832. return total;
  833. }
  834. static int sparse_copy(int src_fd, int dest_fd, struct stat *sb,
  835. const char *saveLog, const char *currLog)
  836. {
  837. int make_holes = is_probably_sparse(sb);
  838. size_t max_n_read = SIZE_MAX;
  839. int last_write_made_hole = 0;
  840. off_t total_n_read = 0;
  841. char buf[BUFSIZ + 1];
  842. while (max_n_read) {
  843. int make_hole = 0;
  844. ssize_t n_read = read (src_fd, buf, MIN (max_n_read, BUFSIZ));
  845. if (n_read < 0) {
  846. if (errno == EINTR) {
  847. continue;
  848. }
  849. message(MESS_ERROR, "error reading %s: %s\n",
  850. currLog, strerror(errno));
  851. return 0;
  852. }
  853. if (n_read == 0)
  854. break;
  855. max_n_read -= n_read;
  856. total_n_read += n_read;
  857. if (make_holes) {
  858. /* Sentinel required by is_nul(). */
  859. buf[n_read] = '\1';
  860. if ((make_hole = is_nul(buf, n_read))) {
  861. if (lseek (dest_fd, n_read, SEEK_CUR) < 0) {
  862. message(MESS_ERROR, "error seeking %s: %s\n",
  863. saveLog, strerror(errno));
  864. return 0;
  865. }
  866. }
  867. }
  868. if (!make_hole) {
  869. size_t n = n_read;
  870. if (full_write (dest_fd, buf, n) != n) {
  871. message(MESS_ERROR, "error writing to %s: %s\n",
  872. saveLog, strerror(errno));
  873. return 0;
  874. }
  875. }
  876. last_write_made_hole = make_hole;
  877. }
  878. if (last_write_made_hole) {
  879. if (ftruncate(dest_fd, total_n_read) < 0) {
  880. message(MESS_ERROR, "error ftruncate %s: %s\n",
  881. saveLog, strerror(errno));
  882. return 0;
  883. }
  884. }
  885. return 1;
  886. }
  887. static int copyTruncate(char *currLog, char *saveLog, struct stat *sb,
  888. int flags, int skip_copy)
  889. {
  890. int rc = 1;
  891. int fdcurr = -1, fdsave = -1;
  892. void *prevCtx;
  893. message(MESS_DEBUG, "copying %s to %s\n", currLog, saveLog);
  894. if (!debug) {
  895. /* read access is sufficient for 'copy' but not for 'copytruncate' */
  896. const int read_only = (flags & LOG_FLAG_COPY)
  897. && !(flags & LOG_FLAG_COPYTRUNCATE);
  898. if ((fdcurr = open(currLog, ((read_only) ? O_RDONLY : O_RDWR) | O_NOFOLLOW)) < 0) {
  899. message(MESS_ERROR, "error opening %s: %s\n", currLog,
  900. strerror(errno));
  901. goto fail;
  902. }
  903. if (!skip_copy) {
  904. if (setSecCtx(fdcurr, currLog, &prevCtx) != 0) {
  905. /* error msg already printed */
  906. goto fail;
  907. }
  908. #ifdef WITH_ACL
  909. if ((prev_acl = acl_get_fd(fdcurr)) == NULL) {
  910. if (is_acl_well_supported(errno)) {
  911. message(MESS_ERROR, "getting file ACL %s: %s\n",
  912. currLog, strerror(errno));
  913. restoreSecCtx(&prevCtx);
  914. goto fail;
  915. }
  916. }
  917. #endif /* WITH_ACL */
  918. fdsave = createOutputFile(saveLog, O_WRONLY | O_CREAT, sb, prev_acl, 0);
  919. restoreSecCtx(&prevCtx);
  920. #ifdef WITH_ACL
  921. if (prev_acl) {
  922. acl_free(prev_acl);
  923. prev_acl = NULL;
  924. }
  925. #endif
  926. if (fdsave < 0)
  927. goto fail;
  928. if (sparse_copy(fdcurr, fdsave, sb, saveLog, currLog) != 1) {
  929. message(MESS_ERROR, "error copying %s to %s: %s\n", currLog,
  930. saveLog, strerror(errno));
  931. unlink(saveLog);
  932. goto fail;
  933. }
  934. }
  935. }
  936. if (flags & LOG_FLAG_COPYTRUNCATE) {
  937. message(MESS_DEBUG, "truncating %s\n", currLog);
  938. if (!debug) {
  939. if (fdsave >= 0)
  940. fsync(fdsave);
  941. if (ftruncate(fdcurr, 0)) {
  942. message(MESS_ERROR, "error truncating %s: %s\n", currLog,
  943. strerror(errno));
  944. goto fail;
  945. }
  946. }
  947. } else
  948. message(MESS_DEBUG, "Not truncating %s\n", currLog);
  949. rc = 0;
  950. fail:
  951. if (fdcurr >= 0) {
  952. close(fdcurr);
  953. }
  954. if (fdsave >= 0) {
  955. close(fdsave);
  956. }
  957. return rc;
  958. }
  959. /* return value similar to mktime() but the exact time is ignored */
  960. static time_t mktimeFromDateOnly(const struct tm *src)
  961. {
  962. /* explicit struct copy to retain C89 compatibility */
  963. struct tm tmp;
  964. memcpy(&tmp, src, sizeof tmp);
  965. /* abstract out (nullify) fields expressing the exact time */
  966. tmp.tm_hour = 0;
  967. tmp.tm_min = 0;
  968. tmp.tm_sec = 0;
  969. return mktime(&tmp);
  970. }
  971. /* return by how many days the date was advanced but ignore exact time */
  972. static int daysElapsed(const struct tm *now, const struct tm *last)
  973. {
  974. const time_t diff = mktimeFromDateOnly(now) - mktimeFromDateOnly(last);
  975. return diff / (24 * 3600);
  976. }
  977. static int findNeedRotating(struct logInfo *log, int logNum, int force)
  978. {
  979. struct stat sb;
  980. struct logState *state = NULL;
  981. struct tm now = *localtime(&nowSecs);
  982. message(MESS_DEBUG, "considering log %s\n", log->files[logNum]);
  983. /* Check if parent directory of this log has safe permissions */
  984. if ((log->flags & LOG_FLAG_SU) == 0 && getuid() == 0) {
  985. char *logpath = strdup(log->files[logNum]);
  986. char *ld = dirname(logpath);
  987. if (stat(ld, &sb)) {
  988. /* If parent directory doesn't exist, it's not real error
  989. (unless nomissingok is specified)
  990. and rotation is not needed */
  991. if (errno != ENOENT || (errno == ENOENT && (log->flags & LOG_FLAG_MISSINGOK) == 0)) {
  992. message(MESS_ERROR, "stat of %s failed: %s\n", ld,
  993. strerror(errno));
  994. free(logpath);
  995. return 1;
  996. }
  997. free(logpath);
  998. return 0;
  999. }
  1000. /* Don't rotate in directories writable by others or group which is not "root" */
  1001. if ((sb.st_gid != 0 && sb.st_mode & S_IWGRP) || sb.st_mode & S_IWOTH) {
  1002. message(MESS_ERROR, "skipping \"%s\" because parent directory has insecure permissions"
  1003. " (It's world writable or writable by group which is not \"root\")"
  1004. " Set \"su\" directive in config file to tell logrotate which user/group"
  1005. " should be used for rotation.\n"
  1006. ,log->files[logNum]);
  1007. free(logpath);
  1008. return 1;
  1009. }
  1010. free(logpath);
  1011. }
  1012. if (lstat(log->files[logNum], &sb)) {
  1013. if ((log->flags & LOG_FLAG_MISSINGOK) && (errno == ENOENT)) {
  1014. message(MESS_DEBUG, " log %s does not exist -- skipping\n",
  1015. log->files[logNum]);
  1016. return 0;
  1017. }
  1018. message(MESS_ERROR, "stat of %s failed: %s\n", log->files[logNum],
  1019. strerror(errno));
  1020. return 1;
  1021. }
  1022. state = findState(log->files[logNum]);
  1023. if (!state)
  1024. return 1;
  1025. state->doRotate = 0;
  1026. state->sb = sb;
  1027. state->isUsed = 1;
  1028. if ((sb.st_mode & S_IFMT) == S_IFLNK) {
  1029. message(MESS_DEBUG, " log %s is symbolic link. Rotation of symbolic"
  1030. " links is not allowed to avoid security issues -- skipping.\n",
  1031. log->files[logNum]);
  1032. return 0;
  1033. }
  1034. message(MESS_DEBUG, " Now: %d-%02d-%02d %02d:%02d\n", 1900 + now.tm_year,
  1035. 1 + now.tm_mon, now.tm_mday,
  1036. now.tm_hour, now.tm_min);
  1037. message(MESS_DEBUG, " Last rotated at %d-%02d-%02d %02d:%02d\n", 1900 + state->lastRotated.tm_year,
  1038. 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday,
  1039. state->lastRotated.tm_hour, state->lastRotated.tm_min);
  1040. if (force) {
  1041. /* user forced rotation of logs from command line */
  1042. state->doRotate = 1;
  1043. }
  1044. else if (log->maxsize && sb.st_size > log->maxsize) {
  1045. state->doRotate = 1;
  1046. }
  1047. else if (log->criterium == ROT_SIZE) {
  1048. state->doRotate = (sb.st_size >= log->threshold);
  1049. if (!state->doRotate) {
  1050. message(MESS_DEBUG, " log does not need rotating "
  1051. "(log size is below the 'size' threshold)\n");
  1052. }
  1053. } else if (mktime(&state->lastRotated) - mktime(&now) > (25 * 3600)) {
  1054. /* 25 hours allows for DST changes as well as geographical moves */
  1055. message(MESS_ERROR,
  1056. "log %s last rotated in the future -- rotation forced\n",
  1057. log->files[logNum]);
  1058. state->doRotate = 1;
  1059. } else if (state->lastRotated.tm_year != now.tm_year ||
  1060. state->lastRotated.tm_mon != now.tm_mon ||
  1061. state->lastRotated.tm_mday != now.tm_mday ||
  1062. state->lastRotated.tm_hour != now.tm_hour) {
  1063. int days;
  1064. switch (log->criterium) {
  1065. case ROT_WEEKLY:
  1066. days = daysElapsed(&now, &state->lastRotated);
  1067. /* rotate if date is advanced by 7+ days (exact time is ignored) */
  1068. state->doRotate = (days >= 7)
  1069. /* ... or if we have not yet rotated today */
  1070. || (days >= 1
  1071. /* ... and the selected weekday is today */
  1072. && now.tm_wday == log->weekday);
  1073. if (!state->doRotate) {
  1074. message(MESS_DEBUG, " log does not need rotating "
  1075. "(log has been rotated at %d-%d-%d %d:%d, "
  1076. "that is not week ago yet)\n", 1900 + state->lastRotated.tm_year,
  1077. 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday,
  1078. state->lastRotated.tm_hour, state->lastRotated.tm_min);
  1079. }
  1080. break;
  1081. case ROT_HOURLY:
  1082. state->doRotate = ((now.tm_hour != state->lastRotated.tm_hour) ||
  1083. (now.tm_mday != state->lastRotated.tm_mday) ||
  1084. (now.tm_mon != state->lastRotated.tm_mon) ||
  1085. (now.tm_year != state->lastRotated.tm_year));
  1086. if (!state->doRotate) {
  1087. message(MESS_DEBUG, " log does not need rotating "
  1088. "(log has been rotated at %d-%d-%d %d:%d, "
  1089. "that is not hour ago yet)\n", 1900 + state->lastRotated.tm_year,
  1090. 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday,
  1091. state->lastRotated.tm_hour, state->lastRotated.tm_min);
  1092. }
  1093. break;
  1094. case ROT_DAYS:
  1095. /* FIXME: only days=1 is implemented!! */
  1096. state->doRotate = ((now.tm_mday != state->lastRotated.tm_mday) ||
  1097. (now.tm_mon != state->lastRotated.tm_mon) ||
  1098. (now.tm_year != state->lastRotated.tm_year));
  1099. if (!state->doRotate) {
  1100. message(MESS_DEBUG, " log does not need rotating "
  1101. "(log has been rotated at %d-%d-%d %d:%d, "
  1102. "that is not day ago yet)\n", 1900 + state->lastRotated.tm_year,
  1103. 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday,
  1104. state->lastRotated.tm_hour, state->lastRotated.tm_min);
  1105. }
  1106. break;
  1107. case ROT_MONTHLY:
  1108. /* rotate if the logs haven't been rotated this month or
  1109. this year */
  1110. state->doRotate = ((now.tm_mon != state->lastRotated.tm_mon) ||
  1111. (now.tm_year != state->lastRotated.tm_year));
  1112. if (!state->doRotate) {
  1113. message(MESS_DEBUG, " log does not need rotating "
  1114. "(log has been rotated at %d-%d-%d %d:%d, "
  1115. "that is not month ago yet)\n", 1900 + state->lastRotated.tm_year,
  1116. 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday,
  1117. state->lastRotated.tm_hour, state->lastRotated.tm_min);
  1118. }
  1119. break;
  1120. case ROT_YEARLY:
  1121. /* rotate if the logs haven't been rotated this year */
  1122. state->doRotate = (now.tm_year != state->lastRotated.tm_year);
  1123. if (!state->doRotate) {
  1124. message(MESS_DEBUG, " log does not need rotating "
  1125. "(log has been rotated at %d-%d-%d %d:%d, "
  1126. "that is not year ago yet)\n", 1900 + state->lastRotated.tm_year,
  1127. 1 + state->lastRotated.tm_mon, state->lastRotated.tm_mday,
  1128. state->lastRotated.tm_hour, state->lastRotated.tm_min);
  1129. }
  1130. break;
  1131. case ROT_SIZE:
  1132. default:
  1133. /* ack! */
  1134. state->doRotate = 0;
  1135. break;
  1136. }
  1137. if (log->minsize && sb.st_size < log->minsize) {
  1138. state->doRotate = 0;
  1139. message(MESS_DEBUG, " log does not need rotating "
  1140. "('minsize' directive is used and the log "
  1141. "size is smaller than the minsize value)\n");
  1142. }
  1143. if (log->rotateMinAge && log->rotateMinAge * DAY_SECONDS >= nowSecs - sb.st_mtime) {
  1144. state->doRotate = 0;
  1145. message(MESS_DEBUG, " log does not need rotating "
  1146. "('minage' directive is used and the log "
  1147. "age is smaller than the minage days)\n");
  1148. }
  1149. }
  1150. else if (!state->doRotate) {
  1151. message(MESS_DEBUG, " log does not need rotating "
  1152. "(log has been already rotated)\n");
  1153. }
  1154. /* The notifempty flag overrides the normal criteria */
  1155. if (state->doRotate && !(log->flags & LOG_FLAG_IFEMPTY) && !sb.st_size) {
  1156. state->doRotate = 0;
  1157. message(MESS_DEBUG, " log does not need rotating "
  1158. "(log is empty)\n");
  1159. }
  1160. if (state->doRotate) {
  1161. message(MESS_DEBUG, " log needs rotating\n");
  1162. }
  1163. return 0;
  1164. }
  1165. /* find the rotated file with the highest index */
  1166. static int findLastRotated(const struct logNames *rotNames,
  1167. const char *fileext, const char *compext)
  1168. {
  1169. char *pattern;
  1170. int glob_rc;
  1171. glob_t globResult;
  1172. size_t i;
  1173. int last = 0;
  1174. size_t prefixLen, suffixLen;
  1175. if (asprintf(&pattern, "%s/%s.*%s%s", rotNames->dirName,
  1176. rotNames->baseName, fileext, compext) < 0)
  1177. /* out of memory */
  1178. return -1;
  1179. glob_rc = glob(pattern, 0, globerr, &globResult);
  1180. free(pattern);
  1181. switch (glob_rc) {
  1182. case 0:
  1183. /* glob() succeeded */
  1184. break;
  1185. case GLOB_NOMATCH:
  1186. /* found nothing -> assume first rotation */
  1187. return 0;
  1188. default:
  1189. /* glob() failed */
  1190. return -1;
  1191. }
  1192. prefixLen = strlen(rotNames->dirName) + /* '/' */1
  1193. + strlen(rotNames->baseName) + /* '.' */ 1;
  1194. suffixLen = strlen(fileext) + strlen(compext);
  1195. for (i = 0; i < globResult.gl_pathc; ++i) {
  1196. char *fileName = globResult.gl_pathv[i];
  1197. const size_t fileNameLen = strlen(fileName);
  1198. int num;
  1199. char c;
  1200. if (fileNameLen <= prefixLen + suffixLen)
  1201. /* not enough room for index in this file name */
  1202. continue;
  1203. /* cut off prefix/suffix */
  1204. fileName[fileNameLen - suffixLen] = '\0';
  1205. fileName += prefixLen;
  1206. if (sscanf(fileName, "%d%c", &num, &c) != 1)
  1207. /* index not matched in this file name */
  1208. continue;
  1209. /* update last index */
  1210. if (last < num)
  1211. last = num;
  1212. }
  1213. globfree(&globResult);
  1214. return last;
  1215. }
  1216. static int prerotateSingleLog(struct logInfo *log, int logNum,
  1217. struct logState *state, struct logNames *rotNames)
  1218. {
  1219. struct tm now = *localtime(&nowSecs);
  1220. char *oldName = NULL;
  1221. const char *compext = "";
  1222. const char *fileext = "";
  1223. int hasErrors = 0;
  1224. char *glob_pattern;
  1225. glob_t globResult;
  1226. int rc;
  1227. int rotateCount = log->rotateCount ? log->rotateCount : 1;
  1228. int logStart = (log->logStart == -1) ? 1 : log->logStart;
  1229. #define DATEEXT_LEN 64
  1230. #define PATTERN_LEN (DATEEXT_LEN * 2)
  1231. char dext_str[DATEEXT_LEN];
  1232. char dformat[PATTERN_LEN] = "";
  1233. char dext_pattern[PATTERN_LEN];
  1234. char *dext;
  1235. if (!state->doRotate)
  1236. return 0;
  1237. /* Logs with rotateCounts of 0 are rotated once, then removed. This
  1238. lets scripts run properly, and everything gets mailed properly. */
  1239. message(MESS_DEBUG, "rotating log %s, log->rotateCount is %d\n",
  1240. log->files[logNum], log->rotateCount);
  1241. if (log->compress_ext && (log->flags & LOG_FLAG_COMPRESS))
  1242. compext = log->compress_ext;
  1243. state->lastRotated = now;
  1244. {
  1245. char *logpath = strdup(log->files[logNum]);
  1246. char *ld = dirname(logpath);
  1247. if (log->oldDir) {
  1248. if (log->oldDir[0] != '/') {
  1249. rotNames->dirName =
  1250. malloc(strlen(ld) + strlen(log->oldDir) + 2);
  1251. sprintf(rotNames->dirName, "%s/%s", ld, log->oldDir);
  1252. } else
  1253. rotNames->dirName = strdup(log->oldDir);
  1254. } else
  1255. rotNames->dirName = strdup(ld);
  1256. free(logpath);
  1257. }
  1258. rotNames->baseName = strdup(basename(log->files[logNum]));
  1259. if (log->addextension) {
  1260. size_t baseLen = strlen(rotNames->baseName);
  1261. size_t extLen = strlen(log->addextension);
  1262. if (baseLen >= extLen &&
  1263. strncmp(&(rotNames->baseName[baseLen - extLen]),
  1264. log->addextension, extLen) == 0) {
  1265. char *tempstr;
  1266. tempstr = calloc(baseLen - extLen + 1, sizeof(char));
  1267. strncat(tempstr, rotNames->baseName, baseLen - extLen);
  1268. free(rotNames->baseName);
  1269. rotNames->baseName = tempstr;
  1270. }
  1271. fileext = log->addextension;
  1272. }
  1273. if (log->extension &&
  1274. strncmp(&
  1275. (rotNames->
  1276. baseName[strlen(rotNames->baseName) -
  1277. strlen(log->extension)]), log->extension,
  1278. strlen(log->extension)) == 0) {
  1279. char *tempstr;
  1280. fileext = log->extension;
  1281. tempstr =
  1282. calloc(strlen(rotNames->baseName) - strlen(log->extension) + 1,
  1283. sizeof(char));
  1284. strncat(tempstr, rotNames->baseName,
  1285. strlen(rotNames->baseName) - strlen(log->extension));
  1286. free(rotNames->baseName);
  1287. rotNames->baseName = tempstr;
  1288. }
  1289. /* Adjust "now" if we want yesterday's date */
  1290. if (log->flags & LOG_FLAG_DATEYESTERDAY) {
  1291. now.tm_hour = 12; /* set hour to noon to work around DST issues */
  1292. now.tm_mday = now.tm_mday - 1;
  1293. mktime(&now);
  1294. }
  1295. if (log->flags & LOG_FLAG_DATEHOURAGO) {
  1296. now.tm_hour -= 1;
  1297. mktime(&now);
  1298. }
  1299. /* Construct the glob pattern corresponding to the date format */
  1300. dext_str[0] = '\0';
  1301. if (log->dateformat) {
  1302. size_t i = 0, j = 0;
  1303. memset(dext_pattern, 0, sizeof(dext_pattern));
  1304. dext = log->dateformat;
  1305. while (*dext == ' ')
  1306. dext++;
  1307. while ((*dext != '\0') && (!hasErrors)) {
  1308. /* Will there be a space for a char and '\0'? */
  1309. if (j >= (sizeof(dext_pattern) - 1)) {
  1310. message(MESS_ERROR, "Date format %s is too long\n",
  1311. log->dateformat);
  1312. hasErrors = 1;
  1313. break;
  1314. }
  1315. if (*dext == '%') {
  1316. switch (*(dext + 1)) {
  1317. case 'Y':
  1318. strncat(dext_pattern, "[0-9][0-9]",
  1319. sizeof(dext_pattern) - strlen(dext_pattern) - 1);
  1320. j += 10; /* strlen("[0-9][0-9]") */
  1321. /* FALLTHRU */
  1322. case 'm':
  1323. case 'd':
  1324. case 'H':
  1325. case 'M':
  1326. case 'S':
  1327. case 'V':
  1328. strncat(dext_pattern, "[0-9][0-9]",
  1329. sizeof(dext_pattern) - strlen(dext_pattern) - 1);
  1330. j += 10;
  1331. if (j >= (sizeof(dext_pattern) - 1)) {
  1332. message(MESS_ERROR, "Date format %s is too long\n",
  1333. log->dateformat);
  1334. hasErrors = 1;
  1335. break;
  1336. }
  1337. dformat[i++] = *(dext++);
  1338. dformat[i] = *dext;
  1339. break;
  1340. case 's':
  1341. /* End of year 2293 this pattern does not work. */
  1342. strncat(dext_pattern,
  1343. "[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]",
  1344. sizeof(dext_pattern) - strlen(dext_pattern) - 1);
  1345. j += 50;
  1346. if (j >= (sizeof(dext_pattern) - 1)) {
  1347. message(MESS_ERROR, "Date format %s is too long\n",
  1348. log->dateformat);
  1349. hasErrors = 1;
  1350. break;
  1351. }
  1352. dformat[i++] = *(dext++);
  1353. dformat[i] = *dext;
  1354. break;
  1355. default:
  1356. dformat[i++] = *dext;
  1357. dformat[i] = '%';
  1358. dext_pattern[j++] = *dext;
  1359. break;
  1360. }
  1361. } else {
  1362. dformat[i] = *dext;
  1363. dext_pattern[j++] = *dext;
  1364. }
  1365. ++i;
  1366. ++dext;
  1367. }
  1368. dformat[i] = '\0';
  1369. message(MESS_DEBUG, "Converted '%s' -> '%s'\n", log->dateformat, dformat);
  1370. strftime(dext_str, sizeof(dext_str), dformat, &now);
  1371. } else {
  1372. if (log->criterium == ROT_HOURLY) {
  1373. /* hourly adds another two digits */
  1374. strftime(dext_str, sizeof(dext_str), "-%Y%m%d%H", &now);
  1375. strncpy(dext_pattern, "-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]",
  1376. sizeof(dext_pattern));
  1377. } else {
  1378. /* The default dateformat and glob pattern */
  1379. strftime(dext_str, sizeof(dext_str), "-%Y%m%d", &now);
  1380. strncpy(dext_pattern, "-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]",
  1381. sizeof(dext_pattern));
  1382. }
  1383. dext_pattern[PATTERN_LEN - 1] = '\0';
  1384. }
  1385. message(MESS_DEBUG, "dateext suffix '%s'\n", dext_str);
  1386. message(MESS_DEBUG, "glob pattern '%s'\n", dext_pattern);
  1387. if (setSecCtxByName(log->files[logNum], &prev_context) != 0) {
  1388. /* error msg already printed */
  1389. return 1;
  1390. }
  1391. /* First compress the previous log when necessary */
  1392. if (log->flags & LOG_FLAG_COMPRESS &&
  1393. log->flags & LOG_FLAG_DELAYCOMPRESS) {
  1394. if (log->flags & LOG_FLAG_DATEEXT) {
  1395. /* glob for uncompressed files with our pattern */
  1396. if (asprintf(&glob_pattern, "%s/%s%s%s", rotNames->dirName,
  1397. rotNames->baseName, dext_pattern, fileext) < 0) {
  1398. message(MESS_FATAL, "could not allocate glob pattern memory\n");
  1399. }
  1400. rc = glob(glob_pattern, 0, globerr, &globResult);
  1401. if (!rc && globResult.gl_pathc > 0) {
  1402. size_t glob_count;
  1403. sortGlobResult(&globResult, strlen(rotNames->dirName) + 1 + strlen(rotNames->baseName), dformat);
  1404. for (glob_count = 0; glob_count < globResult.gl_pathc && !hasErrors; glob_count++) {
  1405. struct stat sbprev;
  1406. if (asprintf(&oldName, "%s", (globResult.gl_pathv)[glob_count]) < 0) {
  1407. message(MESS_FATAL, "could not allocate glob result memory\n");
  1408. }
  1409. if (stat(oldName, &sbprev)) {
  1410. if (errno == ENOENT)
  1411. message(MESS_DEBUG, "previous log %s does not exist\n", oldName);
  1412. else
  1413. message(MESS_ERROR, "cannot stat %s: %s\n", oldName, strerror(errno));
  1414. } else {
  1415. hasErrors = compressLogFile(oldName, log, &sbprev);
  1416. }
  1417. free(oldName);
  1418. }
  1419. } else {
  1420. message(MESS_DEBUG,
  1421. "glob finding logs to compress failed\n");
  1422. /* fallback to old behaviour */
  1423. if (asprintf(&oldName, "%s/%s.%d%s", rotNames->dirName,
  1424. rotNames->baseName, logStart, fileext) < 0) {
  1425. message(MESS_FATAL, "could not allocate oldName memory\n");
  1426. }
  1427. free(oldName);
  1428. }
  1429. globfree(&globResult);
  1430. free(glob_pattern);
  1431. } else {
  1432. struct stat sbprev;
  1433. if (asprintf(&oldName, "%s/%s.%d%s", rotNames->dirName,
  1434. rotNames->baseName, logStart, fileext) < 0) {
  1435. message(MESS_FATAL, "could not allocate oldName memory\n");
  1436. }
  1437. if (stat(oldName, &sbprev)) {
  1438. if (errno == ENOENT)
  1439. message(MESS_DEBUG, "previous log %s does not exist\n", oldName);
  1440. else
  1441. message(MESS_ERROR, "cannot stat %s: %s\n", oldName, strerror(errno));
  1442. } else {
  1443. hasErrors = compressLogFile(oldName, log, &sbprev);
  1444. }
  1445. free(oldName);
  1446. }
  1447. }
  1448. /* adding 2 due to / and \0 being added by snprintf */
  1449. rotNames->firstRotated =
  1450. malloc(strlen(rotNames->dirName) + strlen(rotNames->baseName) +
  1451. strlen(fileext) + strlen(compext) + DATEEXT_LEN + 2 );
  1452. if (log->flags & LOG_FLAG_DATEEXT) {
  1453. /* glob for compressed files with our pattern
  1454. * and compress ext */
  1455. if (asprintf(&glob_pattern, "%s/%s%s%s%s", rotNames->dirName,
  1456. rotNames->baseName, dext_pattern, fileext, compext) < 0) {
  1457. message(MESS_ERROR, "could not allocate glob pattern memory\n");
  1458. }
  1459. rc = glob(glob_pattern, 0, globerr, &globResult);
  1460. if (!rc) {
  1461. /* search for files to drop, if we find one remember it,
  1462. * if we find another one mail and remove the first and
  1463. * remember the second and so on */
  1464. struct stat fst_buf;
  1465. int mail_out = -1;
  1466. size_t glob_count;
  1467. /* Remove the first (n - rotateCount) matches no real rotation
  1468. * needed, since the files have the date in their name. Note that
  1469. * (size_t)-1 == SIZE_T_MAX in rotateCount */
  1470. sortGlobResult(&globResult, strlen(rotNames->dirName) + 1 + strlen(rotNames->baseName), dformat);
  1471. for (glob_count = 0; glob_count < globResult.gl_pathc; glob_count++) {
  1472. if (!stat((globResult.gl_pathv)[glob_count], &fst_buf)) {
  1473. if (((globResult.gl_pathc >= (size_t)rotateCount) && (glob_count <= (globResult.gl_pathc - rotateCount)))
  1474. || ((log->rotateAge > 0)
  1475. &&
  1476. (((nowSecs - fst_buf.st_mtime) / DAY_SECONDS)
  1477. > log->rotateAge))) {
  1478. if (mail_out != -1) {
  1479. char *mailFilename =
  1480. (globResult.gl_pathv)[mail_out];
  1481. if (!hasErrors && log->logAddress)
  1482. hasErrors = mailLogWrapper(mailFilename, mailCommand,
  1483. logNum, log);
  1484. if (!hasErrors) {
  1485. message(MESS_DEBUG, "removing %s\n", mailFilename);
  1486. hasErrors = removeLogFile(mailFilename, log);
  1487. }
  1488. }
  1489. mail_out = glob_count;
  1490. }
  1491. }
  1492. }
  1493. if (mail_out != -1) {
  1494. /* oldName is oldest Backup found (for unlink later) */
  1495. if (asprintf(&oldName, "%s", (globResult.gl_pathv)[mail_out]) < 0) {
  1496. message(MESS_FATAL, "could not allocate mailout memory\n");
  1497. }
  1498. rotNames->disposeName = malloc(strlen(oldName)+1);
  1499. strcpy(rotNames->disposeName, oldName);
  1500. free(oldName);
  1501. } else {
  1502. free(rotNames->disposeName);
  1503. rotNames->disposeName = NULL;
  1504. }
  1505. } else {
  1506. message(MESS_DEBUG, "glob finding old rotated logs failed\n");
  1507. free(rotNames->disposeName);
  1508. rotNames->disposeName = NULL;
  1509. }
  1510. /* firstRotated is most recently created/compressed rotated log */
  1511. sprintf(rotNames->firstRotated, "%s/%s%s%s%s",
  1512. rotNames->dirName, rotNames->baseName, dext_str, fileext,
  1513. (log->flags & LOG_FLAG_DELAYCOMPRESS) ? "" : compext);
  1514. globfree(&globResult);
  1515. free(glob_pattern);
  1516. } else {
  1517. int i;
  1518. char *newName = NULL;
  1519. if (log->rotateAge) {
  1520. struct stat fst_buf;
  1521. /* we will not enter the loop in case rotateCount == -1 */
  1522. for (i = 1; i <= rotateCount + 1; i++) {
  1523. if (asprintf(&oldName, "%s/%s.%d%s%s", rotNames->dirName,
  1524. rotNames->baseName, i, fileext, compext) < 0) {
  1525. message(MESS_FATAL, "could not allocate mailFilename memory\n");
  1526. }
  1527. if (!stat(oldName, &fst_buf)
  1528. && (((nowSecs - fst_buf.st_mtime) / DAY_SECONDS)
  1529. > log->rotateAge)) {
  1530. char *mailFilename = oldName;
  1531. if (!hasErrors && log->logAddress)
  1532. hasErrors =
  1533. mailLogWrapper(mailFilename, mailCommand,
  1534. logNum, log);
  1535. if (!hasErrors)
  1536. hasErrors = removeLogFile(mailFilename, log);
  1537. }
  1538. free(oldName);
  1539. }
  1540. }
  1541. if (rotateCount == -1) {
  1542. rotateCount = findLastRotated(rotNames, fileext, compext);
  1543. if (rotateCount < 0) {
  1544. message(MESS_ERROR, "could not find last rotated file: %s/%s.*%s%s\n",
  1545. rotNames->dirName, rotNames->baseName, fileext, compext);
  1546. return 1;
  1547. }
  1548. }
  1549. if (asprintf(&oldName, "%s/%s.%d%s%s", rotNames->dirName,
  1550. rotNames->baseName, logStart + rotateCount, fileext,
  1551. compext) < 0) {
  1552. message(MESS_FATAL, "could not allocate disposeName memory\n");
  1553. }
  1554. if (log->rotateCount != -1)
  1555. rotNames->disposeName = strdup(oldName);
  1556. sprintf(rotNames->firstRotated, "%s/%s.%d%s%s", rotNames->dirName,
  1557. rotNames->baseName, logStart, fileext,
  1558. (log->flags & LOG_FLAG_DELAYCOMPRESS) ? "" : compext);
  1559. for (i = rotateCount + logStart - 1; (i >= 0) && !hasErrors; i--) {
  1560. free(newName);
  1561. newName = oldName;
  1562. if (asprintf(&oldName, "%s/%s.%d%s%s", rotNames->dirName,
  1563. rotNames->baseName, i, fileext, compext) < 0) {
  1564. message(MESS_FATAL, "could not allocate oldName memory\n");
  1565. oldName = NULL;
  1566. break;
  1567. }
  1568. message(MESS_DEBUG,
  1569. "renaming %s to %s (rotatecount %d, logstart %d, i %d), \n",
  1570. oldName, newName, rotateCount, logStart, i);
  1571. if (!debug && rename(oldName, newName)) {
  1572. if (errno == ENOENT) {
  1573. message(MESS_DEBUG, "old log %s does not exist\n",
  1574. oldName);
  1575. } else {
  1576. message(MESS_ERROR, "error renaming %s to %s: %s\n",
  1577. oldName, newName, strerror(errno));
  1578. hasErrors = 1;
  1579. }
  1580. }
  1581. }
  1582. free(newName);
  1583. free(oldName);
  1584. } /* !LOG_FLAG_DATEEXT */
  1585. if (log->flags & LOG_FLAG_DATEEXT) {
  1586. char *destFile;
  1587. struct stat fst_buf;
  1588. if (asprintf(&(rotNames->finalName), "%s/%s%s%s", rotNames->dirName,
  1589. rotNames->baseName, dext_str, fileext) < 0) {
  1590. message(MESS_FATAL, "could not allocate finalName memory\n");
  1591. }
  1592. if (asprintf(&destFile, "%s%s", rotNames->finalName, compext) < 0) {
  1593. message(MESS_FATAL, "could not allocate destFile memory\n");
  1594. }
  1595. if (!stat(destFile, &fst_buf)) {
  1596. message(MESS_ERROR,
  1597. "destination %s already exists, skipping rotation\n",
  1598. rotNames->firstRotated);
  1599. hasErrors = 1;
  1600. }
  1601. free(destFile);
  1602. } else {
  1603. /* note: the gzip extension is *not* used here! */
  1604. if (asprintf(&(rotNames->finalName), "%s/%s.%d%s", rotNames->dirName,
  1605. rotNames->baseName, logStart, fileext) < 0) {
  1606. message(MESS_ERROR, "could not allocate finalName memory\n");
  1607. }
  1608. }
  1609. /* if the last rotation doesn't exist, that's okay */
  1610. if (rotNames->disposeName && access(rotNames->disposeName, F_OK)) {
  1611. message(MESS_DEBUG,
  1612. "log %s doesn't exist -- won't try to dispose of it\n",
  1613. rotNames->disposeName);
  1614. free(rotNames->disposeName);
  1615. rotNames->disposeName = NULL;
  1616. }
  1617. return hasErrors;
  1618. }
  1619. static int rotateSingleLog(struct logInfo *log, int logNum,
  1620. struct logState *state, struct logNames *rotNames)
  1621. {
  1622. int hasErrors = 0;
  1623. struct stat sb;
  1624. int fd;
  1625. void *savedContext = NULL;
  1626. char *tmpFilename = NULL;
  1627. if (!state->doRotate)
  1628. return 0;
  1629. if (!hasErrors) {
  1630. if (!(log->flags & (LOG_FLAG_COPYTRUNCATE | LOG_FLAG_COPY))) {
  1631. if (setSecCtxByName(log->files[logNum], &savedContext) != 0) {
  1632. /* error msg already printed */
  1633. return 1;
  1634. }
  1635. #ifdef WITH_ACL
  1636. if ((prev_acl = acl_get_file(log->files[logNum], ACL_TYPE_ACCESS)) == NULL) {
  1637. if (is_acl_well_supported(errno)) {
  1638. message(MESS_ERROR, "getting file ACL %s: %s\n",
  1639. log->files[logNum], strerror(errno));
  1640. hasErrors = 1;
  1641. }
  1642. }
  1643. #endif /* WITH_ACL */
  1644. if (log->flags & LOG_FLAG_TMPFILENAME) {
  1645. if (asprintf(&tmpFilename, "%s%s", log->files[logNum], ".tmp") < 0) {
  1646. message(MESS_FATAL, "could not allocate tmpFilename memory\n");
  1647. restoreSecCtx(&savedContext);
  1648. return 1;
  1649. }
  1650. message(MESS_DEBUG, "renaming %s to %s\n", log->files[logNum],
  1651. tmpFilename);
  1652. if (!debug && !hasErrors && rename(log->files[logNum], tmpFilename)) {
  1653. message(MESS_ERROR, "failed to rename %s to %s: %s\n",
  1654. log->files[logNum], tmpFilename,
  1655. strerror(errno));
  1656. hasErrors = 1;
  1657. }
  1658. }
  1659. else {
  1660. message(MESS_DEBUG, "renaming %s to %s\n", log->files[logNum],
  1661. rotNames->finalName);
  1662. if (!debug && !hasErrors &&
  1663. rename(log->files[logNum], rotNames->finalName)) {
  1664. message(MESS_ERROR, "failed to rename %s to %s: %s\n",
  1665. log->files[logNum], rotNames->finalName,
  1666. strerror(errno));
  1667. hasErrors = 1;
  1668. }
  1669. }
  1670. if (!log->rotateCount) {
  1671. const char *ext = "";
  1672. if (log->compress_ext && (log->flags & LOG_FLAG_COMPRESS))
  1673. ext = log->compress_ext;
  1674. free(rotNames->disposeName);
  1675. if (asprintf(&rotNames->disposeName, "%s%s", rotNames->finalName, ext) < 0)
  1676. message(MESS_FATAL, "could not allocate disposeName memory\n");
  1677. message(MESS_DEBUG, "disposeName will be %s\n", rotNames->disposeName);
  1678. }
  1679. }
  1680. if (!hasErrors && log->flags & LOG_FLAG_CREATE &&
  1681. !(log->flags & (LOG_FLAG_COPYTRUNCATE | LOG_FLAG_COPY))) {
  1682. int have_create_mode = 0;
  1683. if (log->createUid == NO_UID)
  1684. sb.st_uid = state->sb.st_uid;
  1685. else
  1686. sb.st_uid = log->createUid;
  1687. if (log->createGid == NO_GID)
  1688. sb.st_gid = state->sb.st_gid;
  1689. else
  1690. sb.st_gid = log->createGid;
  1691. if (log->createMode == NO_MODE)
  1692. sb.st_mode = state->sb.st_mode & 0777;
  1693. else {
  1694. sb.st_mode = log->createMode;
  1695. have_create_mode = 1;
  1696. }
  1697. message(MESS_DEBUG, "creating new %s mode = 0%o uid = %d "
  1698. "gid = %d\n", log->files[logNum], (unsigned int) sb.st_mode,
  1699. (int) sb.st_uid, (int) sb.st_gid);
  1700. if (!debug) {
  1701. if (!hasErrors) {
  1702. fd = createOutputFile(log->files[logNum], O_CREAT | O_RDWR,
  1703. &sb, prev_acl, have_create_mode);
  1704. #ifdef WITH_ACL
  1705. if (prev_acl) {
  1706. acl_free(prev_acl);
  1707. prev_acl = NULL;
  1708. }
  1709. #endif
  1710. if (fd < 0)
  1711. hasErrors = 1;
  1712. else {
  1713. close(fd);
  1714. }
  1715. }
  1716. }
  1717. }
  1718. restoreSecCtx(&savedContext);
  1719. if (!hasErrors
  1720. && log->flags & (LOG_FLAG_COPYTRUNCATE | LOG_FLAG_COPY)
  1721. && !(log->flags & LOG_FLAG_TMPFILENAME)) {
  1722. hasErrors = copyTruncate(log->files[logNum], rotNames->finalName,
  1723. &state->sb, log->flags, !log->rotateCount);
  1724. }
  1725. #ifdef WITH_ACL
  1726. if (prev_acl) {
  1727. acl_free(prev_acl);
  1728. prev_acl = NULL;
  1729. }
  1730. #endif /* WITH_ACL */
  1731. }
  1732. return hasErrors;
  1733. }
  1734. static int postrotateSingleLog(struct logInfo *log, int logNum,
  1735. struct logState *state,
  1736. struct logNames *rotNames)
  1737. {
  1738. int hasErrors = 0;
  1739. if (!state->doRotate) {
  1740. return 0;
  1741. }
  1742. if (!hasErrors && log->flags & LOG_FLAG_TMPFILENAME) {
  1743. char *tmpFilename = NULL;
  1744. if (asprintf(&tmpFilename, "%s%s", log->files[logNum], ".tmp") < 0) {
  1745. message(MESS_FATAL, "could not allocate tmpFilename memory\n");
  1746. return 1;
  1747. }
  1748. hasErrors = copyTruncate(tmpFilename, rotNames->finalName,
  1749. &state->sb, LOG_FLAG_COPY, /* skip_copy */ 0);
  1750. message(MESS_DEBUG, "removing tmp log %s \n", tmpFilename);
  1751. if (!debug && !hasErrors) {
  1752. unlink(tmpFilename);
  1753. }
  1754. }
  1755. if (!hasErrors && (log->flags & LOG_FLAG_COMPRESS) &&
  1756. !(log->flags & LOG_FLAG_DELAYCOMPRESS)) {
  1757. hasErrors = compressLogFile(rotNames->finalName, log, &state->sb);
  1758. }
  1759. if (!hasErrors && log->logAddress) {
  1760. char *mailFilename;
  1761. if (log->flags & LOG_FLAG_MAILFIRST)
  1762. mailFilename = rotNames->firstRotated;
  1763. else
  1764. mailFilename = rotNames->disposeName;
  1765. if (mailFilename)
  1766. hasErrors = mailLogWrapper(mailFilename, mailCommand, logNum, log);
  1767. }
  1768. if (!hasErrors && rotNames->disposeName)
  1769. hasErrors = removeLogFile(rotNames->disposeName, log);
  1770. restoreSecCtx(&prev_context);
  1771. return hasErrors;
  1772. }
  1773. static int rotateLogSet(struct logInfo *log, int force)
  1774. {
  1775. int i, j;
  1776. int hasErrors = 0;
  1777. int *logHasErrors;
  1778. int numRotated = 0;
  1779. struct logState **state;
  1780. struct logNames **rotNames;
  1781. logHasErrors = calloc(log->numFiles, sizeof(int));
  1782. if (!logHasErrors) {
  1783. message(MESS_ERROR, "could not allocate memory for "
  1784. "logHasErrors\n");
  1785. return 1;
  1786. }
  1787. message(MESS_DEBUG, "\nrotating pattern: %s ", log->pattern);
  1788. if (force) {
  1789. message(MESS_DEBUG, "forced from command line ");
  1790. }
  1791. else {
  1792. switch (log->criterium) {
  1793. case ROT_HOURLY:
  1794. message(MESS_DEBUG, "hourly ");
  1795. break;
  1796. case ROT_DAYS:
  1797. message(MESS_DEBUG, "after %jd days ", (intmax_t)log->threshold);
  1798. break;
  1799. case ROT_WEEKLY:
  1800. message(MESS_DEBUG, "weekly ");
  1801. break;
  1802. case ROT_MONTHLY:
  1803. message(MESS_DEBUG, "monthly ");
  1804. break;
  1805. case ROT_YEARLY:
  1806. message(MESS_DEBUG, "yearly ");
  1807. break;
  1808. case ROT_SIZE:
  1809. message(MESS_DEBUG, "%jd bytes ", (intmax_t)log->threshold);
  1810. break;
  1811. default:
  1812. message(MESS_DEBUG, "rotateLogSet() does not have case for: %u ",
  1813. (unsigned) log->criterium);
  1814. }
  1815. }
  1816. if (log->rotateCount > 0)
  1817. message(MESS_DEBUG, "(%d rotations)\n", log->rotateCount);
  1818. else if (log->rotateCount == 0)
  1819. message(MESS_DEBUG, "(no old logs will be kept)\n");
  1820. if (log->oldDir)
  1821. message(MESS_DEBUG, "olddir is %s, ", log->oldDir);
  1822. if (log->flags & LOG_FLAG_IFEMPTY)
  1823. message(MESS_DEBUG, "empty log files are rotated, ");
  1824. else
  1825. message(MESS_DEBUG, "empty log files are not rotated, ");
  1826. if (log->minsize)
  1827. message(MESS_DEBUG, "only log files >= %jd bytes are rotated, ", (intmax_t)log->minsize);
  1828. if (log->maxsize)
  1829. message(MESS_DEBUG, "log files >= %jd are rotated earlier, ", (intmax_t)log->maxsize);
  1830. if (log->rotateMinAge)
  1831. message(MESS_DEBUG, "only log files older than %d days are rotated, ", log->rotateMinAge);
  1832. if (log->logAddress) {
  1833. message(MESS_DEBUG, "old logs mailed to %s\n", log->logAddress);
  1834. } else {
  1835. message(MESS_DEBUG, "old logs are removed\n");
  1836. }
  1837. if (log->numFiles == 0) {
  1838. message(MESS_DEBUG, "No logs found. Rotation not needed.\n");
  1839. free(logHasErrors);
  1840. return 0;
  1841. }
  1842. if (log->flags & LOG_FLAG_SU) {
  1843. if (switch_user(log->suUid, log->suGid) != 0) {
  1844. free(logHasErrors);
  1845. return 1;
  1846. }
  1847. }
  1848. for (i = 0; i < log->numFiles; i++) {
  1849. struct logState *logState;
  1850. logHasErrors[i] = findNeedRotating(log, i, force);
  1851. hasErrors |= logHasErrors[i];
  1852. /* sure is a lot of findStating going on .. */
  1853. if (((logState = findState(log->files[i]))) && logState->doRotate)
  1854. numRotated++;
  1855. }
  1856. if (log->first) {
  1857. if (!numRotated) {
  1858. message(MESS_DEBUG, "not running first action script, "
  1859. "since no logs will be rotated\n");
  1860. } else {
  1861. message(MESS_DEBUG, "running first action script\n");
  1862. if (runScript(log, log->pattern, NULL, log->first)) {
  1863. message(MESS_ERROR, "error running first action script "
  1864. "for %s\n", log->pattern);
  1865. hasErrors = 1;
  1866. if (log->flags & LOG_FLAG_SU) {
  1867. if (switch_user_back() != 0) {
  1868. free(logHasErrors);
  1869. return 1;
  1870. }
  1871. }
  1872. /* finish early, firstaction failed, affects all logs in set */
  1873. free(logHasErrors);
  1874. return hasErrors;
  1875. }
  1876. }
  1877. }
  1878. state = malloc(log->numFiles * sizeof(struct logState *));
  1879. rotNames = malloc(log->numFiles * sizeof(struct logNames *));
  1880. for (j = 0;
  1881. (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && j < log->numFiles)
  1882. || ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && j < 1); j++) {
  1883. for (i = j;
  1884. ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && i < log->numFiles)
  1885. || (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && i == j); i++) {
  1886. state[i] = findState(log->files[i]);
  1887. if (!state[i])
  1888. logHasErrors[i] = 1;
  1889. rotNames[i] = malloc(sizeof(struct logNames));
  1890. memset(rotNames[i], 0, sizeof(struct logNames));
  1891. logHasErrors[i] |=
  1892. prerotateSingleLog(log, i, state[i], rotNames[i]);
  1893. hasErrors |= logHasErrors[i];
  1894. }
  1895. if (log->pre
  1896. && (!(
  1897. ((logHasErrors[j] || !state[j]->doRotate) && !(log->flags & LOG_FLAG_SHAREDSCRIPTS))
  1898. || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS))
  1899. ))
  1900. ) {
  1901. if (!numRotated) {
  1902. message(MESS_DEBUG, "not running prerotate script, "
  1903. "since no logs will be rotated\n");
  1904. } else {
  1905. message(MESS_DEBUG, "running prerotate script\n");
  1906. if (runScript(log, log->flags & LOG_FLAG_SHAREDSCRIPTS ? log->pattern : log->files[j], NULL, log->pre)) {
  1907. if (log->flags & LOG_FLAG_SHAREDSCRIPTS)
  1908. message(MESS_ERROR,
  1909. "error running shared prerotate script "
  1910. "for '%s'\n", log->pattern);
  1911. else {
  1912. message(MESS_ERROR,
  1913. "error running non-shared prerotate script "
  1914. "for %s of '%s'\n", log->files[j], log->pattern);
  1915. }
  1916. logHasErrors[j] = 1;
  1917. hasErrors = 1;
  1918. }
  1919. }
  1920. }
  1921. for (i = j;
  1922. ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && i < log->numFiles)
  1923. || (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && i == j); i++) {
  1924. if (! ( (logHasErrors[i] && !(log->flags & LOG_FLAG_SHAREDSCRIPTS))
  1925. || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) ) ) {
  1926. logHasErrors[i] |=
  1927. rotateSingleLog(log, i, state[i], rotNames[i]);
  1928. hasErrors |= logHasErrors[i];
  1929. }
  1930. }
  1931. if (log->post
  1932. && (!(
  1933. ((logHasErrors[j] || !state[j]->doRotate) && !(log->flags & LOG_FLAG_SHAREDSCRIPTS))
  1934. || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS))
  1935. ))
  1936. ) {
  1937. if (!numRotated) {
  1938. message(MESS_DEBUG, "not running postrotate script, "
  1939. "since no logs were rotated\n");
  1940. } else {
  1941. char *logfn = (log->flags & LOG_FLAG_SHAREDSCRIPTS) ? log->pattern : log->files[j];
  1942. /* It only makes sense to pass in a final rotated filename if scripts are not shared */
  1943. char *logrotfn = (log->flags & LOG_FLAG_SHAREDSCRIPTS) ? NULL : rotNames[j]->finalName;
  1944. message(MESS_DEBUG, "running postrotate script\n");
  1945. if (runScript(log, logfn, logrotfn, log->post)) {
  1946. if (log->flags & LOG_FLAG_SHAREDSCRIPTS)
  1947. message(MESS_ERROR,
  1948. "error running shared postrotate script "
  1949. "for '%s'\n", log->pattern);
  1950. else {
  1951. message(MESS_ERROR,
  1952. "error running non-shared postrotate script "
  1953. "for %s of '%s'\n", log->files[j], log->pattern);
  1954. }
  1955. logHasErrors[j] = 1;
  1956. hasErrors = 1;
  1957. }
  1958. }
  1959. }
  1960. for (i = j;
  1961. ((log->flags & LOG_FLAG_SHAREDSCRIPTS) && i < log->numFiles)
  1962. || (!(log->flags & LOG_FLAG_SHAREDSCRIPTS) && i == j); i++) {
  1963. if (! ( (logHasErrors[i] && !(log->flags & LOG_FLAG_SHAREDSCRIPTS))
  1964. || (hasErrors && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) ) ) {
  1965. logHasErrors[i] |=
  1966. postrotateSingleLog(log, i, state[i], rotNames[i]);
  1967. hasErrors |= logHasErrors[i];
  1968. }
  1969. }
  1970. }
  1971. for (i = 0; i < log->numFiles; i++) {
  1972. free(rotNames[i]->firstRotated);
  1973. free(rotNames[i]->disposeName);
  1974. free(rotNames[i]->finalName);
  1975. free(rotNames[i]->dirName);
  1976. free(rotNames[i]->baseName);
  1977. free(rotNames[i]);
  1978. }
  1979. free(rotNames);
  1980. free(state);
  1981. if (log->last) {
  1982. if (!numRotated) {
  1983. message(MESS_DEBUG, "not running last action script, "
  1984. "since no logs will be rotated\n");
  1985. } else {
  1986. message(MESS_DEBUG, "running last action script\n");
  1987. if (runScript(log, log->pattern, NULL, log->last)) {
  1988. message(MESS_ERROR, "error running last action script "
  1989. "for %s\n", log->pattern);
  1990. hasErrors = 1;
  1991. }
  1992. }
  1993. }
  1994. if (log->flags & LOG_FLAG_SU) {
  1995. if (switch_user_back() != 0) {
  1996. free(logHasErrors);
  1997. return 1;
  1998. }
  1999. }
  2000. free(logHasErrors);
  2001. return hasErrors;
  2002. }
  2003. static int writeState(const char *stateFilename)
  2004. {
  2005. struct logState *p;
  2006. FILE *f;
  2007. char *chptr;
  2008. unsigned int i = 0;
  2009. int error = 0;
  2010. int bytes = 0;
  2011. int fdcurr;
  2012. int fdsave;
  2013. struct stat sb;
  2014. char *tmpFilename = NULL;
  2015. struct tm now = *localtime(&nowSecs);
  2016. time_t now_time, last_time;
  2017. void *prevCtx;
  2018. tmpFilename = malloc(strlen(stateFilename) + 5 );
  2019. if (tmpFilename == NULL) {
  2020. message(MESS_ERROR, "could not allocate memory for "
  2021. "tmp state filename\n");
  2022. return 1;
  2023. }
  2024. strcpy(tmpFilename, stateFilename);
  2025. strcat(tmpFilename, ".tmp");
  2026. /* Remove possible tmp state file from previous run */
  2027. unlink(tmpFilename);
  2028. if ((fdcurr = open(stateFilename, O_RDONLY)) < 0) {
  2029. message(MESS_ERROR, "error opening %s: %s\n", stateFilename,
  2030. strerror(errno));
  2031. free(tmpFilename);
  2032. return 1;
  2033. }
  2034. if (setSecCtx(fdcurr, stateFilename, &prevCtx) != 0) {
  2035. /* error msg already printed */
  2036. free(tmpFilename);
  2037. close(fdcurr);
  2038. return 1;
  2039. }
  2040. #ifdef WITH_ACL
  2041. if ((prev_acl = acl_get_fd(fdcurr)) == NULL) {
  2042. if (is_acl_well_supported(errno)) {
  2043. message(MESS_ERROR, "getting file ACL %s: %s\n",
  2044. stateFilename, strerror(errno));
  2045. restoreSecCtx(&prevCtx);
  2046. free(tmpFilename);
  2047. close(fdcurr);
  2048. return 1;
  2049. }
  2050. }
  2051. #endif
  2052. close(fdcurr);
  2053. if (stat(stateFilename, &sb) == -1) {
  2054. message(MESS_ERROR, "error stating %s: %s\n", stateFilename, strerror(errno));
  2055. free(tmpFilename);
  2056. #ifdef WITH_ACL
  2057. if (prev_acl)
  2058. acl_free(prev_acl);
  2059. #endif
  2060. return 1;
  2061. }
  2062. fdsave = createOutputFile(tmpFilename, O_RDWR | O_CREAT | O_TRUNC, &sb, prev_acl, 0);
  2063. #ifdef WITH_ACL
  2064. if (prev_acl) {
  2065. acl_free(prev_acl);
  2066. prev_acl = NULL;
  2067. }
  2068. #endif
  2069. restoreSecCtx(&prevCtx);
  2070. if (fdsave < 0) {
  2071. free(tmpFilename);
  2072. return 1;
  2073. }
  2074. f = fdopen(fdsave, "w");
  2075. if (!f) {
  2076. message(MESS_ERROR, "error creating temp state file %s: %s\n",
  2077. tmpFilename, strerror(errno));
  2078. free(tmpFilename);
  2079. return 1;
  2080. }
  2081. bytes = fprintf(f, "logrotate state -- version 2\n");
  2082. if (bytes < 0)
  2083. error = bytes;
  2084. /*
  2085. * Time in seconds it takes earth to go around sun. The value is
  2086. * astronomical measurement (solar year) rather than something derived from
  2087. * a convention (calendar year).
  2088. */
  2089. #define SECONDS_IN_YEAR 31556926
  2090. for (i = 0; i < hashSize && error == 0; i++) {
  2091. for (p = states[i]->head.lh_first; p != NULL && error == 0;
  2092. p = p->list.le_next) {
  2093. /* Skip states which are not used for more than a year. */
  2094. now_time = mktime(&now);
  2095. last_time = mktime(&p->lastRotated);
  2096. if (!p->isUsed && difftime(now_time, last_time) > SECONDS_IN_YEAR) {
  2097. message(MESS_DEBUG, "Removing %s from state file, "
  2098. "because it does not exist and has not been rotated for one year\n",
  2099. p->fn);
  2100. continue;
  2101. }
  2102. error = fputc('"', f) == EOF;
  2103. for (chptr = p->fn; *chptr && error == 0; chptr++) {
  2104. switch (*chptr) {
  2105. case '"':
  2106. case '\\':
  2107. error = fputc('\\', f) == EOF;
  2108. break;
  2109. case '\n':
  2110. error = fputc('\\', f) == EOF;
  2111. if (error == 0) {
  2112. error = fputc('n', f) == EOF;
  2113. }
  2114. continue;
  2115. default:
  2116. break;
  2117. }
  2118. if (error == 0 && fputc(*chptr, f) == EOF) {
  2119. error = 1;
  2120. }
  2121. }
  2122. if (error == 0 && fputc('"', f) == EOF)
  2123. error = 1;
  2124. if (error == 0) {
  2125. bytes = fprintf(f, " %d-%d-%d-%d:%d:%d\n",
  2126. p->lastRotated.tm_year + 1900,
  2127. p->lastRotated.tm_mon + 1,
  2128. p->lastRotated.tm_mday,
  2129. p->lastRotated.tm_hour,
  2130. p->lastRotated.tm_min,
  2131. p->lastRotated.tm_sec);
  2132. if (bytes < 0)
  2133. error = bytes;
  2134. }
  2135. }
  2136. }
  2137. if (error == 0)
  2138. error = fflush(f);
  2139. if (error == 0)
  2140. error = fsync(fdsave);
  2141. if (error == 0)
  2142. error = fclose(f);
  2143. else
  2144. fclose(f);
  2145. if (error == 0) {
  2146. if (rename(tmpFilename, stateFilename)) {
  2147. unlink(tmpFilename);
  2148. error = 1;
  2149. message(MESS_ERROR, "error renaming temp state file %s\n",
  2150. tmpFilename);
  2151. }
  2152. }
  2153. else {
  2154. unlink(tmpFilename);
  2155. if (errno)
  2156. message(MESS_ERROR, "error creating temp state file %s: %s\n",
  2157. tmpFilename, strerror(errno));
  2158. else
  2159. message(MESS_ERROR, "error creating temp state file %s%s\n",
  2160. tmpFilename, error == ENOMEM ?
  2161. ": Insufficient storage space is available." : "" );
  2162. }
  2163. free(tmpFilename);
  2164. return error;
  2165. }
  2166. static int readState(const char *stateFilename)
  2167. {
  2168. FILE *f;
  2169. char buf[STATEFILE_BUFFER_SIZE];
  2170. char *filename;
  2171. const char **argv;
  2172. int argc;
  2173. int year, month, day, hour, minute, second;
  2174. int i;
  2175. int line = 0;
  2176. int error;
  2177. struct logState *st;
  2178. time_t lr_time;
  2179. struct stat f_stat;
  2180. int rc = 0;
  2181. message(MESS_DEBUG, "Reading state from file: %s\n", stateFilename);
  2182. error = stat(stateFilename, &f_stat);
  2183. if (error) {
  2184. /* treat non-statable file as an empty file */
  2185. f_stat.st_size = 0;
  2186. if (errno != ENOENT) {
  2187. message(MESS_ERROR, "error stat()ing state file %s: %s\n",
  2188. stateFilename, strerror(errno));
  2189. /* do not return until the hash table is allocated */
  2190. rc = 1;
  2191. }
  2192. }
  2193. if (!debug && (f_stat.st_size == 0)) {
  2194. /* create the file before continuing to ensure we have write
  2195. access to the file */
  2196. f = fopen(stateFilename, "w");
  2197. if (f) {
  2198. fprintf(f, "logrotate state -- version 2\n");
  2199. fclose(f);
  2200. } else {
  2201. message(MESS_ERROR, "error creating state file %s: %s\n",
  2202. stateFilename, strerror(errno));
  2203. /* do not return until the hash table is allocated */
  2204. rc = 1;
  2205. }
  2206. }
  2207. /* Try to estimate how many state entries we have in the state file.
  2208. * We expect single entry to have around 80 characters (Of course this is
  2209. * just an estimation). During the testing I've found out that 200 entries
  2210. * per single hash entry gives good mem/performance ratio. */
  2211. if (allocateHash(f_stat.st_size / 80 / 200))
  2212. return 1;
  2213. if (rc || (f_stat.st_size == 0))
  2214. /* error already occurred, or we have no state file to read from */
  2215. return rc;
  2216. f = fopen(stateFilename, "r");
  2217. if (!f) {
  2218. message(MESS_ERROR, "error opening state file %s: %s\n",
  2219. stateFilename, strerror(errno));
  2220. return 1;
  2221. }
  2222. if (!fgets(buf, sizeof(buf) - 1, f)) {
  2223. message(MESS_ERROR, "error reading top line of %s\n",
  2224. stateFilename);
  2225. fclose(f);
  2226. return 1;
  2227. }
  2228. if (strcmp(buf, "logrotate state -- version 1\n") &&
  2229. strcmp(buf, "logrotate state -- version 2\n")) {
  2230. fclose(f);
  2231. message(MESS_ERROR, "bad top line in state file %s\n",
  2232. stateFilename);
  2233. return 1;
  2234. }
  2235. line++;
  2236. while (fgets(buf, sizeof(buf) - 1, f)) {
  2237. argv = NULL;
  2238. line++;
  2239. i = strlen(buf);
  2240. if (buf[i - 1] != '\n') {
  2241. message(MESS_ERROR, "line %d too long in state file %s\n",
  2242. line, stateFilename);
  2243. fclose(f);
  2244. return 1;
  2245. }
  2246. buf[i - 1] = '\0';
  2247. if (i == 1)
  2248. continue;
  2249. year = month = day = hour = minute = second = 0;
  2250. if (poptParseArgvString(buf, &argc, &argv) || (argc != 2) ||
  2251. (sscanf(argv[1], "%d-%d-%d-%d:%d:%d", &year, &month, &day, &hour, &minute, &second) < 3)) {
  2252. message(MESS_ERROR, "bad line %d in state file %s\n",
  2253. line, stateFilename);
  2254. free(argv);
  2255. fclose(f);
  2256. return 1;
  2257. }
  2258. /* Hack to hide earlier bug */
  2259. if ((year != 1900) && (year < 1970 || year > 2100)) {
  2260. message(MESS_ERROR,
  2261. "bad year %d for file %s in state file %s\n", year,
  2262. argv[0], stateFilename);
  2263. free(argv);
  2264. fclose(f);
  2265. return 1;
  2266. }
  2267. if (month < 1 || month > 12) {
  2268. message(MESS_ERROR,
  2269. "bad month %d for file %s in state file %s\n", month,
  2270. argv[0], stateFilename);
  2271. free(argv);
  2272. fclose(f);
  2273. return 1;
  2274. }
  2275. /* 0 to hide earlier bug */
  2276. if (day < 0 || day > 31) {
  2277. message(MESS_ERROR,
  2278. "bad day %d for file %s in state file %s\n", day,
  2279. argv[0], stateFilename);
  2280. free(argv);
  2281. fclose(f);
  2282. return 1;
  2283. }
  2284. if (hour < 0 || hour > 23) {
  2285. message(MESS_ERROR,
  2286. "bad hour %d for file %s in state file %s\n", hour,
  2287. argv[0], stateFilename);
  2288. free(argv);
  2289. fclose(f);
  2290. return 1;
  2291. }
  2292. if (minute < 0 || minute > 59) {
  2293. message(MESS_ERROR,
  2294. "bad minute %d for file %s in state file %s\n", minute,
  2295. argv[0], stateFilename);
  2296. free(argv);
  2297. fclose(f);
  2298. return 1;
  2299. }
  2300. if (second < 0 || second > 59) {
  2301. message(MESS_ERROR,
  2302. "bad second %d for file %s in state file %s\n", second,
  2303. argv[0], stateFilename);
  2304. free(argv);
  2305. fclose(f);
  2306. return 1;
  2307. }
  2308. year -= 1900, month -= 1;
  2309. filename = strdup(argv[0]);
  2310. unescape(filename);
  2311. if ((st = findState(filename)) == NULL) {
  2312. free(argv);
  2313. free(filename);
  2314. fclose(f);
  2315. return 1;
  2316. }
  2317. memset(&st->lastRotated, 0, sizeof(st->lastRotated));
  2318. st->lastRotated.tm_year = year;
  2319. st->lastRotated.tm_mon = month;
  2320. st->lastRotated.tm_mday = day;
  2321. st->lastRotated.tm_hour = hour;
  2322. st->lastRotated.tm_min = minute;
  2323. st->lastRotated.tm_sec = second;
  2324. st->lastRotated.tm_isdst = -1;
  2325. /* fill in the rest of the st->lastRotated fields */
  2326. lr_time = mktime(&st->lastRotated);
  2327. st->lastRotated = *localtime(&lr_time);
  2328. free(argv);
  2329. free(filename);
  2330. }
  2331. fclose(f);
  2332. return 0;
  2333. }
  2334. int main(int argc, const char **argv)
  2335. {
  2336. int force = 0;
  2337. const char *stateFile = STATEFILE;
  2338. char *logFile = NULL;
  2339. FILE *logFd = NULL;
  2340. int rc = 0;
  2341. int arg;
  2342. const char **files;
  2343. poptContext optCon;
  2344. struct logInfo *log;
  2345. struct poptOption options[] = {
  2346. {"debug", 'd', 0, NULL, 'd',
  2347. "Don't do anything, just test and print debug messages", NULL},
  2348. {"force", 'f', 0, &force, 0, "Force file rotation", NULL},
  2349. {"mail", 'm', POPT_ARG_STRING, &mailCommand, 0,
  2350. "Command to send mail (instead of `" DEFAULT_MAIL_COMMAND "')",
  2351. "command"},
  2352. {"state", 's', POPT_ARG_STRING, &stateFile, 0,
  2353. "Path of state file",
  2354. "statefile"},
  2355. {"verbose", 'v', 0, NULL, 'v', "Display messages during rotation", NULL},
  2356. {"log", 'l', POPT_ARG_STRING, &logFile, 'l', "Log file or 'syslog' to log to syslog",
  2357. "logfile"},
  2358. {"version", '\0', POPT_ARG_NONE, NULL, 'V', "Display version information", NULL},
  2359. POPT_AUTOHELP { NULL, 0, 0, NULL, 0, NULL, NULL }
  2360. };
  2361. logSetLevel(MESS_NORMAL);
  2362. setlocale (LC_ALL, "");
  2363. optCon = poptGetContext("logrotate", argc, argv, options, 0);
  2364. poptReadDefaultConfig(optCon, 1);
  2365. poptSetOtherOptionHelp(optCon, "[OPTION...] <configfile>");
  2366. while ((arg = poptGetNextOpt(optCon)) >= 0) {
  2367. switch (arg) {
  2368. case 'd':
  2369. debug = 1;
  2370. message(MESS_NORMAL, "WARNING: logrotate in debug mode does nothing"
  2371. " except printing debug messages! Consider using verbose"
  2372. " mode (-v) instead if this is not what you want.\n\n");
  2373. /* fallthrough */
  2374. case 'v':
  2375. logSetLevel(MESS_DEBUG);
  2376. break;
  2377. case 'l':
  2378. if (strcmp(logFile, "syslog") == 0) {
  2379. logToSyslog(1);
  2380. }
  2381. else {
  2382. logFd = fopen(logFile, "w");
  2383. if (!logFd) {
  2384. message(MESS_ERROR, "error opening log file %s: %s\n",
  2385. logFile, strerror(errno));
  2386. break;
  2387. }
  2388. logSetMessageFile(logFd);
  2389. }
  2390. break;
  2391. case 'V':
  2392. printf("logrotate %s\n", VERSION);
  2393. printf("\n");
  2394. printf(" Default mail command: %s\n", DEFAULT_MAIL_COMMAND);
  2395. printf(" Default compress command: %s\n", COMPRESS_COMMAND);
  2396. printf(" Default uncompress command: %s\n", UNCOMPRESS_COMMAND);
  2397. printf(" Default compress extension: %s\n", COMPRESS_EXT);
  2398. printf(" Default state file path: %s\n", STATEFILE);
  2399. #ifdef WITH_ACL
  2400. printf(" ACL support: yes\n");
  2401. #else
  2402. printf(" ACL support: no\n");
  2403. #endif
  2404. #ifdef WITH_SELINUX
  2405. printf(" SELinux support: yes\n");
  2406. #else
  2407. printf(" SELinux support: no\n");
  2408. #endif
  2409. poptFreeContext(optCon);
  2410. exit(0);
  2411. default:
  2412. break;
  2413. }
  2414. }
  2415. if (arg < -1) {
  2416. fprintf(stderr, "logrotate: bad argument %s: %s\n",
  2417. poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
  2418. poptStrerror(rc));
  2419. poptFreeContext(optCon);
  2420. return 2;
  2421. }
  2422. files = poptGetArgs((poptContext) optCon);
  2423. if (!files) {
  2424. fprintf(stderr, "logrotate " VERSION
  2425. " - Copyright (C) 1995-2001 Red Hat, Inc.\n");
  2426. fprintf(stderr,
  2427. "This may be freely redistributed under the terms of "
  2428. "the GNU General Public License\n\n");
  2429. poptPrintUsage(optCon, stderr, 0);
  2430. poptFreeContext(optCon);
  2431. exit(1);
  2432. }
  2433. #ifdef WITH_SELINUX
  2434. selinux_enabled = (is_selinux_enabled() > 0);
  2435. selinux_enforce = security_getenforce();
  2436. #endif
  2437. TAILQ_INIT(&logs);
  2438. if (readAllConfigPaths(files))
  2439. rc = 1;
  2440. poptFreeContext(optCon);
  2441. nowSecs = time(NULL);
  2442. if (readState(stateFile))
  2443. rc = 1;
  2444. message(MESS_DEBUG, "\nHandling %d logs\n", numLogs);
  2445. for (log = logs.tqh_first; log != NULL; log = log->list.tqe_next)
  2446. rc |= rotateLogSet(log, force);
  2447. if (!debug)
  2448. rc |= writeState(stateFile);
  2449. return (rc != 0);
  2450. }
  2451. /* vim: set et sw=4 ts=4: */