10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*249Sjwahlig * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 320Sstevel@tonic-gate * The Regents of the University of California 330Sstevel@tonic-gate * All Rights Reserved 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 360Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 370Sstevel@tonic-gate * contributors. 380Sstevel@tonic-gate */ 390Sstevel@tonic-gate 400Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 410Sstevel@tonic-gate 420Sstevel@tonic-gate #include <stdio.h> 430Sstevel@tonic-gate #include <stdlib.h> 440Sstevel@tonic-gate #include <ftw.h> 450Sstevel@tonic-gate #include <signal.h> 460Sstevel@tonic-gate #include <string.h> 470Sstevel@tonic-gate #include <syslog.h> 480Sstevel@tonic-gate #include <netconfig.h> 490Sstevel@tonic-gate #include <unistd.h> 500Sstevel@tonic-gate #include <netdb.h> 510Sstevel@tonic-gate #include <rpc/rpc.h> 520Sstevel@tonic-gate #include <netinet/in.h> 530Sstevel@tonic-gate #include <sys/param.h> 540Sstevel@tonic-gate #include <sys/resource.h> 550Sstevel@tonic-gate #include <sys/file.h> 560Sstevel@tonic-gate #include <sys/types.h> 570Sstevel@tonic-gate #include <sys/stat.h> 580Sstevel@tonic-gate #include <sys/sockio.h> 590Sstevel@tonic-gate #include <dirent.h> 600Sstevel@tonic-gate #include <errno.h> 610Sstevel@tonic-gate #include <rpcsvc/sm_inter.h> 620Sstevel@tonic-gate #include <rpcsvc/nsm_addr.h> 630Sstevel@tonic-gate #include <thread.h> 640Sstevel@tonic-gate #include <synch.h> 650Sstevel@tonic-gate #include <net/if.h> 660Sstevel@tonic-gate #include <limits.h> 670Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 680Sstevel@tonic-gate #include <priv_utils.h> 690Sstevel@tonic-gate #include "sm_statd.h" 700Sstevel@tonic-gate 710Sstevel@tonic-gate 720Sstevel@tonic-gate #define home0 "/var/statmon" 730Sstevel@tonic-gate #define current0 "/var/statmon/sm" 740Sstevel@tonic-gate #define backup0 "/var/statmon/sm.bak" 750Sstevel@tonic-gate #define state0 "/var/statmon/state" 760Sstevel@tonic-gate 770Sstevel@tonic-gate #define home1 "statmon" 780Sstevel@tonic-gate #define current1 "statmon/sm/" 790Sstevel@tonic-gate #define backup1 "statmon/sm.bak/" 800Sstevel@tonic-gate #define state1 "statmon/state" 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * User and group IDs to run as. These are hardwired, rather than looked 840Sstevel@tonic-gate * up at runtime, because they are very unlikely to change and because they 850Sstevel@tonic-gate * provide some protection against bogus changes to the passwd and group 860Sstevel@tonic-gate * files. 870Sstevel@tonic-gate */ 880Sstevel@tonic-gate 890Sstevel@tonic-gate char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN]; 900Sstevel@tonic-gate static char statd_home[MAXPATHLEN]; 910Sstevel@tonic-gate 920Sstevel@tonic-gate int debug; 930Sstevel@tonic-gate int regfiles_only = 0; /* 1 => use symlinks in statmon, 0 => don't */ 940Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN]; 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* 970Sstevel@tonic-gate * These variables will be used to store all the 980Sstevel@tonic-gate * alias names for the host, as well as the -a 990Sstevel@tonic-gate * command line hostnames. 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate int host_name_count; 1020Sstevel@tonic-gate char **host_name; /* store -a opts */ 1030Sstevel@tonic-gate int addrix; /* # of -a entries */ 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * The following 2 variables are meaningful 1080Sstevel@tonic-gate * only under a HA configuration. 1090Sstevel@tonic-gate * The path_name array is dynamically allocated in main() during 1100Sstevel@tonic-gate * command line argument processing for the -p options. 1110Sstevel@tonic-gate */ 1120Sstevel@tonic-gate char **path_name = NULL; /* store -p opts */ 1130Sstevel@tonic-gate int pathix = 0; /* # of -p entries */ 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate /* Global variables. Refer to sm_statd.h for description */ 1160Sstevel@tonic-gate mutex_t crash_lock; 1170Sstevel@tonic-gate int die; 1180Sstevel@tonic-gate int in_crash; 1190Sstevel@tonic-gate cond_t crash_finish; 1200Sstevel@tonic-gate mutex_t sm_trylock; 1210Sstevel@tonic-gate rwlock_t thr_rwlock; 1220Sstevel@tonic-gate cond_t retrywait; 1230Sstevel@tonic-gate mutex_t name_addrlock; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* forward references */ 1260Sstevel@tonic-gate static void set_statmon_owner(void); 1270Sstevel@tonic-gate static void copy_client_names(void); 1280Sstevel@tonic-gate static void one_statmon_owner(const char *); 1290Sstevel@tonic-gate static int nftw_owner(const char *, const struct stat *, int, struct FTW *); 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * statd protocol 1330Sstevel@tonic-gate * commands: 1340Sstevel@tonic-gate * SM_STAT 1350Sstevel@tonic-gate * returns stat_fail to caller 1360Sstevel@tonic-gate * SM_MON 1370Sstevel@tonic-gate * adds an entry to the monitor_q and the record_q 1380Sstevel@tonic-gate * This message is sent by the server lockd to the server 1390Sstevel@tonic-gate * statd, to indicate that a new client is to be monitored. 1400Sstevel@tonic-gate * It is also sent by the server lockd to the client statd 1410Sstevel@tonic-gate * to indicate that a new server is to be monitored. 1420Sstevel@tonic-gate * SM_UNMON 1430Sstevel@tonic-gate * removes an entry from the monitor_q and the record_q 1440Sstevel@tonic-gate * SM_UNMON_ALL 1450Sstevel@tonic-gate * removes all entries from a particular host from the 1460Sstevel@tonic-gate * monitor_q and the record_q. Our statd has this 1470Sstevel@tonic-gate * disabled. 1480Sstevel@tonic-gate * SM_SIMU_CRASH 1490Sstevel@tonic-gate * simulate a crash. removes everything from the 1500Sstevel@tonic-gate * record_q and the recovery_q, then calls statd_init() 1510Sstevel@tonic-gate * to restart things. This message is sent by the server 1520Sstevel@tonic-gate * lockd to the server statd to have all clients notified 1530Sstevel@tonic-gate * that they should reclaim locks. 1540Sstevel@tonic-gate * SM_NOTIFY 1550Sstevel@tonic-gate * Sent by statd on server to statd on client during 1560Sstevel@tonic-gate * crash recovery. The client statd passes the info 1570Sstevel@tonic-gate * to its lockd so it can attempt to reclaim the locks 1580Sstevel@tonic-gate * held on the server. 1590Sstevel@tonic-gate * 1600Sstevel@tonic-gate * There are three main hash tables used to keep track of things. 1610Sstevel@tonic-gate * mon_table 1620Sstevel@tonic-gate * table that keeps track hosts statd must watch. If one of 1630Sstevel@tonic-gate * these hosts crashes, then any locks held by that host must 1640Sstevel@tonic-gate * be released. 1650Sstevel@tonic-gate * record_table 1660Sstevel@tonic-gate * used to keep track of all the hostname files stored in 1670Sstevel@tonic-gate * the directory /var/statmon/sm. These are client hosts who 1680Sstevel@tonic-gate * are holding or have held a lock at some point. Needed 1690Sstevel@tonic-gate * to determine if a file needs to be created for host in 1700Sstevel@tonic-gate * /var/statmon/sm. 1710Sstevel@tonic-gate * recov_q 1720Sstevel@tonic-gate * used to keep track hostnames during a recovery 1730Sstevel@tonic-gate * 1740Sstevel@tonic-gate * The entries are hashed based upon the name. 1750Sstevel@tonic-gate * 1760Sstevel@tonic-gate * There is a directory /var/statmon/sm which holds a file named 1770Sstevel@tonic-gate * for each host that is holding (or has held) a lock. This is 1780Sstevel@tonic-gate * used during initialization on startup, or after a simulated 1790Sstevel@tonic-gate * crash. 1800Sstevel@tonic-gate */ 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate static void 1830Sstevel@tonic-gate sm_prog_1(rqstp, transp) 1840Sstevel@tonic-gate struct svc_req *rqstp; 1850Sstevel@tonic-gate SVCXPRT *transp; 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate union { 1880Sstevel@tonic-gate struct sm_name sm_stat_1_arg; 1890Sstevel@tonic-gate struct mon sm_mon_1_arg; 1900Sstevel@tonic-gate struct mon_id sm_unmon_1_arg; 1910Sstevel@tonic-gate struct my_id sm_unmon_all_1_arg; 1920Sstevel@tonic-gate struct stat_chge ntf_arg; 1930Sstevel@tonic-gate struct reg1args reg1_arg; 1940Sstevel@tonic-gate } argument; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate union { 1970Sstevel@tonic-gate sm_stat_res stat_resp; 1980Sstevel@tonic-gate sm_stat mon_resp; 1990Sstevel@tonic-gate struct reg1res reg1_resp; 2000Sstevel@tonic-gate } result; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate bool_t (*xdr_argument)(), (*xdr_result)(); 2030Sstevel@tonic-gate char *(*local)(); 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate /* 2060Sstevel@tonic-gate * Dispatch according to which protocol is being used: 2070Sstevel@tonic-gate * NSM_ADDR_PROGRAM is the private lockd address 2080Sstevel@tonic-gate * registration protocol. 2090Sstevel@tonic-gate * SM_PROG is the normal statd (NSM) protocol. 2100Sstevel@tonic-gate */ 2110Sstevel@tonic-gate if (rqstp->rq_prog == NSM_ADDR_PROGRAM) { 2120Sstevel@tonic-gate switch (rqstp->rq_proc) { 2130Sstevel@tonic-gate case NULLPROC: 2140Sstevel@tonic-gate svc_sendreply(transp, xdr_void, (caddr_t)NULL); 2150Sstevel@tonic-gate return; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate case NSMADDRPROC1_REG: 2180Sstevel@tonic-gate xdr_argument = xdr_reg1args; 2190Sstevel@tonic-gate xdr_result = xdr_reg1res; 2200Sstevel@tonic-gate local = (char *(*)()) nsmaddrproc1_reg; 2210Sstevel@tonic-gate break; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate default: 2240Sstevel@tonic-gate svcerr_noproc(transp); 2250Sstevel@tonic-gate return; 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate } else { 2280Sstevel@tonic-gate switch (rqstp->rq_proc) { 2290Sstevel@tonic-gate case NULLPROC: 2300Sstevel@tonic-gate svc_sendreply(transp, xdr_void, (caddr_t)NULL); 2310Sstevel@tonic-gate return; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate case SM_STAT: 2340Sstevel@tonic-gate xdr_argument = xdr_sm_name; 2350Sstevel@tonic-gate xdr_result = xdr_sm_stat_res; 2360Sstevel@tonic-gate local = (char *(*)()) sm_status; 2370Sstevel@tonic-gate break; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate case SM_MON: 2400Sstevel@tonic-gate xdr_argument = xdr_mon; 2410Sstevel@tonic-gate xdr_result = xdr_sm_stat_res; 2420Sstevel@tonic-gate local = (char *(*)()) sm_mon; 2430Sstevel@tonic-gate break; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate case SM_UNMON: 2460Sstevel@tonic-gate xdr_argument = xdr_mon_id; 2470Sstevel@tonic-gate xdr_result = xdr_sm_stat; 2480Sstevel@tonic-gate local = (char *(*)()) sm_unmon; 2490Sstevel@tonic-gate break; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate case SM_UNMON_ALL: 2520Sstevel@tonic-gate xdr_argument = xdr_my_id; 2530Sstevel@tonic-gate xdr_result = xdr_sm_stat; 2540Sstevel@tonic-gate local = (char *(*)()) sm_unmon_all; 2550Sstevel@tonic-gate break; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate case SM_SIMU_CRASH: 2580Sstevel@tonic-gate xdr_argument = xdr_void; 2590Sstevel@tonic-gate xdr_result = xdr_void; 2600Sstevel@tonic-gate local = (char *(*)()) sm_simu_crash; 2610Sstevel@tonic-gate break; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate case SM_NOTIFY: 2640Sstevel@tonic-gate xdr_argument = xdr_stat_chge; 2650Sstevel@tonic-gate xdr_result = xdr_void; 2660Sstevel@tonic-gate local = (char *(*)()) sm_notify; 2670Sstevel@tonic-gate break; 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate default: 2700Sstevel@tonic-gate svcerr_noproc(transp); 2710Sstevel@tonic-gate return; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate (void) memset(&argument, 0, sizeof (argument)); 2760Sstevel@tonic-gate if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 2770Sstevel@tonic-gate svcerr_decode(transp); 2780Sstevel@tonic-gate return; 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate (void) memset(&result, 0, sizeof (result)); 2820Sstevel@tonic-gate (*local)(&argument, &result); 2830Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_result, (caddr_t)&result)) { 2840Sstevel@tonic-gate svcerr_systemerr(transp); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 2880Sstevel@tonic-gate syslog(LOG_ERR, "statd: unable to free arguments\n"); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate /* 2930Sstevel@tonic-gate * Remove all files under directory path_dir. 2940Sstevel@tonic-gate */ 2950Sstevel@tonic-gate static int 2960Sstevel@tonic-gate remove_dir(path_dir) 2970Sstevel@tonic-gate char *path_dir; 2980Sstevel@tonic-gate { 2990Sstevel@tonic-gate DIR *dp; 3000Sstevel@tonic-gate struct dirent *dirp, *entp; 3010Sstevel@tonic-gate char tmp_path[MAXPATHLEN]; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if ((dp = opendir(path_dir)) == (DIR *)NULL) { 3040Sstevel@tonic-gate if (debug) 3050Sstevel@tonic-gate syslog(LOG_ERR, 3060Sstevel@tonic-gate "warning: open directory %s failed: %m\n", path_dir); 3070Sstevel@tonic-gate return (1); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate entp = (struct dirent *)xmalloc(MAXDIRENT); 3110Sstevel@tonic-gate if (entp == NULL) { 3120Sstevel@tonic-gate (void) closedir(dp); 3130Sstevel@tonic-gate return (1); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate while ((dirp = readdir_r(dp, entp)) != (struct dirent *)NULL) { 3170Sstevel@tonic-gate if (strcmp(dirp->d_name, ".") != 0 && 3180Sstevel@tonic-gate strcmp(dirp->d_name, "..") != 0) { 3190Sstevel@tonic-gate if (strlen(path_dir) + strlen(dirp->d_name) +2 > 3200Sstevel@tonic-gate MAXPATHLEN) { 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate syslog(LOG_ERR, 3230Sstevel@tonic-gate "statd: remove dir %s/%s failed. Pathname too long.\n", 3240Sstevel@tonic-gate path_dir, dirp->d_name); 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate continue; 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate (void) strcpy(tmp_path, path_dir); 3290Sstevel@tonic-gate (void) strcat(tmp_path, "/"); 3300Sstevel@tonic-gate (void) strcat(tmp_path, dirp->d_name); 3310Sstevel@tonic-gate delete_file(tmp_path); 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate free(entp); 3360Sstevel@tonic-gate (void) closedir(dp); 3370Sstevel@tonic-gate return (0); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate /* 3410Sstevel@tonic-gate * Copy all files from directory `from_dir' to directory `to_dir'. 3420Sstevel@tonic-gate * Symlinks, if any, are preserved. 3430Sstevel@tonic-gate */ 3440Sstevel@tonic-gate void 3450Sstevel@tonic-gate copydir_from_to(from_dir, to_dir) 3460Sstevel@tonic-gate char *from_dir; 3470Sstevel@tonic-gate char *to_dir; 3480Sstevel@tonic-gate { 3490Sstevel@tonic-gate int n; 3500Sstevel@tonic-gate DIR *dp; 3510Sstevel@tonic-gate struct dirent *dirp, *entp; 3520Sstevel@tonic-gate char rname[MAXNAMELEN + 1]; 3530Sstevel@tonic-gate char path[MAXPATHLEN+MAXNAMELEN+2]; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate if ((dp = opendir(from_dir)) == (DIR *)NULL) { 3560Sstevel@tonic-gate if (debug) 3570Sstevel@tonic-gate syslog(LOG_ERR, 3580Sstevel@tonic-gate "warning: open directory %s failed: %m\n", from_dir); 3590Sstevel@tonic-gate return; 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate entp = (struct dirent *)xmalloc(MAXDIRENT); 3630Sstevel@tonic-gate if (entp == NULL) { 3640Sstevel@tonic-gate (void) closedir(dp); 3650Sstevel@tonic-gate return; 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate while ((dirp = readdir_r(dp, entp)) != (struct dirent *)NULL) { 3690Sstevel@tonic-gate if (strcmp(dirp->d_name, ".") == 0 || 3700Sstevel@tonic-gate strcmp(dirp->d_name, "..") == 0) { 3710Sstevel@tonic-gate continue; 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate (void) strcpy(path, from_dir); 3750Sstevel@tonic-gate (void) strcat(path, "/"); 3760Sstevel@tonic-gate (void) strcat(path, dirp->d_name); 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate if (is_symlink(path)) { 3790Sstevel@tonic-gate /* 3800Sstevel@tonic-gate * Follow the link to get the referenced file name 3810Sstevel@tonic-gate * and make a new link for that file in to_dir. 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate n = readlink(path, rname, MAXNAMELEN); 3840Sstevel@tonic-gate if (n <= 0) { 3850Sstevel@tonic-gate if (debug >= 2) { 3860Sstevel@tonic-gate (void) printf( 3870Sstevel@tonic-gate "copydir_from_to: can't read link %s\n", 3880Sstevel@tonic-gate path); 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate continue; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate rname[n] = '\0'; 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate (void) create_symlink(to_dir, rname, dirp->d_name); 3950Sstevel@tonic-gate } else { 3960Sstevel@tonic-gate /* 3970Sstevel@tonic-gate * Simply copy regular files to to_dir. 3980Sstevel@tonic-gate */ 3990Sstevel@tonic-gate (void) strcpy(path, to_dir); 4000Sstevel@tonic-gate (void) strcat(path, "/"); 4010Sstevel@tonic-gate (void) strcat(path, dirp->d_name); 4020Sstevel@tonic-gate (void) create_file(path); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate free(entp); 4070Sstevel@tonic-gate (void) closedir(dp); 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate static int 4110Sstevel@tonic-gate init_hostname(void) 4120Sstevel@tonic-gate { 4130Sstevel@tonic-gate struct lifnum lifn; 4140Sstevel@tonic-gate int sock; 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 4170Sstevel@tonic-gate syslog(LOG_ERR, "statd:init_hostname, socket: %m"); 4180Sstevel@tonic-gate return (-1); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC; 4220Sstevel@tonic-gate lifn.lifn_flags = 0; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 4250Sstevel@tonic-gate syslog(LOG_ERR, 4260Sstevel@tonic-gate "statd:init_hostname, get number of interfaces, error: %m"); 4270Sstevel@tonic-gate close(sock); 4280Sstevel@tonic-gate return (-1); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate host_name_count = lifn.lifn_count; 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate host_name = (char **)malloc(host_name_count * sizeof (char *)); 4340Sstevel@tonic-gate if (host_name == NULL) { 4350Sstevel@tonic-gate perror("statd -a can't get ip configuration\n"); 4360Sstevel@tonic-gate close(sock); 4370Sstevel@tonic-gate return (-1); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate close(sock); 4400Sstevel@tonic-gate return (0); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 443*249Sjwahlig int 444*249Sjwahlig main(int argc, char *argv[]) 4450Sstevel@tonic-gate { 4460Sstevel@tonic-gate int c; 4470Sstevel@tonic-gate int ppid; 4480Sstevel@tonic-gate extern char *optarg; 4490Sstevel@tonic-gate int choice = 0; 4500Sstevel@tonic-gate struct rlimit rl; 4510Sstevel@tonic-gate int mode; 4520Sstevel@tonic-gate int sz; 4530Sstevel@tonic-gate int connmaxrec = RPC_MAXDATASIZE; 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate addrix = 0; 4560Sstevel@tonic-gate pathix = 0; 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate (void) gethostname(hostname, MAXHOSTNAMELEN); 4590Sstevel@tonic-gate if (init_hostname() < 0) 4600Sstevel@tonic-gate exit(1); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate while ((c = getopt(argc, argv, "Dd:a:p:r")) != EOF) 4630Sstevel@tonic-gate switch (c) { 4640Sstevel@tonic-gate case 'd': 4650Sstevel@tonic-gate (void) sscanf(optarg, "%d", &debug); 4660Sstevel@tonic-gate break; 4670Sstevel@tonic-gate case 'D': 4680Sstevel@tonic-gate choice = 1; 4690Sstevel@tonic-gate break; 4700Sstevel@tonic-gate case 'a': 4710Sstevel@tonic-gate if (addrix < host_name_count) { 4720Sstevel@tonic-gate if (strcmp(hostname, optarg) != 0) { 4730Sstevel@tonic-gate sz = strlen(optarg); 4740Sstevel@tonic-gate if (sz < MAXHOSTNAMELEN) { 4750Sstevel@tonic-gate host_name[addrix] = 4760Sstevel@tonic-gate (char *)xmalloc(sz+1); 4770Sstevel@tonic-gate if (host_name[addrix] != 4780Sstevel@tonic-gate NULL) { 4790Sstevel@tonic-gate (void) sscanf(optarg, "%s", 4800Sstevel@tonic-gate host_name[addrix]); 4810Sstevel@tonic-gate addrix++; 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate } else 4840Sstevel@tonic-gate (void) fprintf(stderr, 4850Sstevel@tonic-gate "statd: -a name of host is too long.\n"); 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate } else 4880Sstevel@tonic-gate (void) fprintf(stderr, 4890Sstevel@tonic-gate "statd: -a exceeding maximum hostnames\n"); 4900Sstevel@tonic-gate break; 4910Sstevel@tonic-gate case 'p': 4920Sstevel@tonic-gate if (strlen(optarg) < MAXPATHLEN) { 4930Sstevel@tonic-gate /* If the path_name array has not yet */ 4940Sstevel@tonic-gate /* been malloc'ed, do that. The array */ 4950Sstevel@tonic-gate /* should be big enough to hold all of the */ 4960Sstevel@tonic-gate /* -p options we might have. An upper */ 4970Sstevel@tonic-gate /* bound on the number of -p options is */ 4980Sstevel@tonic-gate /* argc/2, because each -p option consumes */ 4990Sstevel@tonic-gate /* two arguments. Here the upper bound */ 5000Sstevel@tonic-gate /* is supposing that all the command line */ 5010Sstevel@tonic-gate /* arguments are -p options, which would */ 5020Sstevel@tonic-gate /* actually never be the case. */ 5030Sstevel@tonic-gate if (path_name == NULL) { 5040Sstevel@tonic-gate size_t sz = (argc/2) * sizeof (char *); 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate path_name = (char **)malloc(sz); 5070Sstevel@tonic-gate if (path_name == NULL) { 5080Sstevel@tonic-gate (void) fprintf(stderr, 5090Sstevel@tonic-gate "statd: malloc failed\n"); 5100Sstevel@tonic-gate exit(1); 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate (void) memset(path_name, 0, sz); 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate path_name[pathix] = optarg; 5150Sstevel@tonic-gate pathix++; 5160Sstevel@tonic-gate } else { 5170Sstevel@tonic-gate (void) fprintf(stderr, 5180Sstevel@tonic-gate "statd: -p pathname is too long.\n"); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate break; 5210Sstevel@tonic-gate case 'r': 5220Sstevel@tonic-gate regfiles_only = 1; 5230Sstevel@tonic-gate break; 5240Sstevel@tonic-gate default: 5250Sstevel@tonic-gate (void) fprintf(stderr, 5260Sstevel@tonic-gate "statd [-d level] [-D]\n"); 5270Sstevel@tonic-gate return (1); 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate if (choice == 0) { 5310Sstevel@tonic-gate (void) strcpy(statd_home, home0); 5320Sstevel@tonic-gate (void) strcpy(CURRENT, current0); 5330Sstevel@tonic-gate (void) strcpy(BACKUP, backup0); 5340Sstevel@tonic-gate (void) strcpy(STATE, state0); 5350Sstevel@tonic-gate } else { 5360Sstevel@tonic-gate (void) strcpy(statd_home, home1); 5370Sstevel@tonic-gate (void) strcpy(CURRENT, current1); 5380Sstevel@tonic-gate (void) strcpy(BACKUP, backup1); 5390Sstevel@tonic-gate (void) strcpy(STATE, state1); 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate if (debug) 5420Sstevel@tonic-gate (void) printf("debug is on, create entry: %s, %s, %s\n", 5430Sstevel@tonic-gate CURRENT, BACKUP, STATE); 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl)) 5460Sstevel@tonic-gate (void) printf("statd: getrlimit failed. \n"); 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate /* Set maxfdlimit current soft limit */ 5490Sstevel@tonic-gate rl.rlim_cur = MAX_FDS; 5500Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) != 0) 5510Sstevel@tonic-gate syslog(LOG_ERR, "statd: unable to set RLIMIT_NOFILE to %d\n", 5520Sstevel@tonic-gate MAX_FDS); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate if (!debug) { 5550Sstevel@tonic-gate ppid = fork(); 5560Sstevel@tonic-gate if (ppid == -1) { 5570Sstevel@tonic-gate (void) fprintf(stderr, "statd: fork failure\n"); 5580Sstevel@tonic-gate (void) fflush(stderr); 5590Sstevel@tonic-gate abort(); 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate if (ppid != 0) { 5620Sstevel@tonic-gate exit(0); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate closefrom(0); 5650Sstevel@tonic-gate (void) open("/dev/null", O_RDONLY); 5660Sstevel@tonic-gate (void) open("/dev/null", O_WRONLY); 5670Sstevel@tonic-gate (void) dup(1); 5680Sstevel@tonic-gate (void) setsid(); 5690Sstevel@tonic-gate openlog("statd", LOG_PID, LOG_DAEMON); 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate (void) _create_daemon_lock(STATD, DAEMON_UID, DAEMON_GID); 5730Sstevel@tonic-gate /* 5740Sstevel@tonic-gate * establish our lock on the lock file and write our pid to it. 5750Sstevel@tonic-gate * exit if some other process holds the lock, or if there's any 5760Sstevel@tonic-gate * error in writing/locking the file. 5770Sstevel@tonic-gate */ 5780Sstevel@tonic-gate ppid = _enter_daemon_lock(STATD); 5790Sstevel@tonic-gate switch (ppid) { 5800Sstevel@tonic-gate case 0: 5810Sstevel@tonic-gate break; 5820Sstevel@tonic-gate case -1: 5830Sstevel@tonic-gate syslog(LOG_ERR, "error locking for %s: %s", STATD, 5840Sstevel@tonic-gate strerror(errno)); 5850Sstevel@tonic-gate exit(2); 5860Sstevel@tonic-gate default: 5870Sstevel@tonic-gate /* daemon was already running */ 5880Sstevel@tonic-gate exit(0); 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate /* Get other aliases from each interface. */ 5920Sstevel@tonic-gate merge_hosts(); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * Set to automatic mode such that threads are automatically 5960Sstevel@tonic-gate * created 5970Sstevel@tonic-gate */ 5980Sstevel@tonic-gate mode = RPC_SVC_MT_AUTO; 5990Sstevel@tonic-gate if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) { 6000Sstevel@tonic-gate syslog(LOG_ERR, 6010Sstevel@tonic-gate "statd:unable to set automatic MT mode."); 6020Sstevel@tonic-gate exit(1); 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate /* 6060Sstevel@tonic-gate * Set non-blocking mode and maximum record size for 6070Sstevel@tonic-gate * connection oriented RPC transports. 6080Sstevel@tonic-gate */ 6090Sstevel@tonic-gate if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { 6100Sstevel@tonic-gate syslog(LOG_INFO, "unable to set maximum RPC record size"); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) { 6140Sstevel@tonic-gate syslog(LOG_ERR, 6150Sstevel@tonic-gate "statd: unable to create (SM_PROG, SM_VERS) for netpath."); 6160Sstevel@tonic-gate exit(1); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) { 6200Sstevel@tonic-gate syslog(LOG_ERR, 6210Sstevel@tonic-gate "statd: unable to create (NSM_ADDR_PROGRAM, NSM_ADDR_V1) for netpath."); 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* 6250Sstevel@tonic-gate * Make sure /var/statmon and any alternate (-p) statmon 6260Sstevel@tonic-gate * directories exist and are owned by daemon. Then change our uid 6270Sstevel@tonic-gate * to daemon. The uid change is to prevent attacks against local 6280Sstevel@tonic-gate * daemons that trust any call from a local root process. 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate set_statmon_owner(); 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate /* 6340Sstevel@tonic-gate * 6350Sstevel@tonic-gate * statd now runs as a daemon rather than root and can not 6360Sstevel@tonic-gate * dump core under / because of the permission. It is 6370Sstevel@tonic-gate * important that current working directory of statd be 6380Sstevel@tonic-gate * changed to writable directory /var/statmon so that it 6390Sstevel@tonic-gate * can dump the core upon the receipt of the signal. 6400Sstevel@tonic-gate * One still need to set allow_setid_core to non-zero in 6410Sstevel@tonic-gate * /etc/system to get the core dump. 6420Sstevel@tonic-gate * 6430Sstevel@tonic-gate */ 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate if (chdir(statd_home) < 0) { 6460Sstevel@tonic-gate syslog(LOG_ERR, "can't chdir %s: %m", statd_home); 6470Sstevel@tonic-gate exit(1); 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate copy_client_names(); 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate rwlock_init(&thr_rwlock, USYNC_THREAD, NULL); 6530Sstevel@tonic-gate mutex_init(&crash_lock, USYNC_THREAD, NULL); 6540Sstevel@tonic-gate mutex_init(&name_addrlock, USYNC_THREAD, NULL); 6550Sstevel@tonic-gate cond_init(&crash_finish, USYNC_THREAD, NULL); 6560Sstevel@tonic-gate cond_init(&retrywait, USYNC_THREAD, NULL); 6570Sstevel@tonic-gate sm_inithash(); 6580Sstevel@tonic-gate die = 0; 6590Sstevel@tonic-gate /* 6600Sstevel@tonic-gate * This variable is set to ensure that an sm_crash 6610Sstevel@tonic-gate * request will not be done at the same time 6620Sstevel@tonic-gate * when a statd_init is being done, since sm_crash 6630Sstevel@tonic-gate * can reset some variables that statd_init will be using. 6640Sstevel@tonic-gate */ 6650Sstevel@tonic-gate in_crash = 1; 6660Sstevel@tonic-gate statd_init(); 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate if (debug) 6690Sstevel@tonic-gate (void) printf("Starting svc_run\n"); 6700Sstevel@tonic-gate svc_run(); 6710Sstevel@tonic-gate syslog(LOG_ERR, "statd: svc_run returned\n"); 6720Sstevel@tonic-gate /* NOTREACHED */ 6730Sstevel@tonic-gate thr_exit((void *) 1); 674*249Sjwahlig return (0); 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate /* 6790Sstevel@tonic-gate * Make sure the ownership of the statmon directories is correct, then 6800Sstevel@tonic-gate * change our uid to match. If the top-level directories (/var/statmon, -p 6810Sstevel@tonic-gate * arguments) don't exist, they are created first. The sm and sm.bak 6820Sstevel@tonic-gate * directories are not created here, but if they already exist, they are 6830Sstevel@tonic-gate * chowned to the correct uid, along with anything else in the 6840Sstevel@tonic-gate * directories. 6850Sstevel@tonic-gate */ 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate static void 6880Sstevel@tonic-gate set_statmon_owner() 6890Sstevel@tonic-gate { 6900Sstevel@tonic-gate int i; 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate /* 6930Sstevel@tonic-gate * Recursively chown/chgrp /var/statmon and the alternate paths, 6940Sstevel@tonic-gate * creating them if necessary. 6950Sstevel@tonic-gate */ 6960Sstevel@tonic-gate one_statmon_owner(statd_home); 6970Sstevel@tonic-gate for (i = 0; i < pathix; i++) { 6980Sstevel@tonic-gate char alt_path[MAXPATHLEN]; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate snprintf(alt_path, MAXPATHLEN, "%s/statmon", path_name[i]); 7010Sstevel@tonic-gate one_statmon_owner(alt_path); 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 7050Sstevel@tonic-gate DAEMON_UID, DAEMON_GID, (char *)NULL) == -1) { 7060Sstevel@tonic-gate syslog(LOG_ERR, "can't run unprivileged: %m"); 7070Sstevel@tonic-gate exit(1); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION, 7110Sstevel@tonic-gate PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate /* 7150Sstevel@tonic-gate * Copy client names from the alternate statmon directories into 7160Sstevel@tonic-gate * /var/statmon. The top-level (statmon) directories should already 7170Sstevel@tonic-gate * exist, though the sm and sm.bak directories might not. 7180Sstevel@tonic-gate */ 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate static void 7210Sstevel@tonic-gate copy_client_names() 7220Sstevel@tonic-gate { 7230Sstevel@tonic-gate int i; 7240Sstevel@tonic-gate char buf[MAXPATHLEN+SM_MAXPATHLEN]; 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate /* 7270Sstevel@tonic-gate * Copy all clients from alternate paths to /var/statmon/sm 7280Sstevel@tonic-gate * Remove the files in alternate directory when copying is done. 7290Sstevel@tonic-gate */ 7300Sstevel@tonic-gate for (i = 0; i < pathix; i++) { 7310Sstevel@tonic-gate /* 7320Sstevel@tonic-gate * If the alternate directories do not exist, create it. 7330Sstevel@tonic-gate * If they do exist, just do the copy. 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate snprintf(buf, sizeof (buf), "%s/statmon/sm", path_name[i]); 7360Sstevel@tonic-gate if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) { 7370Sstevel@tonic-gate if (errno != EEXIST) { 7380Sstevel@tonic-gate syslog(LOG_ERR, 7390Sstevel@tonic-gate "can't mkdir %s: %m\n", buf); 7400Sstevel@tonic-gate continue; 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate copydir_from_to(buf, CURRENT); 7430Sstevel@tonic-gate (void) remove_dir(buf); 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s/statmon/sm.bak", 7470Sstevel@tonic-gate path_name[i]); 7480Sstevel@tonic-gate if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) { 7490Sstevel@tonic-gate if (errno != EEXIST) { 7500Sstevel@tonic-gate syslog(LOG_ERR, 7510Sstevel@tonic-gate "can't mkdir %s: %m\n", buf); 7520Sstevel@tonic-gate continue; 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate copydir_from_to(buf, BACKUP); 7550Sstevel@tonic-gate (void) remove_dir(buf); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * Create the given directory if it doesn't already exist. Set the user 7620Sstevel@tonic-gate * and group to daemon for the directory and anything under it. 7630Sstevel@tonic-gate */ 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate static void 7660Sstevel@tonic-gate one_statmon_owner(const char *dir) 7670Sstevel@tonic-gate { 7680Sstevel@tonic-gate if ((mkdir(dir, SM_DIRECTORY_MODE)) == -1) { 7690Sstevel@tonic-gate if (errno != EEXIST) { 7700Sstevel@tonic-gate syslog(LOG_ERR, "can't mkdir %s: %m", 7710Sstevel@tonic-gate dir); 7720Sstevel@tonic-gate return; 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate if (debug) 7770Sstevel@tonic-gate printf("Setting owner for %s\n", dir); 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate if (nftw(dir, nftw_owner, MAX_FDS, FTW_PHYS) != 0) { 7800Sstevel@tonic-gate syslog(LOG_WARNING, "error setting owner for %s: %m", 7810Sstevel@tonic-gate dir); 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate /* 7860Sstevel@tonic-gate * Set the user and group to daemon for the given file or directory. If 7870Sstevel@tonic-gate * it's a directory, also makes sure that it is mode 755. 7880Sstevel@tonic-gate * Generates a syslog message but does not return an error if there were 7890Sstevel@tonic-gate * problems. 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /*ARGSUSED3*/ 7930Sstevel@tonic-gate static int 7940Sstevel@tonic-gate nftw_owner(const char *path, const struct stat *statp, int info, 7950Sstevel@tonic-gate struct FTW *ftw) 7960Sstevel@tonic-gate { 7970Sstevel@tonic-gate if (!(info == FTW_F || info == FTW_D)) 7980Sstevel@tonic-gate return (0); 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate /* 8010Sstevel@tonic-gate * Some older systems might have mode 777 directories. Fix that. 8020Sstevel@tonic-gate */ 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate if (info == FTW_D && (statp->st_mode & (S_IWGRP | S_IWOTH)) != 0) { 8050Sstevel@tonic-gate mode_t newmode = (statp->st_mode & ~(S_IWGRP | S_IWOTH)) & 8060Sstevel@tonic-gate S_IAMB; 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate if (debug) 8090Sstevel@tonic-gate printf("chmod %03o %s\n", newmode, path); 8100Sstevel@tonic-gate if (chmod(path, newmode) < 0) { 8110Sstevel@tonic-gate int error = errno; 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate syslog(LOG_WARNING, "can't chmod %s to %03o: %m", 8140Sstevel@tonic-gate path, newmode); 8150Sstevel@tonic-gate if (debug) 8160Sstevel@tonic-gate printf(" FAILED: %s\n", strerror(error)); 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate /* If already owned by daemon, don't bother changing. */ 8210Sstevel@tonic-gate if (statp->st_uid == DAEMON_UID && 8220Sstevel@tonic-gate statp->st_gid == DAEMON_GID) 8230Sstevel@tonic-gate return (0); 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate if (debug) 8260Sstevel@tonic-gate printf("lchown %s daemon:daemon\n", path); 8270Sstevel@tonic-gate if (lchown(path, DAEMON_UID, DAEMON_GID) < 0) { 8280Sstevel@tonic-gate int error = errno; 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate syslog(LOG_WARNING, "can't chown %s to daemon: %m", 8310Sstevel@tonic-gate path); 8320Sstevel@tonic-gate if (debug) 8330Sstevel@tonic-gate printf(" FAILED: %s\n", strerror(error)); 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate return (0); 8370Sstevel@tonic-gate } 838