added qse_get_highest_fd(), qse_close_open_fds_using_proc()
added QSE::AppRoot::daemonize()
This commit is contained in:
		
							
								
								
									
										56
									
								
								qse/include/qse/si/AppRoot.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								qse/include/qse/si/AppRoot.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| /* | ||||
|  * $Id$ | ||||
|  * | ||||
|     Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. | ||||
|  | ||||
|     Redistribution and use in source and binary forms, with or without | ||||
|     modification, are permitted provided that the following conditions | ||||
|     are met: | ||||
|     1. Redistributions of source code must retain the above copyright | ||||
|        notice, this list of conditions and the following disclaimer. | ||||
|     2. Redistributions in binary form must reproduce the above copyright | ||||
|        notice, this list of conditions and the following disclaimer in the | ||||
|        documentation and/or other materials provided with the distribution. | ||||
|  | ||||
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | ||||
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
|  | ||||
| #ifndef _QSE_SI_APPROOT_H_ | ||||
| #define _QSE_SI_APPROOT_H_ | ||||
|  | ||||
| #include <qse/Types.hpp> | ||||
| #include <qse/Uncopyable.hpp> | ||||
|  | ||||
| ///////////////////////////////// | ||||
| QSE_BEGIN_NAMESPACE(QSE) | ||||
| ///////////////////////////////// | ||||
|  | ||||
| class AppRoot: QSE::Uncopyable | ||||
| { | ||||
| public: | ||||
| 	AppRoot (): _root_only (false) {} | ||||
| 	virtual ~AppRoot () {} | ||||
|  | ||||
| 	int daemonize (bool chdir_to_root = true, int fork_count = 1) QSE_CPP_NOEXCEPT; | ||||
|  | ||||
| protected: | ||||
| 	bool _root_only; | ||||
|  | ||||
| 	 | ||||
| 	void on_signal () QSE_CPP_NOEXCEPT; | ||||
| }; | ||||
|  | ||||
| ///////////////////////////////// | ||||
| QSE_END_NAMESPACE(QSE) | ||||
| ///////////////////////////////// | ||||
|  | ||||
| #endif | ||||
| @ -19,6 +19,7 @@ pkginclude_HEADERS = \ | ||||
| 	pio.h  \ | ||||
| 	rwl.h \ | ||||
| 	sck.h \ | ||||
| 	sinfo.h \ | ||||
| 	sio.h  \ | ||||
| 	task.h \ | ||||
| 	thr.h \ | ||||
| @ -26,6 +27,7 @@ pkginclude_HEADERS = \ | ||||
|  | ||||
| if ENABLE_CXX | ||||
| pkginclude_HEADERS += \ | ||||
| 	AppRoot.hpp \ | ||||
| 	SocketAddress.hpp \ | ||||
| 	Socket.hpp | ||||
| endif | ||||
|  | ||||
| @ -88,6 +88,7 @@ POST_UNINSTALL = : | ||||
| build_triplet = @build@ | ||||
| host_triplet = @host@ | ||||
| @ENABLE_CXX_TRUE@am__append_1 = \ | ||||
| @ENABLE_CXX_TRUE@	AppRoot.hpp \ | ||||
| @ENABLE_CXX_TRUE@	SocketAddress.hpp \ | ||||
| @ENABLE_CXX_TRUE@	Socket.hpp | ||||
|  | ||||
| @ -130,8 +131,8 @@ am__can_run_installinfo = \ | ||||
|   esac | ||||
| am__pkginclude_HEADERS_DIST = aio.h aio-pro.h aio-sck.h cnd.h dir.h \ | ||||
| 	fio.h fs.h glob.h intr.h log.h mtx.h mux.h nwad.h nwif.h \ | ||||
| 	nwio.h pio.h rwl.h sck.h sio.h task.h thr.h tio.h \ | ||||
| 	SocketAddress.hpp Socket.hpp | ||||
| 	nwio.h pio.h rwl.h sck.h sinfo.h sio.h task.h thr.h tio.h \ | ||||
| 	AppRoot.hpp SocketAddress.hpp Socket.hpp | ||||
| am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; | ||||
| am__vpath_adj = case $$p in \ | ||||
|     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ | ||||
| @ -366,7 +367,7 @@ top_builddir = @top_builddir@ | ||||
| top_srcdir = @top_srcdir@ | ||||
| pkginclude_HEADERS = aio.h aio-pro.h aio-sck.h cnd.h dir.h fio.h fs.h \ | ||||
| 	glob.h intr.h log.h mtx.h mux.h nwad.h nwif.h nwio.h pio.h \ | ||||
| 	rwl.h sck.h sio.h task.h thr.h tio.h $(am__append_1) | ||||
| 	rwl.h sck.h sinfo.h sio.h task.h thr.h tio.h $(am__append_1) | ||||
| all: all-am | ||||
|  | ||||
| .SUFFIXES: | ||||
|  | ||||
							
								
								
									
										49
									
								
								qse/include/qse/si/sinfo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								qse/include/qse/si/sinfo.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| /* | ||||
|  * $Id$ | ||||
|  * | ||||
|     Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. | ||||
|  | ||||
|     Redistribution and use in source and binary forms, with or without | ||||
|     modification, are permitted provided that the following conditions | ||||
|     are met: | ||||
|     1. Redistributions of source code must retain the above copyright | ||||
|        notice, this list of conditions and the following disclaimer. | ||||
|     2. Redistributions in binary form must reproduce the above copyright | ||||
|        notice, this list of conditions and the following disclaimer in the | ||||
|        documentation and/or other materials provided with the distribution. | ||||
|  | ||||
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | ||||
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
|  | ||||
| #ifndef _QSE_SI_SINFO_H_ | ||||
| #define _QSE_SI_SINFO_H_ | ||||
|  | ||||
| #include <qse/types.h> | ||||
| #include <qse/macros.h> | ||||
|  | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| QSE_EXPORT int qse_get_highest_fd (void); | ||||
|  | ||||
| QSE_EXPORT int qse_close_open_fds_using_proc ( | ||||
| 	int* excepts, | ||||
| 	qse_size_t count | ||||
| ); | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @ -69,6 +69,9 @@ | ||||
| #if defined(HAVE_DIRENT_H) | ||||
| #	include <dirent.h> | ||||
| #endif | ||||
| #if defined(HAVE_SYS_IOCTL_H) | ||||
| #	include <sys/ioctl.h> | ||||
| #endif | ||||
|  | ||||
| #if defined(QSE_USE_SYSCALL) && defined(HAVE_SYS_SYSCALL_H) | ||||
| #	include <sys/syscall.h> | ||||
| @ -214,6 +217,24 @@ | ||||
| #	define QSE_GETEGID() getegid() | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_getsid) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_GETSID(pid) syscall(SYS_getsid,pid) | ||||
| #else | ||||
| #	define QSE_GETSID(pid) getsid(pid) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_setsid) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_SETSID() syscall(SYS_setsid) | ||||
| #else | ||||
| #	define QSE_SETSID() setsid() | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_signal) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_SIGNAL(signum,handler) syscall(SYS_signal,signum,handler) | ||||
| #else | ||||
| #	define QSE_SIGNAL(signum,handler) signal(signum,handler) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_gettimeofday) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_GETTIMEOFDAY(tv,tz) syscall(SYS_gettimeofday,tv,tz) | ||||
| #else | ||||
| @ -250,6 +271,12 @@ | ||||
| #	define QSE_SETRLIMIT(res,lim) setrlimit(res,lim) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_ioctl) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_IOCTL(fd,req,arg) syscall(SYS_ioctl,fd,req,arg) | ||||
| #else | ||||
| #	define QSE_IOCTL(fd,req,arg) ioctl(fd,req,arg) | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /* ===== FILE SYSTEM CALLS ===== */ | ||||
|  | ||||
| @ -378,6 +405,12 @@ | ||||
| #	define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_umask) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_UMASK(mode) syscall(SYS_umask,mode) | ||||
| #else | ||||
| #	define QSE_UMASK(mode) umask(mode) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_mkdir) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_MKDIR(path,mode) syscall(SYS_mkdir,path,mode) | ||||
| #else | ||||
| @ -390,6 +423,12 @@ | ||||
| #	define QSE_RMDIR(path) rmdir(path) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_chdir) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_CHDIR(path) syscall(SYS_chdir,path) | ||||
| #else | ||||
| #	define QSE_CHDIR(path) chdir(path) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_symlink) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_SYMLINK(oldpath,newpath) syscall(SYS_symlink,oldpath,newpath) | ||||
| #else | ||||
|  | ||||
							
								
								
									
										153
									
								
								qse/lib/si/AppRoot.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								qse/lib/si/AppRoot.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | ||||
| /* | ||||
|  * $Id$ | ||||
|  * | ||||
|     Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. | ||||
|  | ||||
|     Redistribution and use in source and binary forms, with or without | ||||
|     modification, are permitted provided that the following conditions | ||||
|     are met: | ||||
|     1. Redistributions of source code must retain the above copyright | ||||
|        notice, this list of conditions and the following disclaimer. | ||||
|     2. Redistributions in binary form must reproduce the above copyright | ||||
|        notice, this list of conditions and the following disclaimer in the | ||||
|        documentation and/or other materials provided with the distribution. | ||||
|  | ||||
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | ||||
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
|  | ||||
| #include <qse/si/AppRoot.hpp> | ||||
| #include <qse/si/sinfo.h> | ||||
| #include "../cmn/syscall.h" | ||||
|  | ||||
| ///////////////////////////////// | ||||
| QSE_BEGIN_NAMESPACE(QSE) | ||||
| ///////////////////////////////// | ||||
|  | ||||
| int AppRoot::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT | ||||
| { | ||||
| 	if (this->_root_only && QSE_GETEUID() != 0) return -1; | ||||
|  | ||||
| 	if (fork_count >= 1) | ||||
| 	{ | ||||
| 		if (fork_count >= 2) | ||||
| 		{ | ||||
| 			struct sigaction sa; | ||||
| 			int n = QSE_FORK(); | ||||
| 			if (n == -1) return -1; | ||||
| 			if (n != 0) QSE_EXIT(0); | ||||
|  | ||||
| 			QSE_SETSID (); | ||||
| 		} | ||||
|  | ||||
| 		int n = QSE_FORK(); | ||||
| 		if (n == -1) | ||||
| 		{ | ||||
| 			//throw DaemonError ("can't xp_fork"); | ||||
| 			//if (err_code) *err_code = ERR_FORK; | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		// the parent exits | ||||
| 		if (n != 0) QSE_EXIT(0); // TODO: should i call exit() in stdlib.h?  | ||||
| 	} | ||||
|  | ||||
| 	QSE_UMASK (0); | ||||
| 	if (chdir_to_root) QSE_CHDIR("/"); // don't care about failure | ||||
|  | ||||
| 	if (true) | ||||
| 	{ | ||||
| 		int keep[] = { 0, 1, 2}; | ||||
|  | ||||
| 		if (qse_close_open_fds_using_proc (keep, QSE_COUNTOF(keep)) <= -1) | ||||
| 		{ | ||||
| 			for (int i = qse_get_highest_fd(); i >= 3; i--) QSE_CLOSE (i); | ||||
| 		} | ||||
|  | ||||
| 		int fd = QSE_OPEN ("/dev/null", O_RDWR, 0); | ||||
| 		if (fd >= 0) | ||||
| 		{ | ||||
| 			if (fd != 0) QSE_DUP2 (fd, 0); | ||||
| 			if (fd != 1) QSE_DUP2 (fd, 1); | ||||
| 			if (fd != 2) QSE_DUP2 (fd, 2); | ||||
| 			if (fd > 2) QSE_CLOSE (fd); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (fork_count <= 1)  | ||||
| 	{ | ||||
| 		if (fork_count <= 0)  | ||||
| 		{ | ||||
| 			// detach from the controlling terminal manually | ||||
| 			// when no fork() is requested though setsid() is supposed to  | ||||
| 			// do this as well.  | ||||
| 			int fd = QSE_OPEN ("/dev/tty", O_RDWR, 0); | ||||
| 			if (fd >= 0) | ||||
| 			{ | ||||
| 				QSE_IOCTL(fd, TIOCNOTTY, NULL); | ||||
| 				QSE_CLOSE (fd); | ||||
| 			} | ||||
|  | ||||
| 			// since no fork() has been executed, the process that has | ||||
| 			// executed this process will remain as the parent. there | ||||
| 			// will happen no orphaning of this process and take-over | ||||
| 			// by init happen | ||||
| 		} | ||||
|  | ||||
| 		QSE_SETSID (); // don't care about failure | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| int AppRoot::switchUser () QSE_CPP_NOEXCEPT | ||||
| { | ||||
| 	struct passwd* pw; | ||||
|  | ||||
| 	pw = getpwnam (username); | ||||
| 	if (!pw) | ||||
|  | ||||
|  | ||||
| 	if (QSE_SETGID(pw->pw_gid) == -1) | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	QSE_SETEGID(gid); | ||||
| 	QSE_SETUID(uid); | ||||
| 	QSE_SETEUID(uid); | ||||
|  | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void AppRoot::on_signal () QSE_CPP_NOEXCEPT | ||||
| { | ||||
| } | ||||
|  | ||||
|  | ||||
| #if 0 | ||||
| int main () | ||||
| { | ||||
| 	AppRoot app; | ||||
|  | ||||
| 	app.daemonize(); | ||||
| 	app.switchUser ("nobody", "nobody"); | ||||
| 	app.switchUser (10, 20); | ||||
| 	app.catchSignal (SIGINT, xxxxx); | ||||
| 	app.catchSignal (SIGTERM, xxx); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| ///////////////////////////////// | ||||
| QSE_END_NAMESPACE(QSE) | ||||
| ///////////////////////////////// | ||||
| @ -38,6 +38,7 @@ libqsesi_la_SOURCES =  \ | ||||
| 	pio.c  \ | ||||
| 	rwl.c \ | ||||
| 	sck.c \ | ||||
| 	sinfo.c \ | ||||
| 	sio.c  \ | ||||
| 	task.c \ | ||||
| 	thr.c \ | ||||
| @ -51,6 +52,7 @@ libqsesi_la_LIBADD = -lqsecmn $(PTHREAD_LIBS) $(SSL_LIBS) | ||||
| if ENABLE_CXX | ||||
| lib_LTLIBRARIES += libqsesixx.la | ||||
| libqsesixx_la_SOURCES = \ | ||||
| 	AppRoot.cpp \ | ||||
| 	SocketAddress.cpp \ | ||||
| 	Socket.cpp | ||||
| libqsesixx_la_LDFLAGS = -L. -L../cmn -version-info 1:0:0 -no-undefined | ||||
|  | ||||
| @ -150,8 +150,8 @@ am_libqsesi_la_OBJECTS = libqsesi_la-aio.lo libqsesi_la-aio-pro.lo \ | ||||
| 	libqsesi_la-nwad.lo libqsesi_la-nwad-skad.lo \ | ||||
| 	libqsesi_la-nwif.lo libqsesi_la-nwif-cfg.lo \ | ||||
| 	libqsesi_la-nwio.lo libqsesi_la-pio.lo libqsesi_la-rwl.lo \ | ||||
| 	libqsesi_la-sck.lo libqsesi_la-sio.lo libqsesi_la-task.lo \ | ||||
| 	libqsesi_la-thr.lo libqsesi_la-tio.lo | ||||
| 	libqsesi_la-sck.lo libqsesi_la-sinfo.lo libqsesi_la-sio.lo \ | ||||
| 	libqsesi_la-task.lo libqsesi_la-thr.lo libqsesi_la-tio.lo | ||||
| libqsesi_la_OBJECTS = $(am_libqsesi_la_OBJECTS) | ||||
| AM_V_lt = $(am__v_lt_@AM_V@) | ||||
| am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) | ||||
| @ -161,8 +161,10 @@ libqsesi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ | ||||
| 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libqsesi_la_CFLAGS) \ | ||||
| 	$(CFLAGS) $(libqsesi_la_LDFLAGS) $(LDFLAGS) -o $@ | ||||
| libqsesixx_la_DEPENDENCIES = | ||||
| am__libqsesixx_la_SOURCES_DIST = SocketAddress.cpp Socket.cpp | ||||
| @ENABLE_CXX_TRUE@am_libqsesixx_la_OBJECTS = SocketAddress.lo Socket.lo | ||||
| am__libqsesixx_la_SOURCES_DIST = AppRoot.cpp SocketAddress.cpp \ | ||||
| 	Socket.cpp | ||||
| @ENABLE_CXX_TRUE@am_libqsesixx_la_OBJECTS = AppRoot.lo \ | ||||
| @ENABLE_CXX_TRUE@	SocketAddress.lo Socket.lo | ||||
| libqsesixx_la_OBJECTS = $(am_libqsesixx_la_OBJECTS) | ||||
| libqsesixx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ | ||||
| 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ | ||||
| @ -471,6 +473,7 @@ libqsesi_la_SOURCES = \ | ||||
| 	pio.c  \ | ||||
| 	rwl.c \ | ||||
| 	sck.c \ | ||||
| 	sinfo.c \ | ||||
| 	sio.c  \ | ||||
| 	task.c \ | ||||
| 	thr.c \ | ||||
| @ -481,6 +484,7 @@ libqsesi_la_CFLAGS = $(PTHREAD_CFLAGS) | ||||
| libqsesi_la_LDFLAGS = -L../cmn -version-info 1:0:0 -no-undefined | ||||
| libqsesi_la_LIBADD = -lqsecmn $(PTHREAD_LIBS) $(SSL_LIBS) | ||||
| @ENABLE_CXX_TRUE@libqsesixx_la_SOURCES = \ | ||||
| @ENABLE_CXX_TRUE@	AppRoot.cpp \ | ||||
| @ENABLE_CXX_TRUE@	SocketAddress.cpp \ | ||||
| @ENABLE_CXX_TRUE@	Socket.cpp | ||||
|  | ||||
| @ -567,6 +571,7 @@ mostlyclean-compile: | ||||
| distclean-compile: | ||||
| 	-rm -f *.tab.c | ||||
|  | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AppRoot.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Socket.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketAddress.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-aio-pro.Plo@am__quote@ | ||||
| @ -596,6 +601,7 @@ distclean-compile: | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-pio.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-rwl.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-sck.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-sinfo.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-sio.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-task.Plo@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-thr.Plo@am__quote@ | ||||
| @ -811,6 +817,13 @@ libqsesi_la-sck.lo: sck.c | ||||
| @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||||
| @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -c -o libqsesi_la-sck.lo `test -f 'sck.c' || echo '$(srcdir)/'`sck.c | ||||
|  | ||||
| libqsesi_la-sinfo.lo: sinfo.c | ||||
| @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-sinfo.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-sinfo.Tpo -c -o libqsesi_la-sinfo.lo `test -f 'sinfo.c' || echo '$(srcdir)/'`sinfo.c | ||||
| @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-sinfo.Tpo $(DEPDIR)/libqsesi_la-sinfo.Plo | ||||
| @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sinfo.c' object='libqsesi_la-sinfo.lo' libtool=yes @AMDEPBACKSLASH@ | ||||
| @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||||
| @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -c -o libqsesi_la-sinfo.lo `test -f 'sinfo.c' || echo '$(srcdir)/'`sinfo.c | ||||
|  | ||||
| libqsesi_la-sio.lo: sio.c | ||||
| @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-sio.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-sio.Tpo -c -o libqsesi_la-sio.lo `test -f 'sio.c' || echo '$(srcdir)/'`sio.c | ||||
| @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-sio.Tpo $(DEPDIR)/libqsesi_la-sio.Plo | ||||
|  | ||||
							
								
								
									
										154
									
								
								qse/lib/si/pio.c
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								qse/lib/si/pio.c
									
									
									
									
									
								
							| @ -25,6 +25,7 @@ | ||||
|  */ | ||||
|  | ||||
| #include <qse/si/pio.h> | ||||
| #include <qse/si/sinfo.h> | ||||
| #include <qse/cmn/mbwc.h> | ||||
| #include "../cmn/mem-prv.h" | ||||
|  | ||||
| @ -374,145 +375,6 @@ static QSE_INLINE int is_fd_valid_and_nocloexec (int fd) | ||||
| 	return !(flags & FD_CLOEXEC)? 1: 0; | ||||
| } | ||||
|  | ||||
| static int close_unneeded_fds_using_proc (int* excepts, qse_size_t count) | ||||
| { | ||||
| 	QSE_DIR* d; | ||||
|  | ||||
| 	/* will getting the highest file descriptor be faster than | ||||
| 	 * attempting to close any files descriptors less than the  | ||||
| 	 * system limit? */	 | ||||
|  | ||||
| 	d = QSE_OPENDIR (QSE_MT("/proc/self/fd")); | ||||
| 	if (!d) | ||||
| 	{ | ||||
| 		qse_mchar_t buf[64]; | ||||
| 		qse_mbsxfmt (buf, QSE_COUNTOF(buf), QSE_MT("/proc/%d/fd"), QSE_GETPID()); | ||||
| 		d = QSE_OPENDIR (buf); | ||||
| 	#if !defined(_SCO_DS) | ||||
| 		/* on SCO OpenServer, a range of file descriptors starting from 0 are | ||||
| 		 * listed under /dev/fd regardless of opening state. And some high  | ||||
| 		 * numbered descriptors are not listed all. not reliable */ | ||||
|  | ||||
| 		if (!d) d = QSE_OPENDIR (QSE_MT("/dev/fd")); /* Darwin, FreeBSD */ | ||||
| 	#endif | ||||
| 	} | ||||
|  | ||||
| 	if (d) | ||||
| 	{ | ||||
| 		qse_dirent_t* de; | ||||
| 		while ((de = QSE_READDIR (d))) | ||||
| 		{ | ||||
| 			qse_long_t l; | ||||
| 			const qse_mchar_t* endptr; | ||||
|  | ||||
| 			if (de->d_name[0] == QSE_MT('.')) continue; | ||||
|  | ||||
| 			QSE_MBSTONUM (l, de->d_name, &endptr, 10); | ||||
| 			if (*endptr == QSE_MT('\0')) | ||||
| 			{ | ||||
| 				int fd = (int)l; | ||||
| 				if ((qse_long_t)fd == l && fd != QSE_DIRFD(d) && fd > 2) | ||||
| 				{ | ||||
| 					qse_size_t i; | ||||
|  | ||||
| 					for (i = 0; i < count; i++) | ||||
| 					{ | ||||
| 						if (fd == excepts[i]) goto skip_close; | ||||
| 					} | ||||
|  | ||||
| 					QSE_CLOSE (fd); | ||||
|  | ||||
| 				skip_close: | ||||
| 					; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		QSE_CLOSEDIR (d); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int get_highest_fd (void) | ||||
| { | ||||
| #if defined(HAVE_GETRLIMIT) | ||||
| 	struct rlimit rlim; | ||||
| #endif | ||||
| 	int fd = -1; | ||||
| 	QSE_DIR* d; | ||||
|  | ||||
| #if defined(F_MAXFD) | ||||
| 	fd = QSE_FCNTL (0, F_MAXFD, 0); | ||||
| 	if (fd >= 0) return fd; | ||||
| #endif | ||||
|  | ||||
| 	/* will getting the highest file descriptor be faster than | ||||
| 	 * attempting to close any files descriptors less than the  | ||||
| 	 * system limit? */	 | ||||
|  | ||||
| 	d = QSE_OPENDIR (QSE_MT("/proc/self/fd")); | ||||
| 	if (!d) | ||||
| 	{ | ||||
| 		qse_mchar_t buf[64]; | ||||
| 		qse_mbsxfmt (buf, QSE_COUNTOF(buf), QSE_MT("/proc/%d/fd"), QSE_GETPID()); | ||||
| 		d = QSE_OPENDIR (buf); | ||||
| 		if (!d) d = QSE_OPENDIR (QSE_MT("/dev/fd")); /* Darwin, FreeBSD */ | ||||
| 	} | ||||
|  | ||||
| 	if (d) | ||||
| 	{ | ||||
| 		int maxfd = -1; | ||||
| 		qse_dirent_t* de; | ||||
| 		while ((de = QSE_READDIR (d))) | ||||
| 		{ | ||||
| 			qse_long_t l; | ||||
| 			const qse_mchar_t* endptr; | ||||
|  | ||||
| 			if (de->d_name[0] == QSE_MT('.')) continue; | ||||
|  | ||||
| 			QSE_MBSTONUM (l, de->d_name, &endptr, 10); | ||||
| 			if (*endptr == QSE_MT('\0')) | ||||
| 			{ | ||||
| 				fd = (int)l; | ||||
| 				if ((qse_long_t)fd == l && fd != QSE_DIRFD(d)) | ||||
| 				{ | ||||
| 					if (fd > maxfd) maxfd = fd; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		QSE_CLOSEDIR (d); | ||||
| 		return maxfd; | ||||
| 	} | ||||
|  | ||||
| /* TODO: should i also use getdtablesize() if available? */ | ||||
|  | ||||
| #if defined(HAVE_GETRLIMIT) | ||||
| 	if (QSE_GETRLIMIT (RLIMIT_NOFILE, &rlim) <= -1 || | ||||
| 	    rlim.rlim_max == RLIM_INFINITY)  | ||||
| 	{ | ||||
| 	#if defined(HAVE_SYSCONF) | ||||
| 		fd = sysconf (_SC_OPEN_MAX); | ||||
| 	#endif | ||||
| 	} | ||||
| 	else fd = rlim.rlim_max; | ||||
| #elif defined(HAVE_SYSCONF) | ||||
| 	fd = sysconf (_SC_OPEN_MAX); | ||||
| #endif | ||||
| 	if (fd <= -1) fd = 1024; /* fallback */ | ||||
|  | ||||
| 	/* F_MAXFD is the highest fd. but RLIMIT_NOFILE and  | ||||
| 	 * _SC_OPEN_MAX returnes the maximum number of file  | ||||
| 	 * descriptors. make adjustment */ | ||||
| 	if (fd > 0) fd--;  | ||||
|  | ||||
|  | ||||
| 	return fd; | ||||
| } | ||||
|  | ||||
|  | ||||
| static qse_pio_pid_t standard_fork_and_exec (qse_pio_t* pio, int pipes[], param_t* param, qse_env_t* env) | ||||
| { | ||||
| 	qse_pio_pid_t pid; | ||||
| @ -537,17 +399,17 @@ static qse_pio_pid_t standard_fork_and_exec (qse_pio_t* pio, int pipes[], param_ | ||||
|  | ||||
| 		if (!(pio->flags & QSE_PIO_NOCLOEXEC)) | ||||
| 		{ | ||||
| 			if (close_unneeded_fds_using_proc (pipes, 6) <= -1) | ||||
| 			if (qse_close_open_fds_using_proc (pipes, 6) <= -1) | ||||
| 			{ | ||||
| 				int fd = get_highest_fd (); | ||||
| 				int fd = qse_get_highest_fd (); | ||||
|  | ||||
| 				/* close all other unknown open handles except  | ||||
| 				 * stdin/out/err and the pipes. */ | ||||
| 				while (fd > 2) | ||||
| 				{ | ||||
| 					if (fd != pipes[0] && fd != pipes[1] && | ||||
| 						fd != pipes[2] && fd != pipes[3] && | ||||
| 						fd != pipes[4] && fd != pipes[5])  | ||||
| 					    fd != pipes[2] && fd != pipes[3] && | ||||
| 					    fd != pipes[4] && fd != pipes[5])  | ||||
| 					{ | ||||
| 						QSE_CLOSE (fd); | ||||
| 					} | ||||
| @ -1571,7 +1433,7 @@ create_process: | ||||
|  | ||||
| 		if (!(flags & QSE_PIO_NOCLOEXEC)) | ||||
| 		{ | ||||
| 			int fd = get_highest_fd (); | ||||
| 			int fd = qse_get_highest_fd (); | ||||
| 			while (fd > 2) | ||||
| 			{ | ||||
| 				if (fd != handle[0] && fd != handle[1] && | ||||
| @ -1651,7 +1513,7 @@ create_process: | ||||
| 		/* prepare some data before vforking for vfork limitation. | ||||
| 		 * the child in vfork should not make function calls or  | ||||
| 		 * change data shared with the parent. */ | ||||
| 		if (!(flags & QSE_PIO_NOCLOEXEC)) highest_fd = get_highest_fd (); | ||||
| 		if (!(flags & QSE_PIO_NOCLOEXEC)) highest_fd = qse_get_highest_fd (); | ||||
| 		envarr = env? qse_env_getarr(env): environ; | ||||
|  | ||||
| 		QSE_SYSCALL0 (pid, SYS_vfork); | ||||
| @ -1673,7 +1535,7 @@ create_process: | ||||
|  | ||||
| 			if (!(flags & QSE_PIO_NOCLOEXEC)) | ||||
| 			{ | ||||
| 				/* cannot call close_unneeded_fds_using_proc() in the vfork() context */ | ||||
| 				/* cannot call qse_close_open_fds_using_proc() in the vfork() context */ | ||||
|  | ||||
| 				int fd = highest_fd; | ||||
|  | ||||
|  | ||||
							
								
								
									
										166
									
								
								qse/lib/si/sinfo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								qse/lib/si/sinfo.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | ||||
| /* | ||||
|  * $Id$ | ||||
|  * | ||||
|     Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. | ||||
|  | ||||
|     Redistribution and use in source and binary forms, with or without | ||||
|     modification, are permitted provided that the following conditions | ||||
|     are met: | ||||
|     1. Redistributions of source code must retain the above copyright | ||||
|        notice, this list of conditions and the following disclaimer. | ||||
|     2. Redistributions in binary form must reproduce the above copyright | ||||
|        notice, this list of conditions and the following disclaimer in the | ||||
|        documentation and/or other materials provided with the distribution. | ||||
|  | ||||
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | ||||
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
|  | ||||
| #include <qse/si/sinfo.h> | ||||
| #include <qse/cmn/str.h> | ||||
| #include "../cmn/syscall.h" | ||||
|  | ||||
| int qse_get_highest_fd (void) | ||||
| { | ||||
| #if defined(HAVE_GETRLIMIT) | ||||
| 	struct rlimit rlim; | ||||
| #endif | ||||
| 	int fd = -1; | ||||
| 	QSE_DIR* d; | ||||
|  | ||||
| #if defined(F_MAXFD) | ||||
| 	fd = QSE_FCNTL (0, F_MAXFD, 0); | ||||
| 	if (fd >= 0) return fd; | ||||
| #endif | ||||
|  | ||||
| 	/* will getting the highest file descriptor be faster than | ||||
| 	 * attempting to close any files descriptors less than the  | ||||
| 	 * system limit? */	 | ||||
|  | ||||
| 	d = QSE_OPENDIR (QSE_MT("/proc/self/fd")); | ||||
| 	if (!d) | ||||
| 	{ | ||||
| 		qse_mchar_t buf[64]; | ||||
| 		qse_mbsxfmt (buf, QSE_COUNTOF(buf), QSE_MT("/proc/%d/fd"), QSE_GETPID()); | ||||
| 		d = QSE_OPENDIR (buf); | ||||
| 		if (!d) d = QSE_OPENDIR (QSE_MT("/dev/fd")); /* Darwin, FreeBSD */ | ||||
| 	} | ||||
|  | ||||
| 	if (d) | ||||
| 	{ | ||||
| 		int maxfd = -1; | ||||
| 		qse_dirent_t* de; | ||||
| 		while ((de = QSE_READDIR (d))) | ||||
| 		{ | ||||
| 			qse_long_t l; | ||||
| 			const qse_mchar_t* endptr; | ||||
|  | ||||
| 			if (de->d_name[0] == QSE_MT('.')) continue; | ||||
|  | ||||
| 			QSE_MBSTONUM (l, de->d_name, &endptr, 10); | ||||
| 			if (*endptr == QSE_MT('\0')) | ||||
| 			{ | ||||
| 				fd = (int)l; | ||||
| 				if ((qse_long_t)fd == l && fd != QSE_DIRFD(d)) | ||||
| 				{ | ||||
| 					if (fd > maxfd) maxfd = fd; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		QSE_CLOSEDIR (d); | ||||
| 		return maxfd; | ||||
| 	} | ||||
|  | ||||
| /* TODO: should i also use getdtablesize() if available? */ | ||||
|  | ||||
| #if defined(HAVE_GETRLIMIT) | ||||
| 	if (QSE_GETRLIMIT (RLIMIT_NOFILE, &rlim) <= -1 || | ||||
| 	    rlim.rlim_max == RLIM_INFINITY)  | ||||
| 	{ | ||||
| 	#if defined(HAVE_SYSCONF) | ||||
| 		fd = sysconf (_SC_OPEN_MAX); | ||||
| 	#endif | ||||
| 	} | ||||
| 	else fd = rlim.rlim_max; | ||||
| #elif defined(HAVE_SYSCONF) | ||||
| 	fd = sysconf (_SC_OPEN_MAX); | ||||
| #endif | ||||
| 	if (fd <= -1) fd = 1024; /* fallback */ | ||||
|  | ||||
| 	/* F_MAXFD is the highest fd. but RLIMIT_NOFILE and  | ||||
| 	 * _SC_OPEN_MAX returnes the maximum number of file  | ||||
| 	 * descriptors. make adjustment */ | ||||
| 	if (fd > 0) fd--;  | ||||
|  | ||||
| 	return fd; | ||||
| } | ||||
|  | ||||
| int qse_close_open_fds_using_proc (int* excepts, qse_size_t count) | ||||
| { | ||||
| 	QSE_DIR* d; | ||||
|  | ||||
| 	/* will getting the highest file descriptor be faster than | ||||
| 	 * attempting to close any files descriptors less than the  | ||||
| 	 * system limit? */	 | ||||
|  | ||||
| 	d = QSE_OPENDIR (QSE_MT("/proc/self/fd")); | ||||
| 	if (!d) | ||||
| 	{ | ||||
| 		qse_mchar_t buf[64]; | ||||
| 		qse_mbsxfmt (buf, QSE_COUNTOF(buf), QSE_MT("/proc/%d/fd"), QSE_GETPID()); | ||||
| 		d = QSE_OPENDIR (buf); | ||||
| 	#if !defined(_SCO_DS) | ||||
| 		/* on SCO OpenServer, a range of file descriptors starting from 0 are | ||||
| 		 * listed under /dev/fd regardless of opening state. And some high  | ||||
| 		 * numbered descriptors are not listed. not reliable */ | ||||
|  | ||||
| 		if (!d) d = QSE_OPENDIR (QSE_MT("/dev/fd")); /* Darwin, FreeBSD */ | ||||
| 	#endif | ||||
| 	} | ||||
|  | ||||
| 	if (d) | ||||
| 	{ | ||||
| 		qse_dirent_t* de; | ||||
| 		while ((de = QSE_READDIR (d))) | ||||
| 		{ | ||||
| 			qse_long_t l; | ||||
| 			const qse_mchar_t* endptr; | ||||
|  | ||||
| 			if (de->d_name[0] == QSE_MT('.')) continue; | ||||
|  | ||||
| 			QSE_MBSTONUM (l, de->d_name, &endptr, 10); | ||||
| 			if (*endptr == QSE_MT('\0')) | ||||
| 			{ | ||||
| 				int fd = (int)l; | ||||
| 				if ((qse_long_t)fd == l && fd != QSE_DIRFD(d) && fd > 2) | ||||
| 				{ | ||||
| 					qse_size_t i; | ||||
|  | ||||
| 					for (i = 0; i < count; i++) | ||||
| 					{ | ||||
| 						if (fd == excepts[i]) goto skip_close; | ||||
| 					} | ||||
|  | ||||
| 					QSE_CLOSE (fd); | ||||
|  | ||||
| 				skip_close: | ||||
| 					; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		QSE_CLOSEDIR (d); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user