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