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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <assert.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <stdarg.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <strings.h> 35 #include <thread.h> 36 #include <unistd.h> 37 38 #include <sys/modctl.h> 39 #include <sys/stat.h> 40 #include <sys/types.h> 41 42 #include <sys/lx_brand.h> 43 #include <sys/lx_debug.h> 44 #include <sys/lx_misc.h> 45 46 /* internal debugging state */ 47 static char *lx_debug_path = NULL; /* debug output file path */ 48 static char lx_debug_path_buf[MAXPATHLEN]; 49 50 void 51 lx_debug_enable(void) 52 { 53 /* send all debugging output to /dev/tty */ 54 lx_debug_path = "/dev/tty"; 55 lx_debug("lx_debug: debugging output enabled: %s", lx_debug_path); 56 } 57 58 void 59 lx_debug_init(void) 60 { 61 if (getenv("LX_DEBUG") == NULL) 62 return; 63 64 /* 65 * It's OK to use this value without any locking, as all callers can 66 * use the return value to decide whether extra work should be done 67 * before calling lx_debug(). 68 * 69 * If debugging is disabled after a routine calls this function it 70 * doesn't really matter as lx_debug() will see debugging is disabled 71 * and will not output anything. 72 */ 73 lx_debug_enabled = 1; 74 75 /* check if there's a debug log file specified */ 76 lx_debug_path = getenv("LX_DEBUG_FILE"); 77 if (lx_debug_path == NULL) { 78 /* send all debugging output to /dev/tty */ 79 lx_debug_path = "/dev/tty"; 80 } 81 82 (void) strlcpy(lx_debug_path_buf, lx_debug_path, 83 sizeof (lx_debug_path_buf)); 84 lx_debug_path = lx_debug_path_buf; 85 86 lx_debug("lx_debug: debugging output ENABLED to path: \"%s\"", 87 lx_debug_path); 88 } 89 90 void 91 lx_debug(const char *msg, ...) 92 { 93 va_list ap; 94 char buf[LX_MSG_MAXLEN + 1]; 95 int rv, fd, n; 96 int errno_backup; 97 98 if (lx_debug_enabled == 0) 99 return; 100 101 errno_backup = errno; 102 103 /* prefix the message with pid/tid */ 104 if ((n = snprintf(buf, sizeof (buf), "%u/%u: ", 105 getpid(), thr_self())) == -1) { 106 errno = errno_backup; 107 return; 108 } 109 110 /* format the message */ 111 va_start(ap, msg); 112 rv = vsnprintf(&buf[n], sizeof (buf) - n, msg, ap); 113 va_end(ap); 114 if (rv == -1) { 115 errno = errno_backup; 116 return; 117 } 118 119 /* add a carrige return if there isn't one already */ 120 if ((buf[strlen(buf) - 1] != '\n') && 121 (strlcat(buf, "\n", sizeof (buf)) >= sizeof (buf))) { 122 errno = errno_backup; 123 return; 124 } 125 126 /* 127 * Open the debugging output file. note that we don't protect 128 * ourselves against exec or fork1 here. if an mt process were 129 * to exec/fork1 while we're doing this they'd end up with an 130 * extra open desciptor in their fd space. a'well. shouldn't 131 * really matter. 132 */ 133 if ((fd = open(lx_debug_path, 134 O_WRONLY|O_APPEND|O_CREAT|O_NDELAY|O_NOCTTY, 0666)) == -1) { 135 return; 136 } 137 (void) fchmod(fd, 0666); 138 139 /* we retry in case of EINTR */ 140 do { 141 rv = write(fd, buf, strlen(buf)); 142 } while ((rv == -1) && (errno == EINTR)); 143 (void) fsync(fd); 144 145 (void) close(fd); 146 errno = errno_backup; 147 }