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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * util.c contains a set of miscellaneous utility functions which: 29 * - syslog(LOG_DEBUG, ...) if debugging is enabled 30 * - check for an IP interface being marked running 31 * - look up all flags for an IP interface 32 * - start a child process 33 * - schedule a timer 34 * - look up the zone name 35 */ 36 37 #include <stdarg.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <pthread.h> 42 #include <string.h> 43 #include <stropts.h> 44 #include <syslog.h> 45 #include <sys/types.h> 46 #include <sys/socket.h> 47 #include <net/if.h> 48 #include <netinet/in.h> 49 #include <arpa/inet.h> 50 #include <spawn.h> 51 #include <wait.h> 52 #include <inetcfg.h> 53 #include <errno.h> 54 #include <zone.h> 55 56 #include "defines.h" 57 #include "structures.h" 58 #include "functions.h" 59 #include "variables.h" 60 61 extern char **environ; 62 boolean_t debug = B_FALSE; 63 64 /* PRINTFLIKE1 */ 65 void 66 dprintf(const char *fmt, ...) 67 { 68 va_list ap; 69 char vbuf[1024]; 70 71 va_start(ap, fmt); 72 if (debug) { 73 (void) vsnprintf(vbuf, sizeof (vbuf), fmt, ap); 74 syslog(LOG_DEBUG, "%d: %s", pthread_self(), vbuf); 75 } 76 va_end(ap); 77 } 78 79 uint64_t 80 get_ifflags(const char *name, sa_family_t family) 81 { 82 icfg_if_t intf; 83 icfg_handle_t h; 84 uint64_t flags = 0; 85 86 (void) strlcpy(intf.if_name, name, sizeof (intf.if_name)); 87 intf.if_protocol = family; 88 89 if (icfg_open(&h, &intf) != ICFG_SUCCESS) 90 return (0); 91 92 if (icfg_get_flags(h, &flags) != ICFG_SUCCESS) { 93 /* 94 * Interfaces can be ripped out from underneath us (for example 95 * by DHCP). We don't want to spam the console for those. 96 */ 97 if (errno == ENOENT) 98 dprintf("get_ifflags: icfg_get_flags failed for '%s'", 99 name); 100 else 101 syslog(LOG_ERR, "get_ifflags: icfg_get_flags %s af " 102 "%d: %m", name, family); 103 /* just to be sure... */ 104 flags = 0; 105 } 106 icfg_close(h); 107 108 return (flags); 109 } 110 111 /* This is just a work-around for CR 6745448: clear out a toxic interface */ 112 void 113 zero_out_v4addr(const char *name) 114 { 115 icfg_if_t intf; 116 icfg_handle_t h; 117 struct sockaddr_in sinv; 118 socklen_t sinlen; 119 int pfxlen; 120 121 (void) strlcpy(intf.if_name, name, sizeof (intf.if_name)); 122 intf.if_protocol = AF_INET; 123 124 if (icfg_open(&h, &intf) != ICFG_SUCCESS) 125 return; 126 127 sinlen = sizeof (sinv); 128 if (icfg_get_addr(h, (struct sockaddr *)&sinv, &sinlen, &pfxlen, 129 B_FALSE) == ICFG_SUCCESS && 130 sinv.sin_addr.s_addr != INADDR_ANY) { 131 dprintf("bug workaround: clear out address %s on %s", 132 inet_ntoa(sinv.sin_addr), name); 133 sinv.sin_addr.s_addr = INADDR_ANY; 134 (void) icfg_set_addr(h, (const struct sockaddr *)&sinv, sinlen); 135 } 136 icfg_close(h); 137 } 138 139 /* 140 * 141 * This starts a child process determined by command. If command contains a 142 * slash then it is assumed to be a full path; otherwise the path is searched 143 * for an executable file with the name command. Command is also used as 144 * argv[0] of the new process. The rest of the arguments of the function 145 * up to the first NULL make up pointers to arguments of the new process. 146 * 147 * This function returns child exit status on success and -1 on failure. 148 * 149 * NOTE: original_sigmask must be set before this function is called. 150 */ 151 int 152 start_childv(const char *command, char const * const *argv) 153 { 154 posix_spawnattr_t attr; 155 sigset_t fullset; 156 int i, rc, status, n; 157 pid_t pid; 158 char vbuf[1024]; 159 160 vbuf[0] = 0; 161 n = sizeof (vbuf); 162 for (i = 1; argv[i] != NULL && n > 2; i++) { 163 n -= strlcat(vbuf, " ", n); 164 n -= strlcat(vbuf, argv[i], n); 165 } 166 if (argv[i] != NULL || n < 0) 167 syslog(LOG_ERR, "start_childv can't log full arg vector"); 168 169 if ((rc = posix_spawnattr_init(&attr)) != 0) { 170 dprintf("posix_spawnattr_init %d %s\n", rc, strerror(rc)); 171 return (-1); 172 } 173 (void) sigfillset(&fullset); 174 if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) { 175 dprintf("setsigdefault %d %s\n", rc, strerror(rc)); 176 return (-1); 177 } 178 if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) { 179 dprintf("setsigmask %d %s\n", rc, strerror(rc)); 180 return (-1); 181 } 182 if ((rc = posix_spawnattr_setflags(&attr, 183 POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) { 184 dprintf("setflags %d %s\n", rc, strerror(rc)); 185 return (-1); 186 } 187 188 if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv, 189 environ)) > 0) { 190 dprintf("posix_spawnp failed errno %d", rc); 191 return (-1); 192 } 193 194 if ((rc = posix_spawnattr_destroy(&attr)) != 0) { 195 dprintf("posix_spawn_attr_destroy %d %s\n", rc, strerror(rc)); 196 return (-1); 197 } 198 199 (void) waitpid(pid, &status, 0); 200 if (WIFSIGNALED(status) || WIFSTOPPED(status)) { 201 i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status); 202 syslog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf, 203 (WIFSIGNALED(status) ? "terminated" : "stopped"), i, 204 strsignal(i)); 205 return (-2); 206 } else { 207 syslog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf, 208 WEXITSTATUS(status)); 209 return (WEXITSTATUS(status)); 210 } 211 } 212 213 int 214 start_child(const char *command, ...) 215 { 216 const char **argv = NULL; 217 int argv_len = 0; 218 va_list ap; 219 int i = 1, rc; 220 221 va_start(ap, command); 222 do { 223 if (i >= argv_len) { 224 void *p; 225 226 argv_len = argv_len != 0 ? argv_len * 2 : 4; 227 p = realloc(argv, sizeof (*argv)*argv_len); 228 if (p != NULL) { 229 argv = p; 230 } else { 231 syslog(LOG_ERR, "Out of memory in start_child"); 232 free(argv); 233 return (-1); 234 } 235 } 236 237 argv[i] = va_arg(ap, const char *); 238 } while (argv[i++] != NULL); 239 va_end(ap); 240 argv[0] = command; 241 242 rc = start_childv(command, argv); 243 free(argv); 244 245 return (rc); 246 } 247 248 uint32_t timer_expire = TIMER_INFINITY; 249 250 /* 251 * Schedules a SIGALRM in delay seconds, unless one is already 252 * scheduled sooner. If one is already scheduled later than 253 * delay seconds from now, that one will be replaced. 254 */ 255 void 256 start_timer(uint32_t now, uint32_t delay) 257 { 258 if (now + delay > timer_expire) 259 return; 260 261 timer_expire = now + delay; 262 (void) alarm(delay); 263 } 264 265 void 266 lookup_zonename(char *zonename, size_t zonesize) 267 { 268 zoneid_t zoneid = getzoneid(); 269 270 if (getzonenamebyid(zoneid, zonename, zonesize) >= 0) 271 return; 272 syslog(LOG_ERR, "could not determine zone name"); 273 (void) strlcpy(zonename, GLOBAL_ZONENAME, zonesize); 274 } 275