1 /* vport.c
2    Find a port in the V2 configuration files.
3 
4    Copyright (C) 1992, 1993, 2002 Ian Lance Taylor
5 
6    This file is part of the Taylor UUCP uuconf library.
7 
8    This library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Library General Public License
10    as published by the Free Software Foundation; either version 2 of
11    the License, or (at your option) any later version.
12 
13    This library 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    Library General Public License for more details.
17 
18    You should have received a copy of the GNU Library General Public
19    License along with this library; 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 "uucnfi.h"
26 
27 #if USE_RCS_ID
28 const char _uuconf_vport_rcsid[] = "$FreeBSD$";
29 #endif
30 
31 #include <errno.h>
32 #include <ctype.h>
33 
34 /* Find a port in the V2 configuration files by name, baud rate, and
35    special purpose function.  */
36 
37 int
uuconf_v2_find_port(pglobal,zname,ibaud,ihighbaud,pifn,pinfo,qport)38 uuconf_v2_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport)
39      pointer pglobal;
40      const char *zname;
41      long ibaud;
42      long ihighbaud ATTRIBUTE_UNUSED;
43      int (*pifn) P((struct uuconf_port *, pointer));
44      pointer pinfo;
45      struct uuconf_port *qport;
46 {
47   struct sglobal *qglobal = (struct sglobal *) pglobal;
48   FILE *e;
49   char *zline;
50   size_t cline;
51   char **pzsplit;
52   size_t csplit;
53   int iret;
54   int cchars;
55 
56   e = fopen (qglobal->qprocess->zv2devices, "r");
57   if (e == NULL)
58     {
59       if (FNO_SUCH_FILE ())
60 	return UUCONF_NOT_FOUND;
61       qglobal->ierrno = errno;
62       qglobal->zfilename = qglobal->qprocess->zv2devices;
63       return (UUCONF_FOPEN_FAILED
64 	      | UUCONF_ERROR_ERRNO
65 	      | UUCONF_ERROR_FILENAME);
66     }
67 
68   zline = NULL;
69   cline = 0;
70   pzsplit = NULL;
71   csplit = 0;
72 
73   iret = UUCONF_NOT_FOUND;
74 
75   qglobal->ilineno = 0;
76 
77   while ((cchars = getline (&zline, &cline, e)) > 0)
78     {
79       int ctoks;
80       char *zend;
81       long ilow, ihigh;
82       pointer pblock;
83 
84       ++qglobal->ilineno;
85 
86       iret = UUCONF_NOT_FOUND;
87 
88       --cchars;
89       if (zline[cchars] == '\n')
90 	zline[cchars] = '\0';
91       zline[strcspn (zline, "#")] = '\0';
92 
93       ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit);
94       if (ctoks < 0)
95 	{
96 	  qglobal->ierrno = errno;
97 	  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
98 	  break;
99 	}
100 
101       /* An entry in L-devices is
102 
103 	 type device dial-device baud dialer
104 
105 	 The type (normally "ACU") is treated as the name.  */
106 
107       /* If there aren't enough entries, ignore the line; this
108 	 should probably do something more useful.  */
109       if (ctoks < 4)
110 	continue;
111 
112       /* Make sure the name matches any argument.  */
113       if (zname != NULL
114 	  && strcmp (pzsplit[0], zname) != 0)
115 	continue;
116 
117       /* Get the baud rate.  */
118       ilow = strtol (pzsplit[3], &zend, 10);
119       if (*zend == '-')
120 	ihigh = strtol (zend + 1, (char **) NULL, 10);
121       else
122 	ihigh = ilow;
123 
124       /* Make sure the baud rate matches any argument.  */
125       if (ibaud != 0
126 	  && ilow != 0
127 	  && (ilow > ibaud || ihigh < ibaud))
128 	continue;
129 
130       /* Now we must construct the port information, so that we can
131 	 pass it to pifn.  The port type is determined by it's name,
132 	 unfortunately.  The name "DIR" is used for a direct port, and
133 	 anything else for a modem port.  */
134       pblock = NULL;
135       _uuconf_uclear_port (qport);
136       qport->uuconf_zname = pzsplit[0];
137       if (strcmp (pzsplit[0], "DIR") == 0)
138 	{
139 	  qport->uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
140 	  qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = pzsplit[1];
141 	  qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = ilow;
142 	  qport->uuconf_u.uuconf_sdirect.uuconf_fcarrier = FALSE;
143 	  qport->uuconf_u.uuconf_sdirect.uuconf_fhardflow = TRUE;
144 	}
145       else
146 	{
147 	  qport->uuconf_ttype = UUCONF_PORTTYPE_MODEM;
148 	  qport->uuconf_u.uuconf_smodem.uuconf_zdevice = pzsplit[1];
149 	  if (strcmp (pzsplit[2], "-") != 0)
150 	    qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = pzsplit[2];
151 	  else
152 	    qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL;
153 	  if (ilow == ihigh)
154 	    {
155 	      qport->uuconf_u.uuconf_smodem.uuconf_ibaud = ilow;
156 	      qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L;
157 	      qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L;
158 	    }
159 	  else
160 	    {
161 	      qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L;
162 	      qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = ilow;
163 	      qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = ihigh;
164 	    }
165 	  qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE;
166 	  qport->uuconf_u.uuconf_smodem.uuconf_fhardflow = TRUE;
167 	  if (ctoks < 5)
168 	    qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL;
169 	  else
170 	    {
171 	      size_t c;
172 	      char **pzd;
173 
174 	      /* We support dialer/token pairs, although normal V2
175 		 doesn't.  */
176 	      pblock = uuconf_malloc_block ();
177 	      if (pblock == NULL)
178 		{
179 		  qglobal->ierrno = errno;
180 		  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
181 		  break;
182 		}
183 	      c = (ctoks - 4) * sizeof (char *);
184 	      pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *));
185 	      if (pzd == NULL)
186 		{
187 		  qglobal->ierrno = errno;
188 		  uuconf_free_block (pblock);
189 		  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
190 		  break;
191 		}
192 	      memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c);
193 	      pzd[ctoks - 4] = NULL;
194 
195 	      qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = pzd;
196 	    }
197 	  qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL;
198 	}
199 
200       if (pifn != NULL)
201 	{
202 	  iret = (*pifn) (qport, pinfo);
203 	  if (iret != UUCONF_SUCCESS)
204 	    {
205 	      if (pblock != NULL)
206 		uuconf_free_block (pblock);
207 	      if (iret != UUCONF_NOT_FOUND)
208 		break;
209 	      continue;
210 	    }
211 	}
212 
213       /* This is the port we want.  */
214       if (pblock == NULL)
215 	{
216 	  pblock = uuconf_malloc_block ();
217 	  if (pblock == NULL)
218 	    {
219 	      qglobal->ierrno = errno;
220 	      iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
221 	      break;
222 	    }
223 	}
224 
225       if (uuconf_add_block (pblock, zline) != 0)
226 	{
227 	  qglobal->ierrno = errno;
228 	  uuconf_free_block (pblock);
229 	  iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
230 	  break;
231 	}
232       zline = NULL;
233 
234       qport->uuconf_palloc = pblock;
235 
236       break;
237     }
238 
239   (void) fclose (e);
240 
241   if (zline != NULL)
242     free ((pointer) zline);
243   if (pzsplit != NULL)
244     free ((pointer) pzsplit);
245 
246   if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND)
247     {
248       qglobal->zfilename = qglobal->qprocess->zv2devices;
249       iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO;
250     }
251 
252   return iret;
253 }
254