1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <ctype.h>
39 #include <string.h>
40 #include <termio.h>
41 #include <sys/stat.h>
42 #include <signal.h>
43 #include <stdarg.h>
44
45 #include "tmstruct.h"
46 #include "ttymon.h"
47
48 static int nflg = 0; /* -n seen */
49 static int iflg = 0; /* -i seen */
50 static int fflg = 0; /* -f seen */
51 static int lflg = 0; /* -l seen */
52
53 struct Gdef Gdef[MAXDEFS]; /* array to hold entries in /etc/ttydefs */
54 int Ndefs = 0; /* highest index to Gdef that was used */
55 static struct Gdef DEFAULT = { /* default terminal settings */
56 "default",
57 "9600",
58 "9600 sane",
59 0,
60 /*
61 * next label is set to 4800 so we can start searching ttydefs.
62 * if 4800 is not in ttydefs, we will loop back to use DEFAULT
63 */
64 "4800"
65 };
66
67
68 static void usage();
69 static void check_ref();
70 static void add_entry();
71 static void remove_entry();
72 static int copy_file();
73 static int verify();
74 static FILE *open_temp();
75 extern void read_ttydefs();
76 extern int check_version();
77 extern int find_label();
78
79 /*
80 * sttydefs - add, remove or check entries in /etc/ttydefs
81 *
82 * Usage: sttydefs -a ttylabel [-n nextlabel] [-i initail-flags]
83 * [-f final-flags] [-b]
84 * sttydefs -r ttylabel
85 * sttydefs -l [ttylabel]
86 *
87 */
88
89 int
main(int argc,char * argv[])90 main(int argc, char *argv[])
91 {
92 int c; /* option letter */
93 int errflg = 0; /* error indicator */
94 int aflg = 0; /* -a seen */
95 int bflg = 0; /* -b seen */
96 int ret;
97 #ifdef __STDC__
98 const
99 #endif
100 char *argtmp;
101 char *nextlabel;
102 struct Gdef ttydef, *ptr;
103
104 extern char *optarg;
105 extern int optind;
106
107 if (argc == 1)
108 usage();
109
110 /* Initialize ttydef structure */
111 memset (&ttydef, 0, sizeof(ttydef));
112
113 ptr = &ttydef;
114 while ((c = getopt(argc, argv, "a:n:i:f:br:l")) != -1) {
115 switch (c) {
116 case 'a':
117 aflg = TRUE;
118 ptr->g_id = optarg;
119 break;
120 case 'n':
121 nflg = TRUE;
122 ptr->g_nextid = optarg;
123 break;
124 case 'i':
125 iflg = TRUE;
126 ptr->g_iflags = optarg;
127 break;
128 case 'f':
129 fflg = TRUE;
130 ptr->g_fflags = optarg;
131 break;
132 case 'b':
133 bflg = TRUE;
134 ptr->g_autobaud |= A_FLAG;
135 break;
136 case 'r':
137 if ((argc > 3) || (optind < argc))
138 usage();
139 remove_entry(optarg);
140 break;
141 case 'l':
142 lflg = TRUE;
143 if (argc > 3)
144 usage();
145 if ((ret = check_version(TTYDEFS_VERS, TTYDEFS)) != 0) {
146 if (ret != 2) {
147 (void)fprintf(stderr, "%s version number is incorrect or missing.\n",TTYDEFS);
148 exit(1);
149 }
150 (void)fprintf(stderr, "sttydefs: can't open %s.\n",TTYDEFS);
151 exit(1);
152 }
153 if (argv[optind] == NULL) {
154 read_ttydefs(NULL,TRUE);
155 printf("\n");
156 check_ref();
157 }
158 else {
159 if (argc == 3) { /* -l ttylabel */
160 if (verify(argv[optind],0) != 0) {
161 errflg++;
162 break;
163 }
164 argtmp = argv[optind];
165 }
166 else { /* -lttylabel */
167 argtmp = argv[optind]+2;
168 }
169 read_ttydefs(argtmp,TRUE);
170 if (Ndefs == 0) {
171 (void)fprintf(stderr,
172 "ttylabel <%s> not found.\n", argtmp);
173 exit(1);
174 }
175 nextlabel = Gdef[--Ndefs].g_nextid;
176 Ndefs = 0;
177 read_ttydefs(nextlabel,FALSE);
178 if (Ndefs == 0) {
179 (void)printf("\nWarning -- nextlabel <%s> of <%s> does not reference any existing ttylabel.\n",
180 nextlabel, argtmp);
181 }
182 }
183 exit(0);
184 break; /*NOTREACHED*/
185 case '?':
186 errflg++;
187 break;
188 } /* end switch */
189 if (errflg)
190 usage();
191 } /* end while */
192 if (optind < argc)
193 usage();
194
195 if (aflg) {
196 add_entry(ptr); /* never return */
197 }
198 if ((iflg) || (fflg) || (bflg) || (nflg))
199 usage();
200 return (0);
201 }
202
203 /*
204 * verify - to check if arg is valid
205 * - i.e. arg cannot start with '-' and
206 * arg must not longer than maxarglen
207 * - return 0 if ok. Otherwise return -1
208 */
209 static int
verify(arg,maxarglen)210 verify(arg,maxarglen)
211 char *arg;
212 int maxarglen;
213 {
214 if (*arg == '-') {
215 (void)fprintf(stderr, "Invalid argument -- %s.\n", arg);
216 return(-1);
217 }
218 if ((maxarglen) && ((int)strlen(arg) > maxarglen)) {
219 arg[maxarglen] = '\0';
220 (void)fprintf(stderr,"string too long, truncated to %s.\n",arg);
221 return(-1);
222 }
223 return(0);
224 }
225
226 /*
227 * usage - print out a usage message
228 */
229
230 static void
usage()231 usage()
232 {
233 (void)fprintf(stderr, "Usage:\tsttydefs -a ttylabel [-n nextlabel] [-i initial-flags]\n\t\t [-f final-flags] [-b]\n");
234 (void)fprintf(stderr, "\tsttydefs -r ttylabel\n");
235 (void)fprintf(stderr, "\tsttydefs -l [ttylabel]\n");
236 exit(2);
237 }
238
239 /*
240 * add_entry - add an entry to /etc/ttydefs
241 */
242
243 static void
add_entry(ttydef)244 add_entry(ttydef)
245 struct Gdef *ttydef;
246 {
247 FILE *fp;
248 int errflg = 0;
249 char tbuf[BUFSIZ], *tp;
250 int add_version = FALSE;
251 extern int check_flags();
252
253 if (getuid()) {
254 (void)fprintf(stderr, "User not privileged for operation.\n");
255 exit(1);
256 }
257 tp = tbuf;
258 *tp = '\0';
259 if ((fp = fopen(TTYDEFS, "r")) != NULL) {
260 if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) {
261 (void)fprintf(stderr,
262 "%s version number is incorrect or missing.\n",TTYDEFS);
263 exit(1);
264 }
265 if (find_label(fp,ttydef->g_id)) {
266 (void)fclose(fp);
267 (void)fprintf(stderr,
268 "Invalid request -- ttylabel <%s> already exists.\n",
269 ttydef->g_id);
270 exit(1);
271 }
272 (void)fclose(fp);
273 }
274 else {
275 add_version = TRUE;
276 }
277 if ((fp = fopen(TTYDEFS, "a+")) == NULL) {
278 (void) fprintf(stderr, "Could not open \"%s\": %s", TTYDEFS,
279 strerror(errno));
280 exit(1);
281 }
282
283 if (add_version) {
284 (void)fprintf(fp,"# VERSION=%d\n", TTYDEFS_VERS);
285 }
286
287
288 /* if optional fields are not provided, set to default */
289 if (!iflg)
290 ttydef->g_iflags = DEFAULT.g_iflags;
291 else
292 if (check_flags(ttydef->g_iflags) != 0 )
293 errflg++;
294 if (!fflg)
295 ttydef->g_fflags = DEFAULT.g_fflags;
296 else
297 if (check_flags(ttydef->g_fflags) != 0 )
298 errflg++;
299 if (errflg)
300 exit(1);
301
302 if (!nflg)
303 ttydef->g_nextid = ttydef->g_id;
304
305 if (ttydef->g_autobaud & A_FLAG) {
306 (void)fprintf(fp,"%s:%s:%s:A:%s\n", ttydef->g_id, ttydef->g_iflags,
307 ttydef->g_fflags, ttydef->g_nextid);
308 }
309 else {
310 (void)fprintf(fp,"%s:%s:%s::%s\n", ttydef->g_id, ttydef->g_iflags,
311 ttydef->g_fflags, ttydef->g_nextid);
312 }
313 (void)fclose(fp);
314 exit(0);
315 }
316
317 static void
remove_entry(ttylabel)318 remove_entry(ttylabel)
319 char *ttylabel;
320 {
321 FILE *tfp; /* file pointer for temp file */
322 int line; /* line number entry is on */
323 FILE *fp; /* scratch file pointer */
324 char *tname = "/etc/.ttydefs";
325
326 if (getuid()) {
327 (void)fprintf(stderr, "User not privileged for operation.\n");
328 exit(1);
329 }
330 fp = fopen(TTYDEFS, "r");
331 if (fp == NULL) {
332 (void) fprintf(stderr, "Could not open \"%s\": %s", TTYDEFS,
333 strerror(errno));
334 exit(1);
335 }
336 if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) {
337 (void)fprintf(stderr,
338 "%s version number is incorrect or missing.\n",TTYDEFS);
339 exit(1);
340 }
341 if ((line = find_label(fp, ttylabel)) == 0) {
342 (void)fprintf(stderr,
343 "Invalid request, ttylabel <%s> does not exist.\n", ttylabel);
344 exit(1);
345 }
346 tfp = open_temp(tname);
347 if (line != 1)
348 if (copy_file(fp, tfp, 1, line - 1)) {
349 (void)fprintf(stderr,"Error accessing temp file.\n");
350 exit(1);
351 }
352 if (copy_file(fp, tfp, line + 1, -1)) {
353 (void)fprintf(stderr,"Error accessing temp file.\n");
354 exit(1);
355 }
356 (void)fclose(fp);
357 if (fclose(tfp) == EOF) {
358 (void)unlink(tname);
359 (void)fprintf(stderr,"Error closing temp file.\n");
360 exit(1);
361 }
362 (void)unlink(TTYDEFS);
363 if (rename(tname, TTYDEFS) != 0 ) {
364 perror("Rename failed");
365 (void)unlink(tname);
366 exit(1);
367 }
368 exit(0);
369 }
370
371 /*
372 * open_temp - open up a temp file
373 *
374 * args: tname - temp file name
375 */
376
377 static FILE *
open_temp(tname)378 open_temp(tname)
379 char *tname;
380 {
381 FILE *fp; /* fp associated with tname */
382 struct sigaction sigact; /* for signal handling */
383
384 sigact.sa_flags = 0;
385 sigact.sa_handler = SIG_IGN;
386 (void) sigemptyset(&sigact.sa_mask);
387 (void) sigaddset(&sigact.sa_mask, SIGHUP);
388 (void) sigaddset(&sigact.sa_mask, SIGINT);
389 (void) sigaddset(&sigact.sa_mask, SIGQUIT);
390 (void) sigaction(SIGHUP, &sigact, NULL);
391 (void) sigaction(SIGINT, &sigact, NULL);
392 (void) sigaction(SIGQUIT, &sigact, NULL);
393 (void)umask(0333);
394 if (access(tname, 0) != -1) {
395 (void)fprintf(stderr,"tempfile busy; try again later.\n");
396 exit(1);
397 }
398 fp = fopen(tname, "w");
399 if (fp == NULL) {
400 perror("Cannot create tempfile");
401 exit(1);
402 }
403 return(fp);
404 }
405
406 /*
407 * copy_file - copy information from one file to another, return 0 on
408 * success, -1 on failure
409 *
410 * args: fp - source file's file pointer
411 * tfp - destination file's file pointer
412 * start - starting line number
413 * finish - ending line number (-1 indicates entire file)
414 */
415
416
417 static int
copy_file(fp,tfp,start,finish)418 copy_file(fp, tfp, start, finish)
419 FILE *fp;
420 FILE *tfp;
421 register int start;
422 register int finish;
423 {
424 register int i; /* loop variable */
425 char dummy[BUFSIZ]; /* scratch buffer */
426
427 /*
428 * always start from the beginning because line numbers are absolute
429 */
430
431 rewind(fp);
432
433 /*
434 * get to the starting point of interest
435 */
436
437 if (start != 1) {
438 for (i = 1; i < start; i++)
439 if (!fgets(dummy, BUFSIZ, fp))
440 return(-1);
441 }
442
443 /*
444 * copy as much as was requested
445 */
446
447 if (finish != -1) {
448 for (i = start; i <= finish; i++) {
449 if (!fgets(dummy, BUFSIZ, fp))
450 return(-1);
451 if (fputs(dummy, tfp) == EOF)
452 return(-1);
453 }
454 }
455 else {
456 for (;;) {
457 if (fgets(dummy, BUFSIZ, fp) == NULL) {
458 if (feof(fp))
459 break;
460 else
461 return(-1);
462 }
463 if (fputs(dummy, tfp) == EOF)
464 return(-1);
465 }
466 }
467 return(0);
468 }
469
470 /*
471 * check_ref - to check if nextlabel are referencing
472 * existing ttylabel
473 */
474 static void
check_ref()475 check_ref()
476 {
477 int i;
478 struct Gdef *np;
479 extern struct Gdef *find_def();
480 np = &Gdef[0];
481 for (i = 0; i < Ndefs; i++, np++) {
482 if (find_def(np->g_nextid) == NULL) {
483 (void)printf("Warning -- nextlabel <%s> of <%s> does not reference any existing ttylabel.\n",
484 np->g_nextid, np->g_id);
485 }
486 }
487 return;
488 }
489
490 /*
491 * log - print a message to stdout
492 */
493
494 void
log(const char * msg,...)495 log(const char *msg, ...)
496 {
497 va_list ap;
498 if (lflg) {
499 va_start(ap, msg);
500 (void) vprintf(msg, ap);
501 va_end(ap);
502 (void) printf("\n");
503 } else {
504 va_start(ap, msg);
505 (void) vfprintf(stderr, msg, ap);
506 va_end(ap);
507 (void) fprintf(stderr,"\n");
508 }
509 }
510