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