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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include <sys/varargs.h>
39 #include "nscd_config.h"
40 #include "nscd_switch.h"
44 * old nscd debug levels
47 #define DBG_CANT_FIND 2
48 #define DBG_NETLOOKUPS 4
51 /* max. chars in a nscd log entry */
52 #define LOGBUFLEN 1024
54 /* configuration for the nscd log component */
55 int _nscd_log_comp
= 0x0;
56 int _nscd_log_level
= 0x0;
57 static char _nscd_logfile
[PATH_MAX
] = { 0 };
59 #define NSCD_DEBUG_NONE '0'
60 #define NSCD_DEBUG_OPEN '1'
61 #define NSCD_DEBUG_CLOSE '2'
63 static char _nscd_debug
= NSCD_DEBUG_NONE
;
64 static char _nscd_logfile_d
[PATH_MAX
] = { 0 };
65 static char _nscd_logfile_s
[PATH_MAX
] = { 0 };
68 static nscd_cfg_stat_global_log_t logstats
= {
69 NSCD_CFG_STAT_GROUP_INFO_GLOBAL_LOG
, 0 };
71 /* if no log file specified, log entry goes to stderr */
75 /* close old log file and open a new one */
81 char *me
= "_nscd_set_lf";
84 * don't try and open the log file /dev/null
86 if (lf
== NULL
|| *lf
== 0) {
87 /* ignore empty log file specs */
88 return (NSCD_SUCCESS
);
89 } else if (strcmp(lf
, "/dev/null") == 0) {
90 (void) strlcpy(_nscd_logfile
, lf
, PATH_MAX
);
94 return (NSCD_SUCCESS
);
95 } else if (strcmp(lf
, "stderr") == 0) {
96 (void) strlcpy(_nscd_logfile
, lf
, PATH_MAX
);
97 if (_logfd
!= -1 && _logfd
!= 2)
100 return (NSCD_SUCCESS
);
104 * In order to open this file securely, we'll try a few tricks
107 if ((newlogfd
= open(lf
, O_EXCL
|O_WRONLY
|O_CREAT
, 0644)) < 0) {
109 * File already exists... now we need to get cute
110 * since opening a file in a world-writeable directory
111 * safely is hard = it could be a hard link or a
112 * symbolic link to a system file.
116 if (lstat(lf
, &before
) < 0) {
117 if (_nscd_debug
== NSCD_DEBUG_NONE
)
118 _nscd_logit(me
, "Cannot open new "
119 "logfile \"%s\": %sn",
120 lf
, strerror(errno
));
121 return (NSCD_CFG_FILE_OPEN_ERROR
);
124 if (S_ISREG(before
.st_mode
) && /* no symbolic links */
125 (before
.st_nlink
== 1) && /* no hard links */
126 (before
.st_uid
== 0)) { /* owned by root */
128 open(lf
, O_APPEND
|O_WRONLY
, 0644)) < 0) {
129 if (_nscd_debug
== NSCD_DEBUG_NONE
)
132 "logfile \"%s\": %s\n", lf
,
134 return (NSCD_CFG_FILE_OPEN_ERROR
);
137 if (_nscd_debug
== NSCD_DEBUG_NONE
)
138 _nscd_logit(me
, "Cannot use specified "
140 "file is/has links or isn't "
141 "owned by root\n", lf
);
142 return (NSCD_CFG_FILE_OPEN_ERROR
);
146 (void) close(_logfd
);
147 (void) strlcpy(_nscd_logfile
, lf
, PATH_MAX
);
149 if (_nscd_debug
== NSCD_DEBUG_NONE
)
150 _nscd_logit(me
, "Start of new logfile %s\n", lf
);
152 return (NSCD_SUCCESS
);
156 /* log an entry to the configured nscd log file */
163 static mutex_t loglock
= DEFAULTMUTEX
;
167 char buffer
[LOGBUFLEN
];
168 int safechars
, offset
;
174 if (_nscd_debug
== NSCD_DEBUG_OPEN
) {
175 (void) mutex_lock(&loglock
);
176 if (_nscd_debug
== NSCD_DEBUG_OPEN
&&
177 *_nscd_logfile_d
!= '\0' &&
178 (strcmp(_nscd_logfile
, "/dev/null") == 0 ||
179 strcmp(_nscd_logfile
, "stderr") == 0)) {
180 (void) strlcpy(_nscd_logfile_s
,
181 _nscd_logfile
, PATH_MAX
);
182 (void) _nscd_set_lf(_nscd_logfile_d
);
184 _nscd_debug
= NSCD_DEBUG_NONE
;
185 (void) mutex_unlock(&loglock
);
186 } else if (_nscd_debug
== NSCD_DEBUG_CLOSE
) {
187 (void) mutex_lock(&loglock
);
188 if (_nscd_debug
== NSCD_DEBUG_CLOSE
)
189 (void) _nscd_set_lf(_nscd_logfile_s
);
190 _nscd_debug
= NSCD_DEBUG_NONE
;
191 (void) mutex_unlock(&loglock
);
194 va_start(ap
, format
);
196 if (gettimeofday(&tv
, NULL
) != 0 ||
197 ctime_r(&tv
.tv_sec
, buffer
) == NULL
) {
198 (void) snprintf(buffer
, LOGBUFLEN
,
199 "<time conversion failed>\t");
201 (void) sprintf(tid_buf
, "--%d", thr_self());
202 (void) sprintf(pid_buf
, "--%ld", getpid());
204 * ctime_r() includes some stuff we don't want;
205 * adjust length to overwrite " YYYY\n" and
206 * include tid string length.
208 offset
= strlen(buffer
) - 6;
209 safechars
= LOGBUFLEN
- (offset
- 1);
210 (void) snprintf(buffer
+ offset
,
211 safechars
, ".%.4ld%s%s\t%s:\n\t\t",
212 tv
.tv_usec
/100, tid_buf
, pid_buf
,
215 offset
= strlen(buffer
);
216 safechars
= LOGBUFLEN
- (offset
- 1);
217 /*LINTED: E_SEC_PRINTF_VAR_FMT*/
218 if (vsnprintf(buffer
+ offset
, safechars
, format
, ap
) >
220 (void) strncat(buffer
, "...\n", LOGBUFLEN
);
223 (void) mutex_lock(&loglock
);
224 (void) write(_logfd
, buffer
, strlen(buffer
));
225 logstats
.entries_logged
++;
226 (void) mutex_unlock(&loglock
);
232 * Map old nscd debug level (0 -10) to log level:
233 * -- >= 6: DBG_ALL --> NSCD_LOG_LEVEL_ALL
234 * -- >= 4: DBG_DBG_NETLOOKUPS --> NSCD_LOG_LEVEL_CANT_FIND
235 * -- >= 2: DBG_CANT_FIND --> NSCD_LOG_LEVEL_CANT_FIND
236 * -- >= 0: DBG_OFF --> NSCD_LOG_LEVEL_NONE
242 if (level
>= 0 && level
<= 10) {
243 if (level
>= DBG_ALL
)
244 return (NSCD_LOG_LEVEL_ALL
);
245 else if (level
>= DBG_NETLOOKUPS
)
246 return (NSCD_LOG_LEVEL_CANT_FIND
);
247 else if (level
>= DBG_CANT_FIND
)
248 return (NSCD_LOG_LEVEL_CANT_FIND
);
249 else if (level
>= DBG_OFF
)
250 return (NSCD_LOG_LEVEL_NONE
);
257 _nscd_cfg_log_notify(
259 struct nscd_cfg_param_desc
*pdesc
,
260 nscd_cfg_id_t
*nswdb
,
261 nscd_cfg_flag_t dflag
,
262 nscd_cfg_error_t
**errorp
,
266 nscd_cfg_global_log_t
*logcfg
;
270 * At init time, the whole group of config params are received.
271 * At update time, group or individual parameter value could
275 if (_nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_GROUP
)) {
277 logcfg
= (nscd_cfg_global_log_t
*)data
;
279 _nscd_log_comp
= logcfg
->debug_comp
;
280 _nscd_log_level
= logcfg
->debug_level
;
283 * logcfg->logfile should have been opened
284 * by _nscd_cfg_log_verify()
287 return (NSCD_SUCCESS
);
291 * individual config parameter
293 off
= offsetof(nscd_cfg_global_log_t
, debug_comp
);
294 if (pdesc
->p_offset
== off
) {
295 _nscd_log_comp
= *(nscd_cfg_bitmap_t
*)data
;
296 return (NSCD_SUCCESS
);
299 off
= offsetof(nscd_cfg_global_log_t
, debug_level
);
300 if (pdesc
->p_offset
== off
)
301 _nscd_log_level
= *(nscd_cfg_bitmap_t
*)data
;
304 * logcfg->logfile should have been opened
305 * by _nscd_cfg_log_verify()
308 return (NSCD_SUCCESS
);
313 _nscd_cfg_log_verify(
315 struct nscd_cfg_param_desc
*pdesc
,
316 nscd_cfg_id_t
*nswdb
,
317 nscd_cfg_flag_t dflag
,
318 nscd_cfg_error_t
**errorp
,
321 nscd_cfg_global_log_t
*logcfg
;
322 nscd_cfg_bitmap_t bt
;
326 * There is no switch db specific config params
327 * for the nscd log component. It is a bug if
328 * the input param description is global.
330 if (_nscd_cfg_flag_is_not_set(pdesc
->pflag
, NSCD_CFG_PFLAG_GLOBAL
))
331 return (NSCD_CFG_PARAM_DESC_ERROR
);
334 * At init time, the whole group of config params are received.
335 * At update time, group or individual parameter value could
339 if (_nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_GROUP
)) {
341 logcfg
= (nscd_cfg_global_log_t
*)data
;
343 if (_nscd_cfg_bitmap_valid(logcfg
->debug_comp
,
345 return (NSCD_CFG_SYNTAX_ERROR
);
347 if (_nscd_cfg_bitmap_valid(logcfg
->debug_level
,
348 NSCD_LOG_LEVEL_ALL
) == 0)
349 return (NSCD_CFG_SYNTAX_ERROR
);
351 if (logcfg
->logfile
!= NULL
)
352 return (_nscd_set_lf(logcfg
->logfile
));
354 return (NSCD_SUCCESS
);
358 * individual config parameter
361 off
= offsetof(nscd_cfg_global_log_t
, debug_comp
);
362 if (pdesc
->p_offset
== off
) {
364 bt
= *(nscd_cfg_bitmap_t
*)data
;
365 if (_nscd_cfg_bitmap_valid(bt
, NSCD_LOG_ALL
) == 0)
366 return (NSCD_CFG_SYNTAX_ERROR
);
368 return (NSCD_SUCCESS
);
371 off
= offsetof(nscd_cfg_global_log_t
, debug_level
);
372 if (pdesc
->p_offset
== off
) {
374 bt
= *(nscd_cfg_bitmap_t
*)data
;
375 if (_nscd_cfg_bitmap_valid(bt
, NSCD_LOG_LEVEL_ALL
) == 0)
376 return (NSCD_CFG_SYNTAX_ERROR
);
378 return (NSCD_SUCCESS
);
381 off
= offsetof(nscd_cfg_global_log_t
, logfile
);
382 if (pdesc
->p_offset
== off
) {
384 return (_nscd_set_lf((char *)data
));
386 return (NSCD_SUCCESS
);
389 return (NSCD_CFG_PARAM_DESC_ERROR
);
394 _nscd_cfg_log_get_stat(
396 struct nscd_cfg_stat_desc
*sdesc
,
397 nscd_cfg_id_t
*nswdb
,
398 nscd_cfg_flag_t
*dflag
,
399 void (**free_stat
)(void *stat
),
400 nscd_cfg_error_t
**errorp
)
403 *(nscd_cfg_stat_global_log_t
**)stat
= &logstats
;
405 /* indicate the statistics are static, i.e., do not free */
406 *dflag
= _nscd_cfg_flag_set(*dflag
, NSCD_CFG_DFLAG_STATIC_DATA
);
408 return (NSCD_SUCCESS
);
412 * set the name of the current log file and make it current.
419 nscd_cfg_handle_t
*h
;
421 rc
= _nscd_cfg_get_handle("logfile", NULL
, &h
, NULL
);
422 if (rc
!= NSCD_SUCCESS
)
425 rc
= _nscd_cfg_set(h
, name
, NULL
);
426 _nscd_cfg_free_handle(h
);
427 if (rc
!= NSCD_SUCCESS
)
430 return (NSCD_SUCCESS
);
433 /* Set debug level to the new one and make it current */
435 _nscd_set_debug_level(
439 nscd_cfg_handle_t
*h
;
443 /* old nscd debug level is 1 to 10, map it to log_level and log_comp */
444 if (level
>= 0 && level
<= 10) {
445 l
= debug_to_log_level(level
);
451 c
= -1 * level
/ 1000000;
454 rc
= _nscd_cfg_get_handle("debug-components", NULL
, &h
, NULL
);
455 if (rc
!= NSCD_SUCCESS
)
458 rc
= _nscd_cfg_set(h
, &c
, NULL
);
459 _nscd_cfg_free_handle(h
);
460 if (rc
!= NSCD_SUCCESS
)
464 rc
= _nscd_cfg_get_handle("debug-level", NULL
, &h
, NULL
);
465 if (rc
!= NSCD_SUCCESS
)
469 l
= -1 * level
% 1000000;
471 rc
= _nscd_cfg_set(h
, &l
, NULL
);
472 _nscd_cfg_free_handle(h
);
473 if (rc
!= NSCD_SUCCESS
)
476 return (NSCD_SUCCESS
);
486 if (_nscd_log_level
!= 0)
487 (void) snprintf(level
, llen
, "%d", _nscd_log_level
);
488 if (*_nscd_logfile
!= '\0')
489 (void) strlcpy(file
, _nscd_logfile
, flen
);