📄 expire.c
字号:
*size = (int)(((long)Sb.st_size >> 10) + (((long)Sb.st_size >> 9) & 1)); if (EXPverbose > 1) (void)printf("\tunlink %s\n", p); EXPunlinked++; if (EXPtracing) { (void)printf("%s\n", p); return; } if (EXPunlinkfile) { (void)fprintf(EXPunlinkfile, "%s\n", p); if (!ferror(EXPunlinkfile)) return; (void)fprintf(stderr, "Can't write to -z file, %s\n", strerror(errno)); (void)fprintf(stderr, "(Will ignore it for rest of run.)\n"); (void)fclose(EXPunlinkfile); EXPunlinkfile = NULL; } if (unlink(p) < 0 && errno != ENOENT) (void)fprintf(stderr, "Can't unlink %s, %s\n", p, strerror(errno));}/*** Do the work of expiring one line.*/STATIC BOOLEXPdoline(out, line, length, arts) FILE *out; char *line; int length; char **arts;{ static char IGNORING[] = "Ignoring bad line, \"%.20s...\"\n"; static long Offset; static BUFFER New; register char *p; register char *q; register char *first; register int i; int count; char *fields[4]; time_t Arrived; time_t Expires; time_t Posted; time_t when; long where; long size; datum key; datum value; char date[20]; /* Split up the major fields. */ i = EXPsplit(line, HIS_FIELDSEP, fields, SIZEOF(fields)); if (i != 2 && i != 3) { (void)fprintf(stderr, IGNORING, line); return TRUE; } /* Split up the time field, robustly. */ if ((p = strchr(fields[1], HIS_SUBFIELDSEP)) == NULL) { /* One sub-field: when the article arrived. */ Arrived = atol(fields[1]); Expires = 0; Posted = Arrived; } else { *p = '\0'; Arrived = atol(fields[1]); *p++ = HIS_SUBFIELDSEP; if ((q = strchr(p, HIS_SUBFIELDSEP)) == NULL) { /* Two sub-fields: arrival and expiration. */ Expires = EQ(p, HIS_NOEXP) ? 0 : atol(p); Posted = Arrived; } else { /* All three sub-fields: arrival, expiration, posted. */ *q = '\0'; Expires = EQ(p, HIS_NOEXP) ? 0 : atol(p); *q++ = HIS_SUBFIELDSEP; Posted = atol(q); } } if (i == 2) { /* History line for already-expired article. */ if (Arrived < EXPremember) { if (EXPverbose > 3) (void)printf("forget: %s\n", line); EXPhistdrop++; return TRUE; } /* Not time to forget about this one yet. */ if (out) { where = Offset; (void)fprintf(out, "%s%c%s\n", fields[0], HIS_FIELDSEP, fields[1]); Offset += strlen(fields[0]) + 1 + strlen(fields[1]) + 1; if (EXPverbose > 3) (void)printf("remember: %s\n", line); EXPhistremember++; } } else { /* Active article -- split up the file entries. */ count = EXPsplit(fields[2], ' ', arts, nGroups); if (count == -1) { (void)fprintf(stderr, IGNORING, line); return TRUE; } EXPprocessed++; when = EXPusepost ? Posted : Arrived; /* Get space to hold the remaining file name entries. */ if (New.Data == NULL) { New.Size = length; New.Data = NEW(char, New.Size); } else if (New.Size < length) { New.Size = length; RENEW(New.Data, char, New.Size); } /* The "first" variable tells us if we haven't saved the first * article yet. This only matters if we're doing link-saving. */ first = EXPlinks && count > 1 ? arts[0] : (char *)NULL; /* Loop over all file entries, see if we should keep each one. */ for (size = -1, q = New.Data, i = 0; i < count; i++) { p = arts[i]; if (*p == '\0') /* Shouldn't happen. */ continue; if (EXPkeepit(p, when, Expires)) { if (EXPverbose > 1) (void)printf("keep %s\n", p); if (first != NULL) { /* Keeping one and haven't kept the first; so save it. */ if (i > 0) q += strlen(strcpy(q, first)); first = NULL; } if (q > New.Data) *q++ = ' '; q += strlen(strcpy(q, p)); continue; } /* Don't delete the file if preserving symbolic links to it. */ if (EXPlinks && i == 0 && count > 1) continue; EXPremove(arts[i], &size); } /* If saving links and didn't have to save the leader, delete it. */ if (EXPlinks && first != NULL) EXPremove(first, &size); if (q == New.Data) { if (EXPsizing && size > 0) EXPsaved += size; if (EXPremember > 0 && out != NULL) { where = Offset; (void)sprintf(date, "%ld", (long)Arrived); (void)fprintf(out, "%s%c%s%c%s\n", fields[0], HIS_FIELDSEP, date, HIS_SUBFIELDSEP, HIS_NOEXP); Offset += strlen(fields[0]) + 1 + strlen(date) + 1 + STRLEN(HIS_NOEXP) + 1; if (EXPverbose > 3) (void)printf("remember history: %s%c%s%c%s\n", fields[0], HIS_FIELDSEP, date, HIS_SUBFIELDSEP, HIS_NOEXP); EXPallgone++; } } else if (out) { where = Offset; (void)fprintf(out, "%s%c%s%c%s\n", fields[0], HIS_FIELDSEP, fields[1], HIS_FIELDSEP, New.Data); Offset += strlen(fields[0]) + 1 + strlen(fields[1]) + 1 + strlen(New.Data) + 1; if (EXPverbose > 3) (void)printf("remember article: %s%c%s%c%s\n", fields[0], HIS_FIELDSEP, fields[1], HIS_FIELDSEP, New.Data); EXPstillhere++; } } if (out == NULL) return TRUE; if (ferror(out)) { (void)fprintf(stderr, "Can't write new history, %s\n", strerror(errno)); return FALSE; } /* Set up the DBZ data. We don't have to sanitize the Message-ID * since it had to have been clean to get in there. */ key.dptr = fields[0]; key.dsize = strlen(key.dptr) + 1; value.dptr = (char *)&where; value.dsize = sizeof where; if (EXPverbose > 4) (void)printf("\tdbz %s@%ld\n", key.dptr, where); if (dbzstore(key, value) < 0) { (void)fprintf(stderr, "Can't store key, %s\n", strerror(errno)); return FALSE; } return TRUE;}/*** Clean up link with the server and exit.*/STATIC NORETURNCleanupAndExit(Server, Paused, x) BOOL Server; BOOL Paused; int x;{ FILE *F; if (Server) (void)ICCreserve(""); if (Paused && ICCgo(EXPreason) != 0) { (void)fprintf(stderr, "Can't unpause server, %s\n", strerror(errno)); x = 1; } if (Server && ICCclose() < 0) { (void)fprintf(stderr, "Can't close communication link, %s\n", strerror(errno)); x = 1; } if (EXPunlinkfile && fclose(EXPunlinkfile) == EOF) { (void)fprintf(stderr, "Can't close -z file, %s\n", strerror(errno)); x = 1; } /* Report stats. */ if (EXPverbose) { (void)printf("Article lines processed %8ld\n", EXPprocessed); (void)printf("Articles retained %8ld\n", EXPstillhere); (void)printf("Entries expired %8ld\n", EXPallgone); (void)printf("Files unlinked %8ld\n", EXPunlinked); (void)printf("Old entries dropped %8ld\n", EXPhistdrop); (void)printf("Old entries retained %8ld\n", EXPhistremember); } /* Append statistics to a summary file */ if (EXPgraph) { F = EXPfopen(FALSE, EXPgraph, "a"); (void)fprintf(F, "%ld %ld %ld %ld %ld %ld %ld\n", (long)Now, EXPprocessed, EXPstillhere, EXPallgone, EXPunlinked, EXPhistdrop, EXPhistremember); (void)fclose(F); } exit(x);}/*** Print a usage message and exit.*/STATIC NORETURNUsage(){ (void)fprintf(stderr, "Usage: expire [flags] [expire.ctl]\n"); exit(1);}intmain(ac, av) int ac; char *av[];{ static char CANTCD[] = "Can't cd to %s, %s\n"; register int i; register int line; register char *p; register QIOSTATE *qp; FILE *F; char *active; char **arts; STRING History; STRING HistoryText; STRING HistoryPath; STRING HistoryDB; char *Historydir; char *Historypag; char *NHistory; char *NHistorydir; char *NHistorypag; char buff[SMBUF]; register FILE *out; BOOL Server; BOOL Paused; BOOL Bad; BOOL IgnoreOld; BOOL Writing; BOOL UnlinkFile; time_t TimeWarp; /* Set defaults. */ Server = TRUE; IgnoreOld = FALSE; History = "history"; HistoryText = _PATH_HISTORY; HistoryPath = NULL; Writing = TRUE; TimeWarp = 0; UnlinkFile = FALSE; (void)umask(NEWSUMASK); /* Parse JCL. */ while ((i = getopt(ac, av, "f:h:d:g:ilnpqr:stv:w:xz:")) != EOF) switch (i) { default: Usage(); /* NOTREACHED */ case 'd': HistoryPath = optarg; break; case 'f': History = optarg; break; case 'g': EXPgraph = optarg; break; case 'h': HistoryText = optarg; break; case 'i': IgnoreOld = TRUE; break; case 'l': EXPlinks = TRUE; break; case 'n': Server = FALSE; break; case 'p': EXPusepost = TRUE; break; case 'q': EXPquiet = TRUE; break; case 'r': EXPreason = optarg; break; case 's': EXPsizing = TRUE; break; case 't': EXPtracing = TRUE; break; case 'v': EXPverbose = atoi(optarg); break; case 'w': TimeWarp = (time_t)(atof(optarg) * 86400.); break; case 'x': Writing = FALSE; break; case 'z': EXPunlinkfile = EXPfopen(TRUE, optarg, "a"); UnlinkFile = TRUE; break; } ac -= optind; av += optind; if (ac != 0 && ac != 1) Usage(); /* Get active file, parse it. */ if ((active = ReadInFile(ACTIVE, (struct stat *)NULL)) == NULL) { (void)fprintf(stderr, "Can't read %s, %s\n", ACTIVE, strerror(errno)); exit(1); } BuildGroups(active); (void)time(&Now); Now += TimeWarp; /* Parse the control file. */ if (av[0]) F = EQ(av[0], "-") ? stdin : EXPfopen(FALSE, av[0], "r"); else F = EXPfopen(FALSE, _PATH_EXPIRECTL, "r"); if (!EXPreadfile(F)) { (void)fclose(F); (void)fprintf(stderr, "Format error in control file\n"); exit(1); } (void)fclose(F); /* Set up the link, reserve the lock. */ if (EXPreason == NULL) { (void)sprintf(buff, "Expiring process %ld", (long)getpid()); EXPreason = COPY(buff); } if (Server) { /* If we fail, leave evidence behind. */ if (ICCopen() < 0) { (void)fprintf(stderr, "Can't open channel to server, %s\n", strerror(errno)); CleanupAndExit(FALSE, FALSE, 1); } if (ICCreserve(EXPreason) != 0) { (void)fprintf(stderr, "Can't reserve server\n"); CleanupAndExit(FALSE, FALSE, 1); } } /* Make the history filenames. */ HistoryDB = COPY(HistoryText); (void)sprintf(buff, "%s.dir", HistoryDB); Historydir = COPY(buff); (void)sprintf(buff, "%s.pag", HistoryDB); Historypag = COPY(buff); if (HistoryPath) (void)sprintf(buff, "%s/%s.n", HistoryPath, History); else (void)sprintf(buff, "%s.n", History); NHistory = COPY(buff); (void)sprintf(buff, "%s.dir", NHistory); NHistorydir = COPY(buff); (void)sprintf(buff, "%s.pag", NHistory); NHistorypag = COPY(buff); if (!Writing) out = NULL; else { /* Open new history files, relative to news lib. */ if (chdir(EXPnewslib) < 0) { (void)fprintf(stderr, CANTCD, EXPnewslib, strerror(errno)); exit(1); } out = EXPfopen(TRUE, NHistory, "w"); (void)fclose(EXPfopen(TRUE, NHistorydir, "w")); (void)fclose(EXPfopen(TRUE, NHistorypag, "w")); if (EXPverbose > 3) (void)printf("created: %s %s %s\n", NHistory, NHistorydir, NHistorypag); (void)dbzincore(1); if (IgnoreOld) { if (dbzfresh(NHistory, dbzsize(0L), '\t', 'C', 0L) < 0) { (void)fprintf(stderr, "Can't create database, %s\n", strerror(errno)); exit(1); } } else if (dbzagain(NHistory, HistoryDB) < 0) { (void)fprintf(stderr, "Can't dbzagain, %s\n", strerror(errno)); exit(1); } } if (chdir(SPOOL) < 0) { (void)fprintf(stderr, CANTCD, SPOOL, strerror(errno)); exit(1); } /* Main processing loop. */ arts = NEW(char*, nGroups); if ((qp = QIOopen(HistoryText, QIO_BUFFER)) == NULL) { (void)fprintf(stderr, "Can't open history file, %s\n", strerror(errno)); CleanupAndExit(Server, FALSE, 1); } for (Bad = FALSE, line = 1, Paused = FALSE; ; line++) { if ((p = QIOread(qp)) != NULL) { if (!EXPdoline(out, p, QIOlength(qp), arts)) { Bad = TRUE; if (errno == ENOSPC) { (void)unlink(NHistory); (void)unlink(NHistorydir); (void)unlink(NHistorypag); } break; } continue; } /* Read or line-format error? */ if (QIOerror(qp)) { (void)fprintf(stderr, "Can't read line %d, %s\n", line, strerror(errno)); QIOclose(qp); CleanupAndExit(Server, Paused, 1); } if (QIOtoolong(qp)) { (void)fprintf(stderr, "Line %d too long\n", line); QIOclose(qp); CleanupAndExit(Server, Paused, 1); } /* We hit EOF. */ if (Paused || !Server) /* Already paused or we don't want to pause -- we're done. */ break; if (ICCpause(EXPreason) != 0) { (void)fprintf(stderr, "Can't pause server, %s\n", strerror(errno)); QIOclose(qp); CleanupAndExit(Server, Paused, 1); } Paused = TRUE; } QIOclose(qp); DISPOSE(arts); if (Writing) { /* Close the output files. */ if (ferror(out) || fflush(out) == EOF || fclose(out) == EOF) { (void)fprintf(stderr, "Can't close %s, %s\n", NHistory, strerror(errno)); Bad = TRUE; } if (dbmclose() < 0) { (void)fprintf(stderr, "Can't close history, %s\n", strerror(errno)); Bad = TRUE; } if (UnlinkFile && EXPunlinkfile == NULL) /* Got -z but file was closed; oops. */ Bad = TRUE; /* If we're done okay, and we're not tracing, slip in the new files. */ if (EXPverbose) { if (Bad) (void)printf("Expire errors: history files not updated.\n"); if (EXPtracing) (void)printf("Expire tracing: history files not updated.\n"); } if (!Bad && !EXPtracing) { if (chdir(EXPnewslib) < 0) { (void)fprintf(stderr, CANTCD, EXPnewslib, strerror(errno)); CleanupAndExit(Server, Paused, 1); } /* If user used the -d flag, mark we're done and exit. */ if (HistoryPath != NULL) { (void)sprintf(buff, "%s.done", NHistory); (void)fclose(EXPfopen(FALSE, buff, "w")); CleanupAndExit(Server, FALSE, 0); } if (rename(NHistory, HistoryText) < 0 || rename(NHistorydir, Historydir) < 0 || rename(NHistorypag, Historypag) < 0) { (void)fprintf(stderr, "Can't replace history files, %s\n", strerror(errno)); /* Yes -- leave the server paused. */ CleanupAndExit(Server, FALSE, 1); } } } if (EXPsizing) (void)printf("%s approximately %ldk\n", EXPtracing ? "Would remove" : "Removed", EXPsaved); CleanupAndExit(Server, Paused, Bad ? 1 : 0); /* NOTREACHED */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -