patch-logrotate_c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. $Id$
  2. --- logrotate-3.7.1.orig/logrotate.c Tue Oct 19 23:41:24 2004
  3. +++ logrotate-3.7.1/logrotate.c Sat Jan 20 18:56:30 2007
  4. @@ -11,6 +11,7 @@
  5. #include <sys/wait.h>
  6. #include <time.h>
  7. #include <unistd.h>
  8. +#include <glob.h>
  9. #ifdef WITH_SELINUX
  10. #include <selinux/selinux.h>
  11. @@ -22,6 +23,10 @@ int selinux_enabled=0;
  12. #include "log.h"
  13. #include "logrotate.h"
  14. +#if !defined(GLOB_ABORTED) && defined(GLOB_ABEND)
  15. +#define GLOB_ABORTED GLOB_ABEND
  16. +#endif
  17. +
  18. typedef struct {
  19. char * fn;
  20. struct tm lastRotated; /* only tm.mon, tm_mday, tm_year are good! */
  21. @@ -42,6 +47,14 @@ int debug = 0;
  22. char * mailCommand = DEFAULT_MAIL_COMMAND;
  23. time_t nowSecs = 0;
  24. +static int globerr(const char * pathname, int theerr) {
  25. + message(MESS_ERROR, "error accessing %s: %s\n", pathname,
  26. + strerror(theerr));
  27. +
  28. + /* We want the glob operation to continue, so return 0 */
  29. + return 1;
  30. +}
  31. +
  32. static logState * findState(const char * fn, struct stateSet * sip) {
  33. int i;
  34. logState * states = sip->states;
  35. @@ -49,9 +62,11 @@ static logState * findState(const char *
  36. struct tm now = *localtime(&nowSecs);
  37. time_t lr_time;
  38. + /* find the filename fn in the statesPtr list */
  39. for (i = 0; i < numStates; i++)
  40. if (!strcmp(fn, states[i].fn)) break;
  41. + /* not in statesPtr list, so add new entry */
  42. if (i == numStates) {
  43. i = numStates++;
  44. states = realloc(states, sizeof(*states) * numStates);
  45. @@ -75,10 +90,7 @@ static logState * findState(const char *
  46. }
  47. static int runScript(char * logfn, char * script) {
  48. - int fd;
  49. - char *filespec;
  50. int rc;
  51. - char buf[256];
  52. if (debug) {
  53. message(MESS_DEBUG, "running script with arg %s: \"%s\"\n",
  54. @@ -86,39 +98,24 @@ static int runScript(char * logfn, char
  55. return 0;
  56. }
  57. - filespec = buf;
  58. - snprintf(buf, sizeof(buf), "%s/logrotate.XXXXXX", getenv("TMPDIR") ?: "/tmp");
  59. - fd = -1;
  60. - if (!filespec || (fd = mkstemp(filespec)) < 0 || fchmod(fd, 0700)) {
  61. - message(MESS_DEBUG, "error creating %s: %s\n", filespec,
  62. - strerror(errno));
  63. - if (fd >= 0) {
  64. - close(fd);
  65. - unlink(filespec);
  66. - }
  67. - return -1;
  68. - }
  69. -
  70. - if (write(fd, "#!/bin/sh\n\n", 11) != 11 ||
  71. - write(fd, script, strlen(script)) != strlen(script)) {
  72. - message(MESS_DEBUG, "error writing %s\n", filespec);
  73. - close(fd);
  74. - unlink(filespec);
  75. - return -1;
  76. - }
  77. -
  78. - close(fd);
  79. -
  80. if (!fork()) {
  81. - execlp(filespec, filespec, logfn, NULL);
  82. + execl("/bin/sh", "sh", "-c", script, NULL);
  83. exit(1);
  84. }
  85. wait(&rc);
  86. + return rc;
  87. +}
  88. - unlink(filespec);
  89. +static int removeLogFile(char * name) {
  90. + message(MESS_DEBUG, "removing old log %s\n", name);
  91. - return rc;
  92. + if (!debug && unlink(name)) {
  93. + message(MESS_ERROR, "Failed to remove old log %s: %s\n",
  94. + name, strerror(errno));
  95. + return 1;
  96. + }
  97. + return 0;
  98. }
  99. static int compressLogFile(char * name, logInfo * log, struct stat *sb) {
  100. @@ -265,6 +262,25 @@ static int mailLog(char * logFile, char
  101. return rc;
  102. }
  103. +static int mailLogWrapper (char * mailFilename, char * mailCommand, int logNum, logInfo * log) {
  104. + /* if the log is compressed (and we're not mailing a
  105. + * file whose compression has been delayed), we need
  106. + * to uncompress it */
  107. + if ((log->flags & LOG_FLAG_COMPRESS) &&
  108. + !((log->flags & LOG_FLAG_DELAYCOMPRESS) &&
  109. + (log->flags & LOG_FLAG_MAILFIRST))) {
  110. + if (mailLog(mailFilename, mailCommand,
  111. + log->uncompress_prog, log->logAddress,
  112. + log->files[logNum]))
  113. + return 1;
  114. + } else {
  115. + if (mailLog(mailFilename, mailCommand, NULL,
  116. + log->logAddress, mailFilename))
  117. + return 1;
  118. + }
  119. + return 0;
  120. +}
  121. +
  122. static int copyTruncate(char * currLog, char * saveLog, struct stat * sb, int flags) {
  123. char buf[BUFSIZ];
  124. int fdcurr = -1, fdsave = -1;
  125. @@ -424,12 +440,15 @@ int findNeedRotating(logInfo * log, int
  126. switch (log->criterium) {
  127. case ROT_WEEKLY:
  128. /* rotate if:
  129. - 1) the current weekday is before the weekday of the
  130. - last rotation
  131. + 1) the day of the week is the same as the day of the week of
  132. + the previous rotation but not the same day of the year
  133. + this will rotate it on the same day every week, but not
  134. + twice a day.
  135. 2) more then a week has passed since the last
  136. rotation */
  137. - state->doRotate = ((now.tm_wday < state->lastRotated.tm_wday) ||
  138. - ((mktime(&now) - mktime(&state->lastRotated)) >
  139. + state->doRotate = ((now.tm_wday == state->lastRotated.tm_wday &&
  140. + now.tm_yday != state->lastRotated.tm_yday) ||
  141. + ((mktime(&now) - mktime(&state->lastRotated)) >
  142. (7 * 24 * 3600)));
  143. break;
  144. case ROT_MONTHLY:
  145. @@ -479,6 +498,9 @@ int rotateSingleLog(logInfo * log, int l
  146. char * baseName;
  147. char * dirName;
  148. char * firstRotated;
  149. + char * glob_pattern;
  150. + glob_t globResult;
  151. + int rc;
  152. size_t alloc_size;
  153. int rotateCount = log->rotateCount ? log->rotateCount : 1;
  154. int logStart = (log->logStart == -1) ? 1 : log->logStart;
  155. @@ -509,7 +531,7 @@ int rotateSingleLog(logInfo * log, int l
  156. alloc_size = strlen(dirName) + strlen(baseName) +
  157. strlen(log->files[logNum]) + strlen(fileext) +
  158. - strlen(compext) + 10;
  159. + strlen(compext) + 18;
  160. oldName = alloca(alloc_size);
  161. newName = alloca(alloc_size);
  162. @@ -531,16 +553,116 @@ int rotateSingleLog(logInfo * log, int l
  163. /* First compress the previous log when necessary */
  164. if (log->flags & LOG_FLAG_COMPRESS &&
  165. log->flags & LOG_FLAG_DELAYCOMPRESS) {
  166. - struct stat sbprev;
  167. -
  168. - sprintf(oldName, "%s/%s.%d%s", dirName, baseName, logStart, fileext);
  169. - if (stat(oldName, &sbprev)) {
  170. - message(MESS_DEBUG, "previous log %s does not exist\n",
  171. - oldName);
  172. - } else {
  173. - hasErrors = compressLogFile(oldName, log, &sbprev);
  174. + if (log->flags & LOG_FLAG_DATEEXT) {
  175. + /* glob for uncompressed files with our pattern */
  176. + glob_pattern = malloc(strlen(dirName) + strlen(baseName)
  177. + + strlen(fileext) + 44 );
  178. + sprintf(glob_pattern,
  179. + "%s/%s-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%s",
  180. + dirName, baseName, fileext);
  181. + rc = glob(glob_pattern, 0, globerr, &globResult);
  182. + if (!rc && globResult.gl_pathc > 0) {
  183. + for (i = 0; i < globResult.gl_pathc && !hasErrors; i++) {
  184. + struct stat sbprev;
  185. + sprintf(oldName,"%s",(globResult.gl_pathv)[i]);
  186. + if (stat(oldName, &sbprev)) {
  187. + message(MESS_DEBUG, "previous log %s does not exist\n", oldName);
  188. + } else {
  189. + hasErrors = compressLogFile(oldName, log, &sbprev);
  190. + }
  191. + }
  192. + } else {
  193. + message (MESS_DEBUG, "glob finding logs to compress failed\n");
  194. + /* fallback to old behaviour */
  195. + sprintf(oldName, "%s/%s.%d%s", dirName, baseName, logStart, fileext);
  196. + }
  197. + globfree(&globResult);
  198. + free(glob_pattern);
  199. + } else {
  200. + struct stat sbprev;
  201. +
  202. + sprintf(oldName, "%s/%s.%d%s", dirName, baseName, logStart, fileext);
  203. + if (stat(oldName, &sbprev)) {
  204. + message(MESS_DEBUG, "previous log %s does not exist\n",
  205. + oldName);
  206. + } else {
  207. + hasErrors = compressLogFile(oldName, log, &sbprev);
  208. + }
  209. }
  210. }
  211. +
  212. + firstRotated = alloca(strlen(dirName) + strlen(baseName) +
  213. + strlen(fileext) + strlen(compext) + 30);
  214. +
  215. + if(log->flags & LOG_FLAG_DATEEXT) {
  216. + /* glob for compressed files with our pattern
  217. + * and compress ext */
  218. + glob_pattern = malloc(strlen(dirName)+strlen(baseName)
  219. + +strlen(fileext)+strlen(compext)+44);
  220. + sprintf(glob_pattern,
  221. + "%s/%s-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%s%s",
  222. + dirName, baseName, fileext, compext);
  223. + rc = glob(glob_pattern, 0, globerr, &globResult);
  224. + if (!rc) {
  225. + /* search for files to drop, if we find one remember it,
  226. + * if we find another one mail and remove the first and
  227. + * remember the second and so on */
  228. + struct stat fst_buf;
  229. + int mail_out = -1;
  230. + /* remove the first (n - rotateCount) matches
  231. + * no real rotation needed, since the files have
  232. + * the date in their name */
  233. + for (i = 0; i < globResult.gl_pathc; i++) {
  234. + if( !stat((globResult.gl_pathv)[i],&fst_buf) ) {
  235. + if ((i <= ((int)globResult.gl_pathc - rotateCount))
  236. + || ((log->rotateAge > 0)
  237. + && (((nowSecs - fst_buf.st_mtime)/60/60/24)
  238. + > log->rotateAge))) {
  239. + if ( mail_out != -1 ) {
  240. + if (!hasErrors && log->logAddress) {
  241. + char * mailFilename = (globResult.gl_pathv)[mail_out];
  242. + hasErrors = mailLogWrapper(mailFilename, mailCommand, logNum, log);
  243. + if (!hasErrors)
  244. + hasErrors = removeLogFile(mailFilename);
  245. + }
  246. + }
  247. + mail_out = i;
  248. + }
  249. + }
  250. + }
  251. + if ( mail_out != -1 ) {
  252. + /* oldName is oldest Backup found (for unlink later) */
  253. + sprintf(oldName, "%s", (globResult.gl_pathv)[mail_out]);
  254. + strcpy(disposeName, oldName);
  255. + } else
  256. + disposeName = NULL;
  257. + } else {
  258. + message (MESS_DEBUG, "glob finding old rotated logs failed\n");
  259. + disposeName = NULL;
  260. + }
  261. + /* firstRotated is most recently created/compressed rotated log */
  262. + sprintf(firstRotated, "%s/%s-%04d%02d%02d%s%s",
  263. + dirName, baseName, now.tm_year+1900,
  264. + now.tm_mon+1, now.tm_mday, fileext, compext);
  265. + globfree(&globResult);
  266. + free(glob_pattern);
  267. + } else {
  268. + if ( log->rotateAge ) {
  269. + struct stat fst_buf;
  270. + for (i=1; i <= rotateCount; i++) {
  271. + sprintf(oldName, "%s/%s.%d%s%s", dirName, baseName,
  272. + rotateCount + 1, fileext, compext);
  273. + if(!stat(oldName,&fst_buf)
  274. + && (((nowSecs - fst_buf.st_mtime)/60/60/24)
  275. + > log->rotateAge)) {
  276. + char * mailFilename = (globResult.gl_pathv)[i];
  277. + if (!hasErrors && log->logAddress)
  278. + hasErrors = mailLogWrapper(mailFilename, mailCommand, logNum, log);
  279. + if (!hasErrors)
  280. + hasErrors = removeLogFile(mailFilename);
  281. + }
  282. + }
  283. + }
  284. sprintf(oldName, "%s/%s.%d%s%s", dirName, baseName,
  285. logStart + rotateCount, fileext, compext);
  286. @@ -548,8 +670,6 @@ int rotateSingleLog(logInfo * log, int l
  287. strcpy(disposeName, oldName);
  288. - firstRotated = alloca(strlen(dirName) + strlen(baseName) +
  289. - strlen(fileext) + strlen(compext) + 30);
  290. sprintf(firstRotated, "%s/%s.%d%s%s", dirName, baseName,
  291. logStart, fileext,
  292. (log->flags & LOG_FLAG_DELAYCOMPRESS) ? "" : compext);
  293. @@ -600,12 +720,27 @@ int rotateSingleLog(logInfo * log, int l
  294. }
  295. }
  296. }
  297. -
  298. + } /* !LOG_FLAG_DATEEXT */
  299. +
  300. finalName = oldName;
  301. -
  302. - /* note: the gzip extension is *not* used here! */
  303. - sprintf(finalName, "%s/%s.%d%s", dirName, baseName, logStart, fileext);
  304. -
  305. +
  306. + if(log->flags & LOG_FLAG_DATEEXT) {
  307. + char * destFile = alloca(strlen(dirName) + strlen(baseName) +
  308. + strlen(fileext) + strlen(compext) + 30);
  309. + struct stat fst_buf;
  310. + sprintf(finalName, "%s/%s-%04d%02d%02d%s",
  311. + dirName, baseName, now.tm_year+1900,
  312. + now.tm_mon+1, now.tm_mday, fileext);
  313. + sprintf(destFile, "%s%s", finalName, compext);
  314. + if(!stat(destFile,&fst_buf)) {
  315. + message (MESS_DEBUG, "destination %s already exists, skipping rotation\n", firstRotated);
  316. + hasErrors = 1;
  317. + }
  318. + } else {
  319. + /* note: the gzip extension is *not* used here! */
  320. + sprintf(finalName, "%s/%s.%d%s", dirName, baseName, logStart, fileext);
  321. + }
  322. +
  323. /* if the last rotation doesn't exist, that's okay */
  324. if (!debug && access(disposeName, F_OK)) {
  325. message(MESS_DEBUG, "log %s doesn't exist -- won't try to "
  326. @@ -613,9 +748,6 @@ int rotateSingleLog(logInfo * log, int l
  327. disposeName = NULL;
  328. }
  329. - free(dirName);
  330. - free(baseName);
  331. -
  332. if (!hasErrors) {
  333. if (log->pre && !(log->flags & LOG_FLAG_SHAREDSCRIPTS)) {
  334. message(MESS_DEBUG, "running prerotate script\n");
  335. @@ -722,33 +854,12 @@ int rotateSingleLog(logInfo * log, int l
  336. else
  337. mailFilename = disposeName;
  338. - if (mailFilename) {
  339. - /* if the log is compressed (and we're not mailing a
  340. - file whose compression has been delayed), we need
  341. - to uncompress it */
  342. - if ((log->flags & LOG_FLAG_COMPRESS) &&
  343. - !((log->flags & LOG_FLAG_DELAYCOMPRESS) &&
  344. - (log->flags & LOG_FLAG_MAILFIRST))) {
  345. - if (mailLog(mailFilename, mailCommand,
  346. - log->uncompress_prog, log->logAddress,
  347. - log->files[logNum]))
  348. - hasErrors = 1;
  349. - } else {
  350. - if (mailLog(mailFilename, mailCommand, NULL,
  351. - log->logAddress, mailFilename))
  352. - hasErrors = 1;
  353. - }
  354. - }
  355. + if (mailFilename)
  356. + hasErrors = mailLogWrapper(mailFilename, mailCommand, logNum, log);
  357. }
  358. if (!hasErrors && disposeName) {
  359. - message(MESS_DEBUG, "removing old log %s\n", disposeName);
  360. -
  361. - if (!debug && unlink(disposeName)) {
  362. - message(MESS_ERROR, "Failed to remove old log %s: %s\n",
  363. - disposeName, strerror(errno));
  364. - hasErrors = 1;
  365. - }
  366. + hasErrors = removeLogFile(disposeName);
  367. }
  368. }
  369. @@ -761,6 +872,8 @@ int rotateSingleLog(logInfo * log, int l
  370. }
  371. }
  372. #endif
  373. + free(dirName);
  374. + free(baseName);
  375. return hasErrors;
  376. }
  377. @@ -1002,7 +1115,7 @@ static int readState(char * stateFilenam
  378. }
  379. /* Hack to hide earlier bug */
  380. - if ((year != 1900) && (year < 1996 || year > 2100)) {
  381. + if ((year != 1900) && (year < 1970 || year > 2100)) {
  382. message(MESS_ERROR, "bad year %d for file %s in state file %s\n",
  383. year, argv[0], stateFilename);
  384. fclose(f);
  385. @@ -1047,7 +1160,9 @@ static int readState(char * stateFilenam
  386. int main(int argc, const char ** argv) {
  387. logInfo defConfig = { NULL, NULL, 0, NULL, ROT_SIZE,
  388. - /* threshHold */ 1024 * 1024, 0,
  389. + /* threshHold */ 1024 * 1024,
  390. + /* rotateCount */ 0,
  391. + /* rotateAge */ 0,
  392. /* log start */ -1,
  393. /* pre, post */ NULL, NULL,
  394. /* first, last */ NULL, NULL,
  395. @@ -1108,8 +1223,7 @@ int main(int argc, const char ** argv) {
  396. files = poptGetArgs((poptContext) optCon);
  397. if (!files) {
  398. - fprintf(stderr, "logrotate " VERSION
  399. - " - Copyright (C) 1995-2001 Red Hat, Inc.\n");
  400. + fprintf(stderr, "logrotate - Copyright (C) 1995-2001 Red Hat, Inc.\n");
  401. fprintf(stderr, "This may be freely redistributed under the terms of "
  402. "the GNU Public License\n\n");
  403. poptPrintUsage(optCon, stderr, 0);