⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fork.c

📁 linux下的E_MAIL客户端源码
💻 C
字号:
/* * $Id: Fork.C,v 1.6 2000/06/07 16:18:22 evgeny Exp $ * * Copyright (c) 1994 HAL Computer Systems International, Ltd. *  *          HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. *                  1315 Dell Avenue *                  Campbell, CA  95008 * * Author: Greg Hilton * Contributors: Tom Lang, Frank Bieser, and others * * 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; either version 2 * of the License, or (at your option) any later version. * * 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. * * http://www.gnu.org/copyleft/gpl.html * * 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. */#include <config.h>#include "Fork.h"#include "Misc.h"#include <hgl/StringListC.h>#include <hgl/CallbackC.h>#include <hgl/SignalRegistry.h>#include <hgl/HalAppC.h>#include <hgl/SysErr.h>#include <X11/Intrinsic.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <sys/wait.h>#ifdef HAVE_VFORK_H# include <vfork.h>#endifextern int debuglev;/*--------------------------------------------------------------- *  Where temp files are created */static char	*ForkItTmpDir = NULL;#ifndef P_tmpdir# define P_tmpdir	"/var/tmp/"#endif/*--------------------------------------------------------------- *  This data is passed to the ForkItDone callback */typedef struct {   pid_t	pid;   CallbackC	userCb;   int		status;} ForkDataT;/*--------------------------------------------------------------- *  Method to build an arg list suitable for execvp from the given *     command line */static voidBuildArgList(StringC cmdline, StringListC& argList){   char	*cs = NULL; // getenv("SHELL");   if ( !cs ) cs = "/bin/sh";   StringC	shell(cs);   argList.add(shell);//// Add flags to preserve environments//   if ( shell.EndsWith("bash") ) {      argList.add("-norc");      argList.add("-c");   }   else if ( shell.EndsWith("csh") )      argList.add("-fbc");   else      argList.add("-c");   argList.add(cmdline);} // End BuildArgList/*----------------------------------------------------------------------- *  TimeOut used to finish processing in X thread.  Can't do this stuff in *     signal handler due to the fact that there may be X calls in the user *     callback. */static voidForkDone2(ForkDataT *fd, XtIntervalId*){//// Call user callback//   fd->userCb((void*)fd->status);#ifdef HAVE_UNLINK//// Delete temporary files//   StringC	prefix(ForkItTmpDir);   if ( prefix.LastChar() != '/' ) prefix += "/";   prefix += (int)fd->pid;//   unlink(prefix + ".err");   unlink(prefix + ".out");#endif//// Delete fork data//   delete fd;   return;} // End ForkDone2/*----------------------------------------------------------------------- *  Callback to handle death of forked process */static voidForkDone(SignalDataT *sd, ForkDataT *fd){//// Make sure this is the right signal//   if ( sd->signum != SIGCHLD || sd->pid != fd->pid ) return;//// Remove this handler//   RemoveSignalCallback(SIGCHLD, (CallbackFn*)ForkDone, fd);   fd->status = sd->status;//// Use a timeout in case there are any X calls in the user callback.  X calls//    cannot be made from a signal handler.//   XtAppAddTimeOut(halApp->context, 0, (XtTimerCallbackProc)ForkDone2,		   (XtPointer)fd);}/*--------------------------------------------------------------- *  Method to fork/exec the specified command.  Returns the pid of the child *  process on success, -1 on failure. */pid_tForkIt(char *cmdline, CallbackC *doneCb){   if ( debuglev > 0 ) cout <<"ForkIt: cmdline = " <<cmdline <<endl;//// Find temp dir if necessary//   if ( !ForkItTmpDir ) {      getenv("TMPDIR");      if ( !ForkItTmpDir && (access(P_tmpdir, W_OK) == 0) )	 ForkItTmpDir = P_tmpdir;      if ( !ForkItTmpDir && (access("/tmp/",  W_OK) == 0) )	 ForkItTmpDir = "/tmp/";   }//// Create a pipe for receiving the return status//   int	pfd[2];   if (pipe(pfd) == -1) return(-1);   fcntl(pfd[0], F_SETFD, 1);   fcntl(pfd[1], F_SETFD, 1);//// Add a callback to detect process completion//   static CallbackC	*nullCb = NULL;   if ( !nullCb ) nullCb = new CallbackC;   ForkDataT	*data = new ForkDataT;   if ( doneCb ) data->userCb = *doneCb;   else		 data->userCb = *nullCb;   AddSignalCallback(SIGCHLD, (CallbackFn*)ForkDone, data);//// Create a child process for executing the command//   int		execstat = 0;   data->pid = vfork();//// Check the result of the fork//   if ( data->pid == -1 ) {	// error      int	err = errno;      if ( debuglev > 0 )	 cout <<"ForkIt: error = " <<SystemErrorMessage(err) <<endl;      close(pfd[0]);      close(pfd[1]);      RemoveSignalCallback(SIGCHLD, (CallbackFn*)ForkDone, data);      delete data;      return (-err);   }   else if ( data->pid == 0 ) {	// child//// Set the effective group id to the real group id.  We don't want to//    run any child processes with the setgid permissions on.//#ifdef HAVE_SETEGID      setegid(getgid());#else      gid_t	gid = getgid();      setresgid(gid, gid, gid);#endif      if ( debuglev > 0 ) cout <<"ForkIt: Effective gid in child is "      			 <<getegid() <<endl;//// Extract the arguments for the command//      StringListC	argList;      BuildArgList(cmdline, argList);      int	argc = argList.size();      char	**argv = new char*[argc+1];      if ( debuglev > 0 ) cout <<"ForkIt: arguments are: " <<endl;      int i=0; for (i=0; i<argc; i++) {	 argv[i] = (char*)*argList[i];	 if ( debuglev > 0 ) cout <<"\t" <<argv[i] <<endl;      }      argv[argc] = NULL;//// Make stdout and stderr point to temporary files//      pid_t	mypid = getpid();      StringC	prefix(ForkItTmpDir);      if ( prefix.LastChar() != '/' ) prefix += "/";      prefix += (int)mypid;      StringC	file = prefix + ".out";      FILE	*ofp = fopen(file, "w+");      if ( ofp ) {	 close(1);	// stdout	 close(2);	// stderr	 fcntl(fileno(ofp), F_DUPFD, 1);	 fcntl(fileno(ofp), F_DUPFD, 2);	 fclose(ofp);      }      pid_t	gpid = setsid();/*      write(pfd[1], &gpid, sizeof(gpid));*///// Execute the command//      execstat = execvp(argv[0], (char *const *)argv);//// If we reached this point, there was a problem//      int	err = errno;      if ( debuglev > 0 ) {	 cout <<"ForkIt(child): execvp failed, errno = " <<err <<endl;	 perror("ForkIt(child)");      }      execstat = err;      write(pfd[1], (char*)&execstat, sizeof(execstat));      _exit(err);   } // End if this is the child process//// If we get here, this is the parent//   if ( debuglev > 0 ) cout <<"ForkIt: pid = " <<data->pid <<endl;   close(pfd[1]);//// See if the child ever got started.  If we are able to read here, then//   the child was able to write which is not a good sign.//   int	readstat = read(pfd[0], (char*)&execstat, sizeof(execstat));   if ( readstat > 0 ) {      RemoveSignalCallback(SIGCHLD, (CallbackFn*)ForkDone, data);      delete data;      data->pid = -execstat;   }//// Close the pipe//   close(pfd[0]);   return data->pid;} // End ForkIt/*--------------------------------------------------------------- *  Create an error message for the given status code */StringCForkStatusMsg(const char *cmdline, int code, pid_t pid){   if ( debuglev > 0 )      cout <<"Status code is " <<code <<" for command " <<cmdline <<endl;   StringC	msg(cmdline);   msg += "\n";//// If less than zero, it's an errno//   if ( code < 0 ) {      msg += SystemErrorMessage(-code);   }//// If greater than zero, it's an exit code//   else if ( code > 0 ) {//// Look for an error output file//      StringC	prefix(ForkItTmpDir);      if ( prefix.LastChar() != '/' ) prefix += "/";      prefix += (int)pid;//      StringC	errfile = prefix + ".err";      StringC	outfile = prefix + ".out";      StringC	str;      str.ReadFile(outfile);//// If there is still no information, try to interpret the code//      if ( str.size() == 0 ) {	 str = "exited with status: ";	 if ( WIFEXITED(code) ) {	    char	ccode = (char)WEXITSTATUS(code);	    code = ccode;	 }	 str += code;      }      msg += str;   } // End if code > 0         else {      msg += "completed successfully.";   }   return msg;} // End ForkStatusMsg/*--------------------------------------------------------------- *  Display the output message for the given process */StringCForkOutput(pid_t pid){//// Look for an output file//   StringC	outfile(ForkItTmpDir);   if ( outfile.LastChar() != '/' ) outfile += "/";   outfile += (int)pid;   outfile += ".out";   StringC	str;   str.ReadFile(outfile);   return str;} // End ForkOutput

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -