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 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33/*
34 * error/logging/cleanup functions for ttymon.
35 */
36
37#include <unistd.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <fcntl.h>
41#include <string.h>
42#include <errno.h>
43#include <stdarg.h>
44#include <time.h>
45#include <sys/types.h>
46#include <sys/stat.h>
47#include <sys/param.h>
48#include <signal.h>
49#include <syslog.h>
50#include "ttymon.h"
51#include "tmstruct.h"
52#include "tmextern.h"
53
54# ifdef DEBUG
55extern FILE *Debugfp;
56# endif
57
58const char *appname = "ttymon";
59
60void
61openttymonlog(void)
62{
63	int	fd, ret;
64	char	logfile[MAXPATHLEN];
65	extern	char	*Tag;
66
67	/* the log file resides in /var/saf/pmtag/ */
68	(void) snprintf(logfile, sizeof (logfile), "%s%s/%s", LOGDIR, Tag,
69	    LOGFILE);
70
71	Logfp = NULL;
72	(void)close(0);
73	if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND,0444)) != -1)
74		if ((ret = fcntl(fd, F_DUPFD, 3)) == 3) {
75			/* set close-on-exec flag */
76			if (fcntl(ret, F_SETFD, FD_CLOEXEC) == 0) {
77				Logfp = fdopen(ret, "a+");
78			}
79		}
80	if (!Logfp) {
81		cons_printf("ttymon cannot create log file \"%s\": %s\n",
82		    logfile, strerror(errno));
83		exit(1);
84	}
85	log(" ");
86	log("********** ttymon starting **********");
87
88#ifdef	DEBUG
89	log("fd(log)\t = %d", fileno(Logfp));
90#endif
91}
92
93static void
94roll_log()
95{
96	char logf[MAXPATHLEN];
97	char ologf[MAXPATHLEN];
98	char tlogf[MAXPATHLEN];
99	FILE *nlogfp;
100	struct stat buf;
101
102	(void) fprintf(Logfp, "Restarting log file\n");
103	(void) snprintf(logf, sizeof (logf), "%s%s/%s", LOGDIR, Tag, LOGFILE);
104
105	(void) snprintf(ologf, sizeof (ologf), "%s%s/%s", LOGDIR, Tag,
106	    OLOGFILE);
107
108	(void) snprintf(tlogf, sizeof (tlogf), "%s%s/%s", LOGDIR, Tag,
109	    TLOGFILE);
110
111	if (!stat(ologf, &buf) && rename(ologf, tlogf)) {
112		(void) fprintf(Logfp, "rename old to tmp file failed\n");
113	} else if (!stat(logf, &buf) && rename(logf, ologf)) {
114		(void) fprintf(Logfp, "rename log to old file failed\n");
115		/* Restore old log file */
116		if (!stat(tlogf, &buf) && rename(tlogf, ologf))
117			(void) fprintf(Logfp,
118			    "rename tmp to old file failed\n");
119	} else if (nlogfp = fopen(logf, "w")) {
120		(void) fclose(Logfp);
121		Logfp = nlogfp;
122		/* reset close-on-exec */
123		(void) fcntl(fileno(Logfp), F_SETFD, 1);
124	} else {
125		(void) fprintf(Logfp, "log file open failed\n");
126		/* Restore current and old log file */
127		if (!stat(ologf, &buf) && rename(ologf, logf))
128			(void) fprintf(Logfp,
129			    "rename old to log file failed\n");
130		else if (!stat(tlogf, &buf) && rename(tlogf, ologf))
131			(void) fprintf(Logfp,
132			    "rename tmp to old file failed\n");
133	}
134
135	(void) unlink(tlogf); /* remove any stale tmp logfile */
136}
137
138
139/*
140 * vlog(msg) - common message routine.
141 *	    - if Logfp is NULL, write message to stderr or CONSOLE
142 */
143static void
144vlog(const char *fmt, va_list ap)
145{
146	char *timestamp;	/* current time in readable form */
147	time_t clock;		/* current time in seconds */
148	int	fd;
149	struct stat buf;
150
151	if (Logfp) {
152		if ((fstat(fileno(Logfp), &buf) != -1) &&
153		    (buf.st_size >= Logmaxsz) && !Splflag) {
154			Splflag = 1;
155			roll_log();
156			Splflag = 0;
157		}
158
159		(void) time(&clock);
160		timestamp = ctime(&clock);
161		*(strchr(timestamp, '\n')) = '\0';
162		(void) fprintf(Logfp, "%s; %ld; ", timestamp, getpid());
163		(void) vfprintf(Logfp, fmt, ap);
164		if (fmt[strlen(fmt) - 1] != '\n')
165			(void) fputc('\n', Logfp);
166		(void) fflush(Logfp);
167	} else if (isatty(STDERR_FILENO)) {
168		(void) fprintf(stderr, "%s: ", appname);
169		(void) vfprintf(stderr, fmt, ap);
170		if (fmt[strlen(fmt) - 1] != '\n')
171			(void) fputc('\n', stderr);
172		(void) fflush(stderr);
173	} else if ((fd = open(CONSOLE, O_WRONLY|O_NOCTTY)) != -1) {
174		FILE *f = fdopen(fd, "w");
175
176		(void) fprintf(f, "%s: ", appname);
177		(void) vfprintf(f, fmt, ap);
178		if (fmt[strlen(fmt) - 1] != '\n')
179			(void) fputc('\n', f);
180		(void) fclose(f);
181	} else {
182		vsyslog(LOG_CRIT, fmt, ap);
183	}
184}
185
186/*
187 * log(fmt, ...) - put a message into the log file
188 *	    - if Logfp is NULL, write message to stderr or CONSOLE
189 */
190/*PRINTFLIKE1*/
191void
192log(const char *fmt, ...)
193{
194	va_list ap;
195	va_start(ap, fmt);
196	vlog(fmt, ap);
197	va_end(ap);
198}
199
200
201/*
202 * fatal(fmt, ...) - put a message into the log file, then exit.
203 */
204/*PRINTFLIKE1*/
205void
206fatal(const char *fmt, ...)
207{
208	if (fmt) {
209		va_list ap;
210		va_start(ap, fmt);
211		vlog(fmt, ap);
212		va_end(ap);
213	}
214	log("********** ttymon exiting ***********");
215	exit(1);
216}
217
218# ifdef DEBUG
219
220/*
221 * opendebug - open debugging file, sets global file pointer Debugfp
222 * 	arg:   getty - if TRUE, ttymon is in getty_mode and use a different
223 *		       debug file
224 */
225
226void
227opendebug(int getty_mode)
228{
229	int  fd, ret;
230	char	debugfile[BUFSIZ];
231	extern	char	*Tag;
232
233	if (!getty_mode) {
234		(void)strcpy(debugfile, LOGDIR);
235		(void)strcat(debugfile, Tag);
236		(void)strcat(debugfile, "/");
237		(void)strcat(debugfile, DBGFILE);
238		if ((Debugfp = fopen(debugfile, "a+")) == NULL)
239			fatal("open debug file failed");
240	}
241	else {
242		if ((fd = open(EX_DBG, O_WRONLY|O_APPEND|O_CREAT)) < 0)
243			fatal("open %s failed: %s", EX_DBG, errno);
244
245		if (fd >= 3)
246			ret = fd;
247		else {
248			if ((ret = fcntl(fd, F_DUPFD, 3)) < 0)
249				fatal("F_DUPFD fcntl failed: %s",
250				    strerror(errno));
251
252		}
253		if ((Debugfp = fdopen(ret, "a+")) == NULL)
254			fatal("fdopen failed: %s", strerror(errno));
255
256		if (ret != fd)
257			(void)close(fd);
258	}
259	/* set close-on-exec flag */
260	if (fcntl(fileno(Debugfp), F_SETFD, 1) == -1)
261		fatal("F_SETFD fcntl failed: %s", strerror(errno));
262}
263
264/*
265 * debug(msg) - put a message into debug file
266 */
267
268void
269debug(const char *fmt, ...)
270{
271	va_list ap;
272	char *timestamp;	/* current time in readable form */
273	time_t clock;		/* current time in seconds */
274
275	(void) time(&clock);
276	timestamp = ctime(&clock);
277	*(strchr(timestamp, '\n')) = '\0';
278
279	(void) fprintf(Debugfp, "%s; %ld; ", timestamp, getpid());
280
281	va_start(ap, fmt);
282	(void) vfprintf(Debugfp, fmt, ap);
283	va_end(ap);
284
285	(void) fprintf(Debugfp, "\n");
286	(void) fflush(Debugfp);
287}
288#endif
289