13938Sjbeck /* 23938Sjbeck * CDDL HEADER START 33938Sjbeck * 43938Sjbeck * The contents of this file are subject to the terms of the 53938Sjbeck * Common Development and Distribution License (the "License"). 63938Sjbeck * You may not use this file except in compliance with the License. 73938Sjbeck * 83938Sjbeck * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93938Sjbeck * or http://www.opensolaris.org/os/licensing. 103938Sjbeck * See the License for the specific language governing permissions 113938Sjbeck * and limitations under the License. 123938Sjbeck * 133938Sjbeck * When distributing Covered Code, include this CDDL HEADER in each 143938Sjbeck * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153938Sjbeck * If applicable, add the following below this CDDL HEADER, with the 163938Sjbeck * fields enclosed by brackets "[]" replaced with your own identifying 173938Sjbeck * information: Portions Copyright [yyyy] [name of copyright owner] 183938Sjbeck * 193938Sjbeck * CDDL HEADER END 203938Sjbeck */ 213938Sjbeck 223938Sjbeck /* 23*7645Sjames.d.carlson@sun.com * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243938Sjbeck * Use is subject to license terms. 253938Sjbeck */ 263938Sjbeck 273938Sjbeck /* 283938Sjbeck * util.c contains a set of miscellaneous utility functions which: 293938Sjbeck * - syslog(LOG_DEBUG, ...) if debugging is enabled 303938Sjbeck * - check for an IP interface being marked running 313938Sjbeck * - look up all flags for an IP interface 323938Sjbeck * - start a child process 333938Sjbeck * - schedule a timer 343938Sjbeck * - look up the zone name 353938Sjbeck */ 363938Sjbeck 373938Sjbeck #include <stdarg.h> 383938Sjbeck #include <stdio.h> 393938Sjbeck #include <stdlib.h> 403938Sjbeck #include <unistd.h> 413938Sjbeck #include <pthread.h> 423938Sjbeck #include <string.h> 433938Sjbeck #include <stropts.h> 443938Sjbeck #include <syslog.h> 453938Sjbeck #include <sys/types.h> 463938Sjbeck #include <sys/socket.h> 473938Sjbeck #include <net/if.h> 48*7645Sjames.d.carlson@sun.com #include <netinet/in.h> 49*7645Sjames.d.carlson@sun.com #include <arpa/inet.h> 503938Sjbeck #include <spawn.h> 513938Sjbeck #include <wait.h> 523938Sjbeck #include <inetcfg.h> 533938Sjbeck #include <errno.h> 543938Sjbeck #include <zone.h> 553938Sjbeck 563938Sjbeck #include "defines.h" 573938Sjbeck #include "structures.h" 583938Sjbeck #include "functions.h" 593938Sjbeck #include "variables.h" 603938Sjbeck 613938Sjbeck extern char **environ; 623938Sjbeck boolean_t debug = B_FALSE; 633938Sjbeck 645439Smeem /* PRINTFLIKE1 */ 653938Sjbeck void 663938Sjbeck dprintf(const char *fmt, ...) 673938Sjbeck { 683938Sjbeck va_list ap; 693938Sjbeck char vbuf[1024]; 703938Sjbeck 713938Sjbeck va_start(ap, fmt); 723938Sjbeck if (debug) { 733938Sjbeck (void) vsnprintf(vbuf, sizeof (vbuf), fmt, ap); 743938Sjbeck syslog(LOG_DEBUG, "%d: %s", pthread_self(), vbuf); 753938Sjbeck } 763938Sjbeck va_end(ap); 773938Sjbeck } 783938Sjbeck 793938Sjbeck uint64_t 803938Sjbeck get_ifflags(const char *name, sa_family_t family) 813938Sjbeck { 823938Sjbeck icfg_if_t intf; 833938Sjbeck icfg_handle_t h; 843938Sjbeck uint64_t flags = 0; 853938Sjbeck 863938Sjbeck (void) strlcpy(intf.if_name, name, sizeof (intf.if_name)); 873938Sjbeck intf.if_protocol = family; 883938Sjbeck 893938Sjbeck if (icfg_open(&h, &intf) != ICFG_SUCCESS) 903938Sjbeck return (0); 913938Sjbeck 923938Sjbeck if (icfg_get_flags(h, &flags) != ICFG_SUCCESS) { 933938Sjbeck /* 943938Sjbeck * Interfaces can be ripped out from underneath us (for example 953938Sjbeck * by DHCP). We don't want to spam the console for those. 963938Sjbeck */ 973938Sjbeck if (errno == ENOENT) 983938Sjbeck dprintf("get_ifflags: icfg_get_flags failed for '%s'", 993938Sjbeck name); 1003938Sjbeck else 1013938Sjbeck syslog(LOG_ERR, "get_ifflags: icfg_get_flags %s af " 1023938Sjbeck "%d: %m", name, family); 1033938Sjbeck /* just to be sure... */ 1043938Sjbeck flags = 0; 1053938Sjbeck } 1063938Sjbeck icfg_close(h); 1073938Sjbeck 1083938Sjbeck return (flags); 1093938Sjbeck } 1103938Sjbeck 111*7645Sjames.d.carlson@sun.com /* This is just a work-around for CR 6745448: clear out a toxic interface */ 112*7645Sjames.d.carlson@sun.com void 113*7645Sjames.d.carlson@sun.com zero_out_v4addr(const char *name) 114*7645Sjames.d.carlson@sun.com { 115*7645Sjames.d.carlson@sun.com icfg_if_t intf; 116*7645Sjames.d.carlson@sun.com icfg_handle_t h; 117*7645Sjames.d.carlson@sun.com struct sockaddr_in sinv; 118*7645Sjames.d.carlson@sun.com socklen_t sinlen; 119*7645Sjames.d.carlson@sun.com int pfxlen; 120*7645Sjames.d.carlson@sun.com 121*7645Sjames.d.carlson@sun.com (void) strlcpy(intf.if_name, name, sizeof (intf.if_name)); 122*7645Sjames.d.carlson@sun.com intf.if_protocol = AF_INET; 123*7645Sjames.d.carlson@sun.com 124*7645Sjames.d.carlson@sun.com if (icfg_open(&h, &intf) != ICFG_SUCCESS) 125*7645Sjames.d.carlson@sun.com return; 126*7645Sjames.d.carlson@sun.com 127*7645Sjames.d.carlson@sun.com sinlen = sizeof (sinv); 128*7645Sjames.d.carlson@sun.com if (icfg_get_addr(h, (struct sockaddr *)&sinv, &sinlen, &pfxlen, 129*7645Sjames.d.carlson@sun.com B_FALSE) == ICFG_SUCCESS && 130*7645Sjames.d.carlson@sun.com sinv.sin_addr.s_addr != INADDR_ANY) { 131*7645Sjames.d.carlson@sun.com dprintf("bug workaround: clear out address %s on %s", 132*7645Sjames.d.carlson@sun.com inet_ntoa(sinv.sin_addr), name); 133*7645Sjames.d.carlson@sun.com sinv.sin_addr.s_addr = INADDR_ANY; 134*7645Sjames.d.carlson@sun.com (void) icfg_set_addr(h, (const struct sockaddr *)&sinv, sinlen); 135*7645Sjames.d.carlson@sun.com } 136*7645Sjames.d.carlson@sun.com icfg_close(h); 137*7645Sjames.d.carlson@sun.com } 138*7645Sjames.d.carlson@sun.com 1393938Sjbeck /* 1403938Sjbeck * 1413938Sjbeck * This starts a child process determined by command. If command contains a 1423938Sjbeck * slash then it is assumed to be a full path; otherwise the path is searched 1433938Sjbeck * for an executable file with the name command. Command is also used as 1443938Sjbeck * argv[0] of the new process. The rest of the arguments of the function 1453938Sjbeck * up to the first NULL make up pointers to arguments of the new process. 1463938Sjbeck * 1473938Sjbeck * This function returns child exit status on success and -1 on failure. 1483938Sjbeck * 1493938Sjbeck * NOTE: original_sigmask must be set before this function is called. 1503938Sjbeck */ 1513938Sjbeck int 1523938Sjbeck start_childv(const char *command, char const * const *argv) 1533938Sjbeck { 1543938Sjbeck posix_spawnattr_t attr; 1553938Sjbeck sigset_t fullset; 1563938Sjbeck int i, rc, status, n; 1573938Sjbeck pid_t pid; 1583938Sjbeck char vbuf[1024]; 1593938Sjbeck 1603938Sjbeck vbuf[0] = 0; 1613938Sjbeck n = sizeof (vbuf); 1623938Sjbeck for (i = 1; argv[i] != NULL && n > 2; i++) { 1633938Sjbeck n -= strlcat(vbuf, " ", n); 1643938Sjbeck n -= strlcat(vbuf, argv[i], n); 1653938Sjbeck } 1663938Sjbeck if (argv[i] != NULL || n < 0) 1673938Sjbeck syslog(LOG_ERR, "start_childv can't log full arg vector"); 1683938Sjbeck 1693938Sjbeck if ((rc = posix_spawnattr_init(&attr)) != 0) { 1703938Sjbeck dprintf("posix_spawnattr_init %d %s\n", rc, strerror(rc)); 1713938Sjbeck return (-1); 1723938Sjbeck } 1733938Sjbeck (void) sigfillset(&fullset); 1743938Sjbeck if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) { 1753938Sjbeck dprintf("setsigdefault %d %s\n", rc, strerror(rc)); 1763938Sjbeck return (-1); 1773938Sjbeck } 1783938Sjbeck if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) { 1793938Sjbeck dprintf("setsigmask %d %s\n", rc, strerror(rc)); 1803938Sjbeck return (-1); 1813938Sjbeck } 1823938Sjbeck if ((rc = posix_spawnattr_setflags(&attr, 1833938Sjbeck POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) { 1843938Sjbeck dprintf("setflags %d %s\n", rc, strerror(rc)); 1853938Sjbeck return (-1); 1863938Sjbeck } 1873938Sjbeck 1883938Sjbeck if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv, 1893938Sjbeck environ)) > 0) { 1903938Sjbeck dprintf("posix_spawnp failed errno %d", rc); 1913938Sjbeck return (-1); 1923938Sjbeck } 1933938Sjbeck 1943938Sjbeck if ((rc = posix_spawnattr_destroy(&attr)) != 0) { 1953938Sjbeck dprintf("posix_spawn_attr_destroy %d %s\n", rc, strerror(rc)); 1963938Sjbeck return (-1); 1973938Sjbeck } 1983938Sjbeck 1993938Sjbeck (void) waitpid(pid, &status, 0); 2003938Sjbeck if (WIFSIGNALED(status) || WIFSTOPPED(status)) { 2013938Sjbeck i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status); 2023938Sjbeck syslog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf, 2033938Sjbeck (WIFSIGNALED(status) ? "terminated" : "stopped"), i, 2043938Sjbeck strsignal(i)); 2053938Sjbeck return (-2); 2063938Sjbeck } else { 2073938Sjbeck syslog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf, 2083938Sjbeck WEXITSTATUS(status)); 2093938Sjbeck return (WEXITSTATUS(status)); 2103938Sjbeck } 2113938Sjbeck } 2123938Sjbeck 2133938Sjbeck int 2143938Sjbeck start_child(const char *command, ...) 2153938Sjbeck { 2163938Sjbeck const char **argv = NULL; 2173938Sjbeck int argv_len = 0; 2183938Sjbeck va_list ap; 2193938Sjbeck int i = 1, rc; 2203938Sjbeck 2213938Sjbeck va_start(ap, command); 2223938Sjbeck do { 2233938Sjbeck if (i >= argv_len) { 2243938Sjbeck void *p; 2253938Sjbeck 2263938Sjbeck argv_len = argv_len != 0 ? argv_len * 2 : 4; 2273938Sjbeck p = realloc(argv, sizeof (*argv)*argv_len); 2283938Sjbeck if (p != NULL) { 2293938Sjbeck argv = p; 2303938Sjbeck } else { 2313938Sjbeck syslog(LOG_ERR, "Out of memory in start_child"); 2323938Sjbeck free(argv); 2333938Sjbeck return (-1); 2343938Sjbeck } 2353938Sjbeck } 2363938Sjbeck 2373938Sjbeck argv[i] = va_arg(ap, const char *); 2383938Sjbeck } while (argv[i++] != NULL); 2393938Sjbeck va_end(ap); 2403938Sjbeck argv[0] = command; 2413938Sjbeck 2423938Sjbeck rc = start_childv(command, argv); 2433938Sjbeck free(argv); 2443938Sjbeck 2453938Sjbeck return (rc); 2463938Sjbeck } 2473938Sjbeck 2483938Sjbeck uint32_t timer_expire = TIMER_INFINITY; 2493938Sjbeck 2503938Sjbeck /* 2513938Sjbeck * Schedules a SIGALRM in delay seconds, unless one is already 2523938Sjbeck * scheduled sooner. If one is already scheduled later than 2533938Sjbeck * delay seconds from now, that one will be replaced. 2543938Sjbeck */ 2553938Sjbeck void 2563938Sjbeck start_timer(uint32_t now, uint32_t delay) 2573938Sjbeck { 2583938Sjbeck if (now + delay > timer_expire) 2593938Sjbeck return; 2603938Sjbeck 2613938Sjbeck timer_expire = now + delay; 2623938Sjbeck (void) alarm(delay); 2633938Sjbeck } 2643938Sjbeck 2653938Sjbeck void 2663938Sjbeck lookup_zonename(char *zonename, size_t zonesize) 2673938Sjbeck { 2683938Sjbeck zoneid_t zoneid = getzoneid(); 2693938Sjbeck 2703938Sjbeck if (getzonenamebyid(zoneid, zonename, zonesize) >= 0) 2713938Sjbeck return; 2723938Sjbeck syslog(LOG_ERR, "could not determine zone name"); 2733938Sjbeck (void) strlcpy(zonename, GLOBAL_ZONENAME, zonesize); 2743938Sjbeck } 275