1 /* $Id: crosspost.c 6135 2003-01-19 01:15:40Z rra $
3 ** Parse input to add links for cross posted articles. Input format is one
4 ** line per article. Dots '.' are changed to '/'. Commas ',' or blanks
5 ** ' ' separate entries. Typically this is via a channel feed from innd
6 ** though an edit of the history file can also be used for recovery
7 ** purposes. Sample newsfeeds entry:
9 ** # Create the links for cross posted articles
10 ** crosspost:*:Tc,Ap,WR:/usr/local/newsbin/crosspost
12 ** WARNING: This no longer works with the current INN; don't use it
13 ** currently. It still exists in the source tree in case someone will
14 ** want to clean it up and make it useable again.
31 static int debug = false;
32 static int syncfiles = true;
34 static unsigned long STATTime = 0;
35 static unsigned long STATMissing = 0; /* Source file missing */
36 static unsigned long STATTooLong = 0; /* Name Too Long (src or dest) */
37 static unsigned long STATLink = 0; /* Link done */
38 static unsigned long STATLError = 0; /* Link problem */
39 static unsigned long STATSymlink = 0; /* Symlink done */
40 static unsigned long STATSLError = 0; /* Symlink problem */
41 static unsigned long STATMkdir = 0; /* Mkdir done */
42 static unsigned long STATMdError = 0; /* Mkdir problem */
43 static unsigned long STATOError = 0; /* Other errors */
46 #define STATREFRESH 10800 /* 3 hours */
49 ** Write some statistics and reset all counters.
58 "seconds %lu links %lu %lu symlinks %lu %lu mkdirs %lu %lu missing %lu toolong %lu other %lu",
59 Time - STATTime, STATLink, STATLError, STATSymlink, STATSLError,
60 STATMkdir, STATMdError, STATMissing, STATTooLong, STATOError);
62 STATMissing = STATTooLong = STATLink = STATLError = 0;
63 STATSymlink = STATSLError = STATMkdir = STATMdError = STATOError = 0;
68 ** Try to make one directory. Return false on error.
76 if (mkdir(Name, GROUPDIR_MODE) >= 0) {
81 /* See if it failed because it already exists. */
82 return stat(Name, &Sb) >= 0 && S_ISDIR(Sb.st_mode);
87 ** Make spool directory. Return false on error.
96 /* Optimize common case -- parent almost always exists. */
100 /* Try to make each of comp and comp/foo in turn. */
101 for (p = Name; *p; p++)
104 made = MakeDir(Name);
112 return MakeDir(Name);
117 ** Process the input. Data can come from innd:
118 ** news/group/name/<number> [space news/group/<number>]...
120 ** news.group.name/<number>,[news.group.name/<number>]...
131 char *names[MAXXPOST];
136 if (time(NULL) - STATTime > STATREFRESH)
139 /* Read the first line of data. */
140 if ((p = QIOread(qp)) == NULL) {
141 if (QIOtoolong(qp)) {
142 fprintf(stderr, "crosspost line too long\n");
149 for (i = 0; *p && (i < MAXXPOST); i++) { /* parse input into array */
152 if (*p == '.') *p++ = '/'; /* dot to slash translation */
153 else if ((*p == ',') /* name separators */
164 for (i = 0; i < nxp; i++)
165 fprintf(stderr, "crosspost: debug %d %s\n",
169 if(syncfiles) fd = open(names[0], O_RDWR);
171 for (i = 1; i < nxp; i++) {
172 lnval = link(names[0], names[i]) ;
173 if (lnval == 0) STATLink++;
174 if (lnval < 0 && errno != EXDEV) { /* first try to link */
176 char path[SPOOLNAMEBUFF+2];
178 for (j = 0; (path[j] = names[i][j]) != '\0' ; j++) ;
179 for (j--; (j > 0) && (path[j] != '/'); j--) ;
180 if (path[j] == '/') {
182 /* try making parent dir */
183 if (MakeSpoolDir(path) == false) {
184 fprintf(stderr, "crosspost cant mkdir %s\n",
188 /* 2nd try to link */
189 lnval = link(names[0], names[i]) ;
190 if (lnval == 0) STATLink++;
191 if (lnval < 0 && errno == EXDEV) {
192 #if !defined(HAVE_SYMLINK)
193 fprintf(stderr, "crosspost cant link %s %s",
197 /* Try to make a symbolic link
198 ** to the full pathname.
200 for (j = 0, p = Dir; (j < SPOOLNAMEBUFF) && *p; )
201 path[j++] = *p++; /* copy spool dir */
202 if (j < SPOOLNAMEBUFF) path[j++] = '/';
203 for (p = names[0]; (j < SPOOLNAMEBUFF) && *p; )
204 path[j++] = *p++; /* append path */
206 if (symlink(path, names[i]) < 0) {
208 "crosspost cant symlink %s %s",
215 #endif /* !defined(HAVE_SYMLINK) */
216 } else if (lnval < 0) {
220 fprintf(stderr, "crosspost cant link %s %s",
228 fprintf(stderr, "crosspost bad path %s\n",
232 } else if (lnval < 0) {
234 char path[SPOOLNAMEBUFF+2];
236 #if !defined(HAVE_SYMLINK)
237 fprintf(stderr, "crosspost cant link %s %s",
241 /* Try to make a symbolic link
242 ** to the full pathname.
244 for (j = 0, p = Dir; (j < SPOOLNAMEBUFF) && *p; )
245 path[j++] = *p++; /* copy spool dir */
246 if (j < SPOOLNAMEBUFF) path[j++] = '/';
247 for (p = names[0]; (j < SPOOLNAMEBUFF) && *p; )
248 path[j++] = *p++; /* append path */
250 if (symlink(path, names[i]) < 0) {
252 "crosspost cant symlink %s %s",
259 #endif /* !defined(HAVE_SYMLINK) */
263 if (syncfiles && (fd >= 0)) {
270 fprintf(stderr, "crosspost cant read %s\n", strerror(errno));
278 fprintf(stderr, "usage: crosspost [-D dir] [files...]\n");
292 if (ReadInnConf() < 0) exit(1);
293 Dir = innconf->patharticles;
297 while ((i = getopt(ac, av, "D:ds")) != EOF)
303 Dir = optarg; /* specify spool path */
309 syncfiles = false; /* do not fsync articles */
315 if (chdir(Dir) < 0) {
316 fprintf(stderr, "crosspost cant chdir %s %s\n",
317 Dir, strerror(errno));
320 openlog("crosspost", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
321 STATTime = time (NULL);
323 ProcessIncoming(QIOfdopen(STDIN_FILENO));
326 if (strcmp(*av, "-") == 0)
327 ProcessIncoming(QIOfdopen(STDIN_FILENO));
328 else if ((qp = QIOopen(*av)) == NULL)
329 fprintf(stderr, "crosspost cant open %s %s\n",
330 *av, strerror(errno));