/** BEGIN COPYRIGHT BLOCK * This Program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; version 2 of the License. * * This Program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA. * * In addition, as a special exception, Red Hat, Inc. gives You the additional * right to link the code of this Program with code not covered under the GNU * General Public License ("Non-GPL Code") and to distribute linked combinations * including the two, subject to the limitations in this paragraph. Non-GPL Code * permitted under this exception must only link to the code of this Program * through those well defined interfaces identified in the file named EXCEPTION * found in the source code files (the "Approved Interfaces"). The files of * Non-GPL Code may instantiate templates or use macros or inline functions from * the Approved Interfaces without causing the resulting work to be covered by * the GNU General Public License. Only Red Hat, Inc. may make changes or * additions to the list of Approved Interfaces. You must obey the GNU General * Public License in all respects for all of the Program code and other code used * in conjunction with the Program except the Non-GPL Code covered by this * exception. If you modify this file, you may extend this exception to your * version of the file, but you are not obligated to do so. If you do not wish to * provide this exception without modification, you must delete this exception * statement from your version and license this file solely under the GPL without * exception. * * * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. * Copyright (C) 2005 Red Hat, Inc. * All rights reserved. * END COPYRIGHT BLOCK **/ #ifdef HAVE_CONFIG_H # include #endif /* * Copyright (c) 1990, 1994 Regents of the University of Michigan. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of Michigan at Ann Arbor. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. */ #include #include #ifdef SVR4 #include #endif /* svr4 */ #include #ifndef _WIN32 #include #include #include #include #endif #include #ifdef LINUX #undef CTIME #endif #include "slap.h" #include "fe.h" #if defined(USE_SYSCONF) || defined(LINUX) #include #endif /* USE_SYSCONF */ int detach( int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *ports_info ) { #ifndef _WIN32 int i, sd; char *workingdir = 0; char *errorlog = 0; char *ptr = 0; char errorbuf[BUFSIZ]; extern char *config_get_errorlog(void); #endif #ifndef _WIN32 if ( should_detach ) { for ( i = 0; i < 5; i++ ) { #if defined( sunos5 ) switch ( fork1() ) { #else switch ( fork() ) { #endif case -1: sleep( 5 ); continue; case 0: break; default: _exit( 0 ); } break; } /* call this right after the fork, but before closing stdin */ if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, s_port, ports_info)) { return 1; } workingdir = config_get_workingdir(); if ( NULL == workingdir ) { errorlog = config_get_errorlog(); if ( NULL == errorlog ) { (void) chdir( "/" ); } else { if ((ptr = strrchr(errorlog, '/')) || (ptr = strrchr(errorlog, '\\'))) { *ptr = 0; } (void) chdir( errorlog ); config_set_workingdir(CONFIG_WORKINGDIR_ATTRIBUTE, errorlog, errorbuf, 1); slapi_ch_free_string(&errorlog); } } else { /* calling config_set_workingdir to check for validity of directory, don't apply */ if (config_set_workingdir(CONFIG_WORKINGDIR_ATTRIBUTE, workingdir, errorbuf, 0) == LDAP_OPERATIONS_ERROR) { return 1; } (void) chdir( workingdir ); slapi_ch_free_string(&workingdir); } if ( (sd = open( "/dev/null", O_RDWR )) == -1 ) { perror( "/dev/null" ); return 1; } (void) dup2( sd, 0 ); (void) dup2( sd, 1 ); (void) dup2( sd, 2 ); close( sd ); #ifdef USE_SETSID setsid(); #else /* USE_SETSID */ if ( (sd = open( "/dev/tty", O_RDWR )) != -1 ) { (void) ioctl( sd, TIOCNOTTY, NULL ); (void) close( sd ); } #endif /* USE_SETSID */ g_set_detached(1); } else { /* not detaching - call nss/ssl init */ if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, s_port, ports_info)) { return 1; } } (void) SIGNAL( SIGPIPE, SIG_IGN ); #endif /* _WIN32 */ return 0; } #ifndef _WIN32 /* * close all open files except stdin/out/err */ void close_all_files() { int i, nbits; #ifdef USE_SYSCONF nbits = sysconf( _SC_OPEN_MAX ); #else /* USE_SYSCONF */ nbits = getdtablesize(); #endif /* USE_SYSCONF */ for ( i = 3; i < nbits; i++ ) { close( i ); } } #endif /* !_WIN32 */ /* * There is no need to do anything on some platforms (NT) and not try to * raise fds on AIX. */ static void raise_process_fd_limits(void) { #if !defined(_WIN32) && !defined(AIX) struct rlimit rl, setrl; RLIM_TYPE curlim; slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); if ( slapdFrontendConfig->maxdescriptors < 0 ) { return; } /* * Try to set our file descriptor limit. Our basic strategy is: * 1) Try to set the soft limit and the hard limit if * necessary to match our maxdescriptors value. * 2) If that fails and our soft limit is less than our hard * limit, we try to raise it to match the hard. */ if ( getrlimit( RLIMIT_NOFILE, &rl ) != 0 ) { int oserr = errno; LDAPDebug( LDAP_DEBUG_ANY, "getrlimit of descriptor limit failed - error %d (%s)\n", oserr, slapd_system_strerror( oserr ), 0 ); return; } if ( rl.rlim_cur == slapdFrontendConfig->maxdescriptors ) { /* already correct */ return; } curlim = rl.rlim_cur; setrl = rl; /* struct copy */ setrl.rlim_cur = slapdFrontendConfig->maxdescriptors; /* don't lower the hard limit as it's irreversible */ if (setrl.rlim_cur > setrl.rlim_max) { setrl.rlim_max = setrl.rlim_cur; } if ( setrlimit( RLIMIT_NOFILE, &setrl ) != 0 && curlim < rl.rlim_max ) { setrl = rl; /* struct copy */ setrl.rlim_cur = setrl.rlim_max; if ( setrlimit( RLIMIT_NOFILE, &setrl ) != 0 ) { int oserr = errno; LDAPDebug( LDAP_DEBUG_ANY, "setrlimit of descriptor " "limit to %d failed - error %d (%s)\n", setrl.rlim_cur, oserr, slapd_system_strerror(oserr)); return; } } (void)getrlimit( RLIMIT_NOFILE, &rl ); LDAPDebug( LDAP_DEBUG_TRACE, "descriptor limit changed from %d to %d\n", curlim, rl.rlim_cur, 0 ); #endif /* !_WIN32 && !AIX */ } /* * Try to raise relevant per-process limits */ void raise_process_limits() { #if !defined(_WIN32) struct rlimit rl; raise_process_fd_limits(); #ifdef RLIMIT_DATA if (getrlimit(RLIMIT_DATA,&rl) == 0) { rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_DATA,&rl) != 0) { LDAPDebug(LDAP_DEBUG_TRACE,"setrlimit(RLIMIT_DATA) failed %d\n", errno,0,0); } } else { LDAPDebug(LDAP_DEBUG_TRACE,"getrlimit(RLIMIT_DATA) failed %d\n", errno,0,0); } #endif #ifdef RLIMIT_VMEM if (getrlimit(RLIMIT_VMEM,&rl) == 0) { rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_VMEM,&rl) != 0) { LDAPDebug(LDAP_DEBUG_TRACE,"setrlimit(RLIMIT_VMEM) failed %d\n", errno,0,0); } } else { LDAPDebug(LDAP_DEBUG_TRACE,"getrlimit(RLIMIT_VMEM) failed %d\n", errno,0,0); } #endif /* RLIMIT_VMEM */ #endif /* !_WIN32 */ }