4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
41 #include <sys/param.h>
44 #include <sys/types.h>
45 #include <sys/console.h>
50 static char devbuf
[BUFSIZ
];
53 static int parse_args();
54 static void ttymon_options();
55 static void getty_options();
57 static char *find_ttyname();
59 extern void tmchild();
62 void revokedevaccess(char *, uid_t
, gid_t
, mode_t
);
63 /* cannot include libdevinfo.h */
64 extern int di_devperm_logout(const char *);
67 * ttymon_express - This is call when ttymon is invoked with args
69 * - This special version of ttymon will monitor
71 * - It is intended to be used when some process
72 * wants to have a login session on the fly
75 ttymon_express(int argc
, char **argv
)
78 struct sigaction sigact
;
80 extern void open_device();
81 extern void read_ttydefs();
82 extern int checkut_line();
85 extern void opendebug();
93 sigact
.sa_handler
= SIG_IGN
;
94 (void) sigemptyset(&sigact
.sa_mask
);
95 (void) sigaction(SIGINT
, &sigact
, NULL
);
97 if ((pmtab
= ALLOC_PMTAB
) == PNULL
) {
98 log("ttymon_express: ALLOC_PMTAB failed");
102 if (parse_args(argc
, argv
, pmtab
) != 0) {
103 log("ttymon_express: parse_args failed");
107 read_ttydefs(NULL
, FALSE
);
109 if ((pmtab
->p_device
!= NULL
) && (*(pmtab
->p_device
) != '\0'))
110 while (checkut_line(pmtab
->p_device
))
113 if ((pmtab
->p_device
== NULL
) || (*(pmtab
->p_device
) == '\0')) {
114 devname
= find_ttyname(0);
115 if ((devname
== NULL
) || (*devname
== '\0')) {
116 log("ttyname cannot find the device on fd 0");
119 pmtab
->p_device
= devname
;
121 debug("ttymon_express: devname = %s", devname
);
124 * become session leader
125 * fd 0 is closed and reopened just to make sure
126 * controlling tty is set up right
130 revokedevaccess(pmtab
->p_device
, 0, 0, 0);
131 if (open(pmtab
->p_device
, O_RDWR
) < 0) {
132 log("open %s failed: %s", pmtab
->p_device
,
136 if ((pmtab
->p_modules
!= NULL
) &&
137 (*(pmtab
->p_modules
) != '\0')) {
138 if (push_linedisc(0, pmtab
->p_modules
,
139 pmtab
->p_device
) == -1)
142 if (initial_termio(0, pmtab
) == -1)
144 di_devperm_logout((const char *)pmtab
->p_device
);
150 if (Retry
) /* open failed */
154 exit(1); /*NOTREACHED*/
158 * parse_arg - parse cmd line arguments
161 parse_args(int argc
, char **argv
, struct pmtab
*pmtab
)
163 static char p_server
[] = "/usr/bin/login";
164 extern char *lastname();
165 extern void getty_account();
166 static char termbuf
[MAX_TERM_TYPE_LEN
];
167 static struct cons_getterm cnterm
= {sizeof (termbuf
), termbuf
};
169 /* initialize fields to some default first */
172 pmtab
->p_identity
= "root";
173 pmtab
->p_res1
= "reserved";
174 pmtab
->p_res2
= "reserved";
175 pmtab
->p_res3
= "reserved";
179 pmtab
->p_ttyflags
= 0;
181 pmtab
->p_server
= p_server
;
182 pmtab
->p_timeout
= 0;
183 pmtab
->p_modules
= "";
184 pmtab
->p_prompt
= "login: ";
186 pmtab
->p_termtype
= "";
187 pmtab
->p_device
= "";
188 pmtab
->p_status
= GETTY
;
189 if (strcmp(lastname(argv
[0]), "getty") == 0) {
190 pmtab
->p_ttylabel
= "300";
191 getty_options(argc
, argv
, pmtab
);
195 pmtab
->p_ttylabel
= "9600";
196 ttymon_options(argc
, argv
, pmtab
);
199 * The following code is only reached if -g was specified.
200 * It attempts to determine a suitable terminal type for
201 * the console login process.
203 * If -d /dev/console also specified, we send an ioctl
204 * to the console device to query the TERM type.
206 * If any of the tests, system calls, or ioctls fail
207 * then pmtab->p_termtype retains its default value
208 * of "". otherwise it is set to a term type value
211 if ((strlen(pmtab
->p_termtype
) == 0) &&
212 (strcmp(pmtab
->p_device
, "/dev/console") == 0) &&
213 ((cn_fd
= open("/dev/console", O_RDONLY
)) != -1)) {
215 if (ioctl(cn_fd
, CONS_GETTERM
, &cnterm
) != -1)
216 pmtab
->p_termtype
= cnterm
.cn_term_type
;
221 if ((pmtab
->p_device
!= NULL
) && (*(pmtab
->p_device
) != '\0'))
222 getty_account(pmtab
->p_device
); /* utmp accounting */
228 * ttymon_options - scan and check args for ttymon express
232 ttymon_options(int argc
, char **argv
, struct pmtab
*pmtab
)
234 int c
; /* option letter */
236 int gflag
= 0; /* -g seen */
242 extern void copystr();
243 extern char *strsave();
244 extern char *getword();
246 while ((c
= getopt(argc
, argv
, "T:gd:ht:p:m:l:")) != -1) {
252 pmtab
->p_device
= optarg
;
255 pmtab
->p_ttyflags
&= ~H_FLAG
;
259 pmtab
->p_termtype
= optarg
;
263 * pmtab->p_ttyflags |= B_FLAG;
264 * pmtab->p_ttyflags |= R_FLAG;
270 if (!isdigit(*optarg
++)) {
271 log("Invalid argument for "
272 "\"-t\" -- number expected.");
276 pmtab
->p_timeout
= atoi(timeout
);
279 copystr(tbuf
, optarg
);
280 pmtab
->p_prompt
= strsave(getword(tbuf
, &size
, TRUE
));
283 pmtab
->p_modules
= optarg
;
284 if (vml(pmtab
->p_modules
) != 0)
288 pmtab
->p_ttylabel
= optarg
;
292 break; /*NOTREACHED*/
303 * usage - print out a usage message
309 char *umsg
= "Usage: ttymon\n ttymon -g [-h] [-d device] "
310 "[-l ttylabel] [-t timeout] [-p prompt] [-m modules]\n";
312 if (isatty(STDERR_FILENO
))
313 (void) fprintf(stderr
, "%s", umsg
);
320 * getty_options - this is cut from getty.c
321 * - it scan getty cmd args
322 * - modification is made to stuff args in pmtab
325 getty_options(argc
, argv
, pmtab
)
333 * the pre-4.0 getty's hang_up_line() is a no-op.
334 * For compatibility, H_FLAG cannot be set for this "getty".
336 pmtab
->p_ttyflags
&= ~(H_FLAG
);
338 while (--argc
&& **++argv
== '-') {
339 for (ptr
= *argv
+ 1; *ptr
; ptr
++)
344 if (isdigit(*++ptr
)) {
345 (void) sscanf(ptr
, "%d", &(pmtab
->p_timeout
));
346 while (isdigit(*++ptr
));
349 if (isdigit(*(ptr
= *++argv
)))
350 (void) sscanf(ptr
, "%d",
351 &(pmtab
->p_timeout
));
353 log("getty: timeout argument <%s> "
361 log("Use \"sttydefs -l\" to check /etc/ttydefs.");
369 log("getty: no terminal line specified.");
372 (void) strcat(devbuf
, "/dev/");
373 (void) strcat(devbuf
, *argv
);
374 pmtab
->p_device
= devbuf
;
378 pmtab
->p_ttylabel
= *++argv
;
382 * every thing after this will be ignored
383 * i.e. termtype and linedisc are ignored
388 * find_ttyname(fd) - find the name of device associated with fd.
389 * - it first tries utmpx to see if an entry exists
390 * - with my pid and ut_line is defined. If ut_line
391 * - is defined, it will see if the major and minor
392 * - number of fd and devname from utmpx match.
393 * - If utmpx search fails, ttyname(fd) will be called.
401 static struct stat statf
, statu
;
402 static char buf
[BUFSIZ
];
406 while ((u
= getutxent()) != NULL
) {
407 if (u
->ut_pid
== ownpid
) {
408 if (strlen(u
->ut_line
) != 0) {
409 if (*(u
->ut_line
) != '/') {
410 (void) strcpy(buf
, "/dev/");
411 (void) strncat(buf
, u
->ut_line
,
412 sizeof (u
->ut_line
));
414 (void) strncat(buf
, u
->ut_line
,
415 sizeof (u
->ut_line
));
425 (fstat(fd
, &statf
) == 0) &&
426 (stat(buf
, &statu
) == 0) &&
427 (statf
.st_dev
== statu
.st_dev
) &&
428 (statf
.st_rdev
== statu
.st_rdev
)) {
430 debug("ttymon_express: find device name from utmpx.");
435 debug("ttymon_express: calling ttyname to find device name.");
437 return (ttyname(fd
));
442 * Revoke all access to a device node and make sure that there are
443 * no interposed streams devices attached. Must be called before a
444 * device is actually opened.
445 * When fdetach is called, the underlying device node is revealed; it
446 * will have the previous owner and that owner can re-attach; so we
447 * retry until we win.
448 * Ignore non-existent devices.
451 revokedevaccess(char *dev
, uid_t uid
, gid_t gid
, mode_t mode
)
454 if (chown(dev
, uid
, gid
) == -1)
456 } while (fdetach(dev
) == 0);
460 (void) acl_strip(dev
, uid
, gid
, mode
);