📄 sflproc.c
字号:
---------------------------------------------------------------------[>]-*/
int
process_server (
const char *workdir, /* Where server runs, or NULL/"" */
const char *lockfile, /* For exclusive execution */
int argc, /* Original command-line arguments */
char *argv [], /* Original command-line arguments */
const char *sswitch []) /* Filter these options from argv */
{
#if (defined (__UNIX__))
int
fork_result,
file_handle;
char
pid_buffer [10];
struct flock
lock_file; /* flock() argument block */
#endif
int
argi = 0, /* Input arguments iterator */
argo = 0; /* Output arguments iterator */
char
**newargv = NULL; /* Array of new arguments */
newargv = malloc (argc * sizeof (char *));
if (newargv == NULL)
return (-1);
/* Copy the arguments across, skipping any in sswitch */
for (argi = argo = 0; argi < argc; argi++)
{
Bool
copy_argument = TRUE;
int
i = 0;
for (i = 0; sswitch != NULL && sswitch [i] != NULL; i++)
{
if (strcmp (argv [argi], sswitch [i]) == 0)
copy_argument = FALSE;
}
if (copy_argument)
newargv [argo++] = argv [argi];
}
/* Terminate the new argument array */
newargv [argo] = NULL;
#if (defined (__UNIX__))
/* We recreate our process as a child of init. The process continues */
/* to exit in the background. UNIX calls wait() for all children of */
/* the init process, so the server will exit cleanly. */
fork_result = fork ();
if (fork_result < 0) /* < 0 is an error */
return (-1); /* Could not fork */
else
if (fork_result > 0) /* > 0 is the parent process */
exit (EXIT_SUCCESS); /* End parent process */
/* We close all open file descriptors that may have been inherited */
/* from the parent process. This is to reduce the resources we use. */
for (file_handle = FILEHANDLE_MAX - 1; file_handle >= 0; file_handle--)
close (file_handle); /* Ignore errors */
/* We move to a safe and known directory, which is supplied as an */
/* argument to this function (or not, if workdir is NULL or empty). */
if (workdir && strused (workdir))
chdir (workdir);
/* We set the umask so that new files are given mode 750 octal */
umask (027); /* Complement of 0750 */
/* We set standard input and output to the null device so that any */
/* functions that assume that these files are open can still work. */
file_handle = open ("/dev/null", O_RDWR); /* stdin = handle 0 */
dup (file_handle); /* stdout = handle 1 */
dup (file_handle); /* stderr = handle 2 */
/* We enforce a lock on the lockfile, if specified, so that only one */
/* copy of the server can run at once. We return -1 if the lock fails. */
/* This locking code might be better isolated into a separate package, */
/* since it is not very portable between unices. */
if (lockfile && strused (lockfile))
{
file_handle = open (lockfile, O_RDWR | O_CREAT, 0640);
if (file_handle < 0)
return (-1); /* We could not open lock file */
else
{
lock_file.l_type = F_WRLCK;
if (fcntl (file_handle, F_SETLK, &lock_file))
return (-1); /* We could not obtain a lock */
}
/* We record the server's process id in the lock file */
snprintf (pid_buffer, sizeof (pid_buffer), "%6d\n", getpid ());
write (file_handle, pid_buffer, strlen (pid_buffer));
}
/* We ignore any hangup signal from the controlling TTY */
signal (SIGHUP, SIG_IGN);
return (0); /* Initialisation completed ok */
#elif (defined (__OS2__))
/* Start a new copy of the program up, running detached from this
* program. Quote the arguments to prevent expansion because they've
* already been expanded once if applicable. The program name is taken
* to be argv[0] due to the lack of better options, and the path will be
* searched to try to find it.
*
* Providing the program starts successfully, this process exits,
* otherwise an error is returned.
*/
# if (defined (__EMX__))
if (spawnvp ((P_NOWAIT | P_DETACH | P_QUOTE), newargv [0], newargv) == -1)
return -1;
else
exit (EXIT_SUCCESS);
# else
# error Do not know how to run detached program.
# endif
#else
return (0); /* Nothing to do on this system */
#endif
}
#if (defined (__WINDOWS__))
/* handle_timer -- internal
*
* This function is called by Windows when the timer goes off. We use this
* to send a SIGALRM to whoever is handling signals. (SIGALRM is actually
* SIGFPE, since MSVC does not know SIGALRM, and its raise() function
* only works with the pathetic little group of standard signals.)
* We call WSACancelBlockingCall(), which *should* unblock any select() or
* other blocking winsock call that is in progress. If you are waiting in
* a select() loop, and a timer goes off, you want to go handle it right
* away. Sadly, this does not work with all (any?) winsocks. So, a word
* to the wise: if you use select() and timers, under Windows you should
* use a select() timeout that matches the level of responsiveness that
* you need. (Typically 100-500ms.)
*/
static UINT /* We only want a single timer to */
last_timer = 0; /* be active at once. */
# if (defined (WIN32))
void FAR PASCAL handle_timer (UINT idTimer, UINT msg,
DWORD dw1, DWORD dw2, DWORD dw3)
# else
void CALLBACK handle_timer (HWND hwnd, UINT msg, UINT timerid, DWORD time)
# endif
{
WSACancelBlockingCall (); /* Force "interrupted system call" */
raise (SIGALRM); /* Simulate UNIX signal */
last_timer = 0; /* and note that timer has gone */
}
#endif
/* ---------------------------------------------------------------------[<]-
Function: process_alarm
Synopsis: Sets a system timer to raise a SIGALRM after a specified
interval in milliseconds. Returns TRUE if the timer could be created
and FALSE if there were insufficient resources, or if the system does
not support timers. Permits a single alarm for the current process:
any alarm that was still pending when you called this function is
annulled. The implementation is system-dependent and highly
non-portable.
Under UNIX we use the setitimer() system function, which is clean and
simple.
BeOS does not support this, so we use the good old alarm() function.
Under 16-bit Windows we use the SetTimer() call. This does not work
in 32-bit console applications. Under 32-bit Windows we use the
'multimedia' timer, which provides better resolution and does work
in console applications. In both these cases we cache the id of the
last-created alarm (and kill it before each new request), to avoid
multiple active alarms. It is not a good idea to create too many
concurrent timers; after 16 or so the alarms start to fail. This is
not supposed to happen with MM timers, but does anyway. Under
Windows, SIGALRM does not exist. Since signal() only accepts one of
a small set of fixed signals, we hijack the SIGFPE signal... It's a
compromise and requires that any code which expects a SIGALRM does
not use SIGFPE. This can be tweaked in prelude.h.
Under OS/2 we use the alarm() function which is accurate to one
second only. The required accuracy of timing is not easily
achieved, so process_alarm() rounds down to whole seconds (except if
rounding down would give 0, in which case it will delay 1 second).
This will probably cause problems in code applications that depends
on sub-second timing resolution.
Under OpenVMS 7 and later we use the setitimer() function as for
UNIX. Under OpenVMS 6 and earlier we use the alarm() function as
for OS/2. This code may be tuned to use native VMS system calls.
---------------------------------------------------------------------[>]-*/
Bool
process_alarm (long delay)
{
#if ((defined (__UNIX__) && !defined (__UTYPE_BEOS)) || defined (__VMS_XOPEN))
struct itimerval
timeout; /* Timeout for setitimer */
/* If the system supports interval timers, ask for a signal */
timeout.it_interval.tv_sec = 0;
timeout.it_interval.tv_usec = 0;
timeout.it_value.tv_sec = delay / 1000;
timeout.it_value.tv_usec = delay % 1000 * 1000L;
setitimer (ITIMER_REAL, &timeout, 0);
return (TRUE);
#elif (defined (__OS2__) || defined (__VMS__) || defined (__UTYPE_BEOS))
/* Since we use alarm() for our timeout, we can only time to */
/* the nearest second, and alarm(0) turns off the alarm. */
/* NOTE: we also have only one timer -- if alarm() is called while */
/* the alarm is active, then it will be reset to the new value, and */
/* only a single SIGALRM will be generated. */
delay = (delay < 1000) ? 1 : (delay / 1000);
alarm (delay);
return (TRUE);
#elif (defined (__WINDOWS__))
# if (defined (WIN32))
# pragma comment (lib, "winmm") /* Link-in multimedia library */
/* The multimedia timer gives the best accuracy, and works in console */
/* applications */
int rc;
if (last_timer)
__try {
rc = timeKillEvent (last_timer);
}
__except (1) {
coprintf ("timeKillEvent %d failed", last_timer);
}
__try {
last_timer = timeSetEvent (delay, 50, handle_timer, 0, TIME_ONESHOT);
}
__except (1) {
coprintf ("timeSetEvent %ld failed", delay);
}
return (TRUE);
# else
/* But the normal Windows timer will do if we're in 16 bits */
if (last_timer)
KillTimer ((HWND) NULL, last_timer);
last_timer = SetTimer ((HWND) NULL, 0, (UINT) delay, handle_timer);
return (TRUE);
# endif
#else
return (FALSE); /* No timers - function failed */
#endif
}
/* ---------------------------------------------------------------------[<]-
Function: process_esc
Synopsis: Escapes a directory string so that process_create() can handle
it correctly. If you pass a command to process_create with a directory
name that contains spaces, it will assume that the spaces delimit the
command from its arguments. For instance, under Windows 95, the filename
"C:\Program Files\Myprog.exe" will be incorrectly treated as a program
called "C:\Program" with arguments "Files\Myprog.exe". This function
replaces spaces by the escape character (0x1B). You cannot use this
value in a filename and expect process_create() to work correctly. On
an EBCDIC system, the escape character (0x27) is also used. If the
dest argument is NULL, allocates a string using mem_alloc() and returns
that. Otherwise copies into the dest string and returns that. If the
src string is NULL, returns an empty string.
---------------------------------------------------------------------[>]-*/
char *
process_esc (char *dest, const char *src)
{
#if (defined (__EBCDIC__))
# define ESC_CHAR 0x27
#else
# define ESC_CHAR 0x1B
#endif
/* Copy to dest, allocate if necessary */
if (dest != src)
{
xstrcpy_debug ();
dest = xstrcpy (dest, src, NULL);
}
strconvch (dest, ' ', ESC_CHAR);
return (dest);
}
/* ---------------------------------------------------------------------[<]-
Function: process_unesc
Synopsis: Does the reverse translaction to process_esc().
---------------------------------------------------------------------[>]-*/
char *
process_unesc (char *dest, const char *src)
{
/* Copy to dest, allocate if necessary */
if (dest != src)
{
xstrcpy_debug ();
dest = xstrcpy (dest, src, NULL);
}
strconvch (dest, ESC_CHAR, ' ');
return (dest);
}
/* ---------------------------------------------------------------------[<]-
Function: process_priority
Synopsis: Sets process priority as specified, to one of PRIORITY_LOW,
PRIORITY_NORMAL, or PRIORITY_HIGH. Currently has an effect only under
Windows NT/95. Returns 0 if okay, -1 if there was an error.
---------------------------------------------------------------------[>]-*/
int
process_priority (int priority)
{
#if (defined (WIN32))
int
class;
if (priority == PRIORITY_HIGH)
class = HIGH_PRIORITY_CLASS;
else
if (priority == PRIORITY_LOW)
class = IDLE_PRIORITY_CLASS;
else
class = NORMAL_PRIORITY_CLASS;
return (SetPriorityClass (GetCurrentProcess (), class));
#else
return (0);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -