1/* xqtfil.c
2   Routines to read execute files.
3
4   Copyright (C) 1991, 1992, 1993, 1995, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#if USE_RCS_ID
28const char xqtfil_rcsid[] = "$Id: xqtfil.c,v 1.13 2002/03/05 19:10:42 ian Rel $";
29#endif
30
31#include "uudefs.h"
32#include "sysdep.h"
33#include "system.h"
34
35#include <errno.h>
36
37#if HAVE_OPENDIR
38#if HAVE_DIRENT_H
39#include <dirent.h>
40#else /* ! HAVE_DIRENT_H */
41#include <sys/dir.h>
42#define dirent direct
43#endif /* ! HAVE_DIRENT_H */
44#endif /* HAVE_OPENDIR */
45
46/* Under the V2 or BSD42 spool directory scheme, all execute files are
47   in the main spool directory.  Under the BSD43 scheme, they are all
48   in the directory X..  Under the HDB or SVR4 scheme, they are in
49   directories named after systems.  Under the ULTRIX scheme, they are
50   in X.  subdirectories of subdirectories of sys.  Under the TAYLOR
51   scheme, they are all in the subdirectory X. of a directory named
52   after the system.
53
54   This means that for HDB, ULTRIX, SVR4 or TAYLOR, we have to search
55   directories of directories.  */
56
57#if SPOOLDIR_V2 || SPOOLDIR_BSD42
58#define ZDIR "."
59#define SUBDIRS 0
60#endif
61#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR
62#define ZDIR "."
63#define SUBDIRS 1
64#endif
65#if SPOOLDIR_ULTRIX
66#define ZDIR "sys"
67#define SUBDIRS 1
68#endif
69#if SPOOLDIR_BSD43
70#define ZDIR "X."
71#define SUBDIRS 0
72#endif
73
74/* Static variables for the execute file scan.  */
75
76static DIR *qSxqt_topdir;
77#if ! SUBDIRS
78static const char *zSdir;
79#else /* SUBDIRS */
80static boolean fSone_dir;
81static char *zSdir;
82static DIR *qSxqt_dir;
83static char *zSsystem;
84#endif /* SUBDIRS */
85
86/* Initialize the scan for execute files.  The function
87   usysdep_get_xqt_free will clear the data out when we are done with
88   the system.  This returns FALSE on error.  */
89
90/*ARGSUSED*/
91boolean
92fsysdep_get_xqt_init (zsystem)
93     const char *zsystem;
94{
95  usysdep_get_xqt_free ((const char *) NULL);
96
97#if SUBDIRS
98  if (zsystem != NULL)
99    {
100#if SPOOLDIR_HDB || SPOOLDIR_SVR4
101      zSdir = zbufcpy (zsystem);
102#endif
103#if SPOOLDIR_ULTRIX
104      zSdir = zsappend3 ("sys", zsystem, "X.");
105#endif
106#if SPOOLDIR_TAYLOR
107      zSdir = zsysdep_in_dir (zsystem, "X.");
108#endif
109
110      qSxqt_dir = opendir ((char *) zSdir);
111      if (qSxqt_dir != NULL)
112	{
113	  qSxqt_topdir = qSxqt_dir;
114	  fSone_dir = TRUE;
115	  zSsystem = zbufcpy (zsystem);
116	  return TRUE;
117	}
118    }
119
120  fSone_dir = FALSE;
121#endif
122
123  qSxqt_topdir = opendir ((char *) ZDIR);
124  if (qSxqt_topdir == NULL)
125    {
126      if (errno == ENOENT)
127	return TRUE;
128      ulog (LOG_ERROR, "opendir (%s): %s", ZDIR, strerror (errno));
129      return FALSE;
130    }
131
132  return TRUE;
133}
134
135/* Return the name of the next execute file to read and process.  If
136   this returns NULL, *pferr must be checked.  If will be TRUE on
137   error, FALSE if there are no more files.  On a successful return
138   *pzsystem will be set to the system for which the execute file was
139   created.  */
140
141/*ARGSUSED*/
142char *
143zsysdep_get_xqt (zsystem, pzsystem, pferr)
144     const char *zsystem ATTRIBUTE_UNUSED;
145     char **pzsystem;
146     boolean *pferr;
147{
148  *pferr = FALSE;
149
150  if (qSxqt_topdir == NULL)
151    return NULL;
152
153  /* This loop continues until we find a file.  */
154  while (TRUE)
155    {
156      DIR *qdir;
157      struct dirent *q;
158
159#if ! SUBDIRS
160      zSdir = ZDIR;
161      qdir = qSxqt_topdir;
162#else /* SUBDIRS */
163      /* This loop continues until we find a subdirectory to read.  */
164      while (qSxqt_dir == NULL)
165	{
166	  struct dirent *qtop;
167
168	  qtop = readdir (qSxqt_topdir);
169	  if (qtop == NULL)
170	    {
171	      (void) closedir (qSxqt_topdir);
172	      qSxqt_topdir = NULL;
173	      return NULL;
174	    }
175
176	  /* No system name may start with a dot This allows us to
177	     quickly skip impossible directories.  */
178	  if (qtop->d_name[0] == '.')
179	    continue;
180
181	  DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
182			  "zsysdep_get_xqt: Found %s in top directory",
183			  qtop->d_name);
184
185	  ubuffree (zSdir);
186
187#if SPOOLDIR_HDB || SPOOLDIR_SVR4
188	  zSdir = zbufcpy (qtop->d_name);
189#endif
190#if SPOOLDIR_ULTRIX
191	  zSdir = zsappend3 ("sys", qtop->d_name, "X.");
192#endif
193#if SPOOLDIR_TAYLOR
194	  zSdir = zsysdep_in_dir (qtop->d_name, "X.");
195#endif
196
197	  ubuffree (zSsystem);
198	  zSsystem = zbufcpy (qtop->d_name);
199
200	  qSxqt_dir = opendir (zSdir);
201
202	  if (qSxqt_dir == NULL
203	      && errno != ENOTDIR
204	      && errno != ENOENT)
205	    ulog (LOG_ERROR, "opendir (%s): %s", zSdir, strerror (errno));
206	}
207
208      qdir = qSxqt_dir;
209#endif /* SUBDIRS */
210
211      q = readdir (qdir);
212
213#if DEBUG > 1
214      if (q != NULL)
215	DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
216			"zsysdep_get_xqt: Found %s in subdirectory %s",
217			q->d_name, zSdir);
218#endif
219
220      /* If we've found an execute file, return it.  We have to get
221	 the system name, which is easy for HDB or TAYLOR.  For other
222	 spool directory schemes, we have to pull it out of the X.
223	 file name; this would be insecure, except that zsfind_file
224	 clobbers the file name to include the real system name.  */
225      if (q != NULL
226	  && q->d_name[0] == 'X'
227	  && q->d_name[1] == '.')
228	{
229	  char *zret;
230
231#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR
232	  *pzsystem = zbufcpy (zSsystem);
233#else
234	  {
235	    size_t clen;
236
237	    clen = strlen (q->d_name) - 7;
238	    *pzsystem = zbufalc (clen + 1);
239	    memcpy (*pzsystem, q->d_name + 2, clen);
240	    (*pzsystem)[clen] = '\0';
241	  }
242#endif
243
244	  zret = zsysdep_in_dir (zSdir, q->d_name);
245#if DEBUG > 1
246	  DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
247			  "zsysdep_get_xqt: Returning %s (system %s)",
248			  zret, *pzsystem);
249#endif
250	  return zret;
251	}
252
253      /* If we've reached the end of the directory, then if we are
254	 using subdirectories loop around to read the next one,
255	 otherwise we are finished.  */
256      if (q == NULL)
257	{
258	  (void) closedir (qdir);
259
260#if SUBDIRS
261	  qSxqt_dir = NULL;
262	  if (! fSone_dir)
263	    continue;
264#endif
265
266	  qSxqt_topdir = NULL;
267	  return NULL;
268	}
269    }
270}
271
272/* Free up the results of an execute file scan, when we're done with
273   this system.  */
274
275/*ARGSUSED*/
276void
277usysdep_get_xqt_free (zsystem)
278     const char *zsystem ATTRIBUTE_UNUSED;
279{
280  if (qSxqt_topdir != NULL)
281    {
282      (void) closedir (qSxqt_topdir);
283      qSxqt_topdir = NULL;
284    }
285#if SUBDIRS
286  if (qSxqt_dir != NULL)
287    {
288      (void) closedir (qSxqt_dir);
289      qSxqt_dir = NULL;
290    }
291  ubuffree (zSdir);
292  zSdir = NULL;
293  ubuffree (zSsystem);
294  zSsystem = NULL;
295  fSone_dir = FALSE;
296#endif
297}
298