]> git.saurik.com Git - apple/network_cmds.git/blame - rtadvd.tproj/advcap.c
network_cmds-115.tar.gz
[apple/network_cmds.git] / rtadvd.tproj / advcap.c
CommitLineData
7ba0088d
A
1/* $KAME: advcap.c,v 1.5 2001/02/01 09:12:08 jinmei Exp $ */
2
3/*
4 * Copyright (c) 1983 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * $FreeBSD: src/usr.sbin/rtadvd/advcap.c,v 1.1.2.2 2001/07/03 11:02:13 ume Exp $
36 */
37
38/*
39 * remcap - routines for dealing with the remote host data base
40 *
41 * derived from termcap
42 */
43#include <sys/types.h>
44#include <sys/uio.h>
45#include <unistd.h>
46#include <fcntl.h>
47#include <ctype.h>
48#include <stdlib.h>
49#include <stdio.h>
50#include <syslog.h>
51#include <errno.h>
52#include <string.h>
53#include "pathnames.h"
54
55#ifndef BUFSIZ
56#define BUFSIZ 1024
57#endif
58#define MAXHOP 32 /* max number of tc= indirections */
59
60#define tgetent agetent
61#define tnchktc anchktc
62#define tnamatch anamatch
63#define tgetnum agetnum
64#define tgetflag agetflag
65#define tgetstr agetstr
66
67#if 0
68#define V_TERMCAP "REMOTE"
69#define V_TERM "HOST"
70#endif
71
72char *RM;
73
74/*
75 * termcap - routines for dealing with the terminal capability data base
76 *
77 * BUG: Should use a "last" pointer in tbuf, so that searching
78 * for capabilities alphabetically would not be a n**2/2
79 * process when large numbers of capabilities are given.
80 * Note: If we add a last pointer now we will screw up the
81 * tc capability. We really should compile termcap.
82 *
83 * Essentially all the work here is scanning and decoding escapes
84 * in string capabilities. We don't use stdio because the editor
85 * doesn't, and because living w/o it is not hard.
86 */
87
88static char *tbuf;
89static int hopcount; /* detect infinite loops in termcap, init 0 */
90
91static char *remotefile;
92
93extern char *conffile;
94
95int tgetent __P((char *, char *));
96int getent __P((char *, char *, char *));
97int tnchktc __P((void));
98int tnamatch __P((char *));
99static char *tskip __P((char *));
100long long tgetnum __P((char *));
101int tgetflag __P((char *));
102char *tgetstr __P((char *, char **));
103static char *tdecode __P((char *, char **));
104
105/*
106 * Get an entry for terminal name in buffer bp,
107 * from the termcap file. Parse is very rudimentary;
108 * we just notice escaped newlines.
109 */
110int
111tgetent(bp, name)
112 char *bp, *name;
113{
114 char *cp;
115
116 remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF;
117 return (getent(bp, name, cp));
118}
119
120int
121getent(bp, name, cp)
122 char *bp, *name, *cp;
123{
124 register int c;
125 register int i = 0, cnt = 0;
126 char ibuf[BUFSIZ];
127 int tf;
128
129 tbuf = bp;
130 tf = 0;
131 /*
132 * TERMCAP can have one of two things in it. It can be the
133 * name of a file to use instead of /etc/termcap. In this
134 * case it better start with a "/". Or it can be an entry to
135 * use so we don't have to read the file. In this case it
136 * has to already have the newlines crunched out.
137 */
138 if (cp && *cp) {
139 tf = open(RM = cp, O_RDONLY);
140 }
141 if (tf < 0) {
142 syslog(LOG_INFO,
143 "<%s> open: %s", __FUNCTION__, strerror(errno));
144 return (-2);
145 }
146 for (;;) {
147 cp = bp;
148 for (;;) {
149 if (i == cnt) {
150 cnt = read(tf, ibuf, BUFSIZ);
151 if (cnt <= 0) {
152 close(tf);
153 return (0);
154 }
155 i = 0;
156 }
157 c = ibuf[i++];
158 if (c == '\n') {
159 if (cp > bp && cp[-1] == '\\') {
160 cp--;
161 continue;
162 }
163 break;
164 }
165 if (cp >= bp+BUFSIZ) {
166 write(2,"Remcap entry too long\n", 23);
167 break;
168 } else
169 *cp++ = c;
170 }
171 *cp = 0;
172
173 /*
174 * The real work for the match.
175 */
176 if (tnamatch(name)) {
177 close(tf);
178 return (tnchktc());
179 }
180 }
181}
182
183/*
184 * tnchktc: check the last entry, see if it's tc=xxx. If so,
185 * recursively find xxx and append that entry (minus the names)
186 * to take the place of the tc=xxx entry. This allows termcap
187 * entries to say "like an HP2621 but doesn't turn on the labels".
188 * Note that this works because of the left to right scan.
189 */
190int
191tnchktc()
192{
193 register char *p, *q;
194 char tcname[16]; /* name of similar terminal */
195 char tcbuf[BUFSIZ];
196 char *holdtbuf = tbuf;
197 int l;
198
199 p = tbuf + strlen(tbuf) - 2; /* before the last colon */
200 while (*--p != ':')
201 if (p<tbuf) {
202 write(2, "Bad remcap entry\n", 18);
203 return (0);
204 }
205 p++;
206 /* p now points to beginning of last field */
207 if (p[0] != 't' || p[1] != 'c')
208 return (1);
209 strcpy(tcname, p+3);
210 q = tcname;
211 while (*q && *q != ':')
212 q++;
213 *q = 0;
214 if (++hopcount > MAXHOP) {
215 write(2, "Infinite tc= loop\n", 18);
216 return (0);
217 }
218 if (getent(tcbuf, tcname, remotefile) != 1) {
219 return (0);
220 }
221 for (q = tcbuf; *q++ != ':'; )
222 ;
223 l = p - holdtbuf + strlen(q);
224 if (l > BUFSIZ) {
225 write(2, "Remcap entry too long\n", 23);
226 q[BUFSIZ - (p-holdtbuf)] = 0;
227 }
228 strcpy(p, q);
229 tbuf = holdtbuf;
230 return (1);
231}
232
233/*
234 * Tnamatch deals with name matching. The first field of the termcap
235 * entry is a sequence of names separated by |'s, so we compare
236 * against each such name. The normal : terminator after the last
237 * name (before the first field) stops us.
238 */
239int
240tnamatch(np)
241 char *np;
242{
243 register char *Np, *Bp;
244
245 Bp = tbuf;
246 if (*Bp == '#')
247 return (0);
248 for (;;) {
249 for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
250 continue;
251 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
252 return (1);
253 while (*Bp && *Bp != ':' && *Bp != '|')
254 Bp++;
255 if (*Bp == 0 || *Bp == ':')
256 return (0);
257 Bp++;
258 }
259}
260
261/*
262 * Skip to the next field. Notice that this is very dumb, not
263 * knowing about \: escapes or any such. If necessary, :'s can be put
264 * into the termcap file in octal.
265 */
266static char *
267tskip(bp)
268 register char *bp;
269{
270 int dquote;
271
272 dquote = 0;
273 while (*bp) {
274 switch (*bp) {
275 case ':':
276 if (!dquote)
277 goto breakbreak;
278 else
279 bp++;
280 break;
281 case '\\':
282 bp++;
283 if (isdigit(*bp)) {
284 while (isdigit(*bp++))
285 ;
286 } else
287 bp++;
288 case '"':
289 dquote = (dquote ? 1 : 0);
290 bp++;
291 break;
292 default:
293 bp++;
294 break;
295 }
296 }
297breakbreak:
298 if (*bp == ':')
299 bp++;
300 return (bp);
301}
302
303/*
304 * Return the (numeric) option id.
305 * Numeric options look like
306 * li#80
307 * i.e. the option string is separated from the numeric value by
308 * a # character. If the option is not found we return -1.
309 * Note that we handle octal numbers beginning with 0.
310 */
311long long
312tgetnum(id)
313 char *id;
314{
315 register long long i;
316 register int base;
317 register char *bp = tbuf;
318
319 for (;;) {
320 bp = tskip(bp);
321 if (*bp == 0)
322 return (-1);
323 if (strncmp(bp, id, strlen(id)) != 0)
324 continue;
325 bp += strlen(id);
326 if (*bp == '@')
327 return (-1);
328 if (*bp != '#')
329 continue;
330 bp++;
331 base = 10;
332 if (*bp == '0')
333 base = 8;
334 i = 0;
335 while (isdigit(*bp))
336 i *= base, i += *bp++ - '0';
337 return (i);
338 }
339}
340
341/*
342 * Handle a flag option.
343 * Flag options are given "naked", i.e. followed by a : or the end
344 * of the buffer. Return 1 if we find the option, or 0 if it is
345 * not given.
346 */
347int
348tgetflag(id)
349 char *id;
350{
351 register char *bp = tbuf;
352
353 for (;;) {
354 bp = tskip(bp);
355 if (!*bp)
356 return (0);
357 if (strncmp(bp, id, strlen(id)) == 0) {
358 bp += strlen(id);
359 if (!*bp || *bp == ':')
360 return (1);
361 else if (*bp == '@')
362 return (0);
363 }
364 }
365}
366
367/*
368 * Get a string valued option.
369 * These are given as
370 * cl=^Z
371 * Much decoding is done on the strings, and the strings are
372 * placed in area, which is a ref parameter which is updated.
373 * No checking on area overflow.
374 */
375char *
376tgetstr(id, area)
377 char *id, **area;
378{
379 register char *bp = tbuf;
380
381 for (;;) {
382 bp = tskip(bp);
383 if (!*bp)
384 return (0);
385 if (strncmp(bp, id, strlen(id)) != 0)
386 continue;
387 bp += strlen(id);
388 if (*bp == '@')
389 return (0);
390 if (*bp != '=')
391 continue;
392 bp++;
393 return (tdecode(bp, area));
394 }
395}
396
397/*
398 * Tdecode does the grung work to decode the
399 * string capability escapes.
400 */
401static char *
402tdecode(str, area)
403 register char *str;
404 char **area;
405{
406 register char *cp;
407 register int c;
408 register char *dp;
409 int i;
410 char term;
411
412 term = ':';
413 cp = *area;
414again:
415 if (*str == '"') {
416 term = '"';
417 str++;
418 }
419 while ((c = *str++) && c != term) {
420 switch (c) {
421
422 case '^':
423 c = *str++ & 037;
424 break;
425
426 case '\\':
427 dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\"";
428 c = *str++;
429nextc:
430 if (*dp++ == c) {
431 c = *dp++;
432 break;
433 }
434 dp++;
435 if (*dp)
436 goto nextc;
437 if (isdigit(c)) {
438 c -= '0', i = 2;
439 do
440 c <<= 3, c |= *str++ - '0';
441 while (--i && isdigit(*str));
442 }
443 break;
444 }
445 *cp++ = c;
446 }
447 if (c == term && term != ':') {
448 term = ':';
449 goto again;
450 }
451 *cp++ = 0;
452 str = *area;
453 *area = cp;
454 return (str);
455}