1998-02-27 07:54:42 +03:00
|
|
|
/* {{{ Copyright */
|
|
|
|
|
|
|
|
/* Background support.
|
2007-09-25 19:33:35 +04:00
|
|
|
Copyright (C) 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
|
|
|
|
Free Software Foundation, Inc.
|
2010-04-30 17:31:06 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
Written by: 1996 Miguel de Icaza
|
|
|
|
|
|
|
|
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.
|
2010-04-30 17:31:06 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
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
|
2005-05-27 07:35:10 +04:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* }}} */
|
|
|
|
|
2009-02-05 21:28:18 +03:00
|
|
|
/** \file background.c
|
|
|
|
* \brief Source: Background support
|
|
|
|
*/
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <config.h>
|
2003-10-26 01:54:55 +04:00
|
|
|
|
|
|
|
#ifdef WITH_BACKGROUND
|
|
|
|
|
2009-02-06 02:30:45 +03:00
|
|
|
#include <stdlib.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <stdarg.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2009-02-06 01:27:37 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2010-04-30 17:31:06 +04:00
|
|
|
#include <sys/wait.h> /* waitpid() */
|
2005-02-08 12:04:03 +03:00
|
|
|
#include <unistd.h>
|
2009-02-06 02:30:45 +03:00
|
|
|
#include <fcntl.h>
|
2001-09-03 09:07:40 +04:00
|
|
|
|
2010-01-20 18:11:52 +03:00
|
|
|
#include "lib/global.h"
|
2010-11-12 11:03:57 +03:00
|
|
|
#include "lib/tty/key.h" /* add_select_channel(), delete_select_channel() */
|
|
|
|
#include "lib/widget.h" /* message() */
|
2010-11-10 22:45:56 +03:00
|
|
|
|
2010-11-22 17:15:28 +03:00
|
|
|
#include "filemanager/layout.h" /* repaint_screen() */
|
|
|
|
#include "filemanager/fileopctx.h" /* FileOpContext */
|
|
|
|
|
2010-11-12 11:03:57 +03:00
|
|
|
#include "background.h"
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/*** global variables ****************************************************************************/
|
|
|
|
|
|
|
|
#define MAXCALLARGS 4 /* Number of arguments supported */
|
|
|
|
|
|
|
|
/*** file scope macro definitions ****************************************************************/
|
|
|
|
|
|
|
|
/*** file scope type declarations ****************************************************************/
|
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
enum ReturnType
|
|
|
|
{
|
2003-10-26 08:42:29 +03:00
|
|
|
Return_String,
|
|
|
|
Return_Integer
|
|
|
|
};
|
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/*** file scope variables ************************************************************************/
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* File descriptor for talking to our parent */
|
|
|
|
static int parent_fd;
|
|
|
|
|
2009-10-20 01:30:55 +04:00
|
|
|
/* File descriptor for messages from our parent */
|
|
|
|
static int from_parent_fd;
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
struct TaskList *task_list = NULL;
|
1999-01-14 04:10:32 +03:00
|
|
|
|
|
|
|
static int background_attention (int fd, void *closure);
|
2010-04-30 17:31:06 +04:00
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/*** file scope functions ************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
1999-01-14 04:10:32 +03:00
|
|
|
static void
|
2010-04-30 17:31:06 +04:00
|
|
|
register_task_running (FileOpContext * ctx, pid_t pid, int fd, int to_child, char *info)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
TaskList *new;
|
|
|
|
|
Glibing..... (2)
Wed Jan 27 03:17:44 1999 Timur Bakeyev <mc@bat.ru>
* Converted memory managment to Glib. Now we use g_new()/g_malloc()/
g_strdup()/g_free() routings. Also, copy_strings() replaced by
g_strconcat(), strcasecmp() -> g_strcasecmp(),and sprintf() by
g_snprintf().
* Some sequences of malloc()/sprintf() changed to g_strdup_printf().
* mad.[ch]: Modified, to work with new GLib's memory managment. Fixed
a missing #undef for tempnam, which caused dead loop. Add several new
functions to emulate GLib memory managment.
*main.c, mad.[ch]: Add a new switch "-M", which allows to redirect MAD
messages to the file.
* util.[ch], utilunix.c: Modified, deleted our variants of strcasecmp()
and strdup() - we have g_ equivalences. Remove get_full_name() - it is
similar to concat_dir_and_file(). Some other tricks with g_* functions.
* global.h: Modified, extended. Now it is main memory mangment include -
i.e. all inclusions of <stdlib.h>, <malloc.h>, <glib.h>, "fs.h", "mem.h",
"util.h" and "mad.h" done there. This elimanates problem with proper or-
der of #include's.
* All around the source - changed order of #include's, most of them gone
to global.h (see above), minor changes, like "0" -> NULL in string func-
tions.
1999-01-27 04:08:30 +03:00
|
|
|
new = g_new (TaskList, 1);
|
2010-04-30 17:31:06 +04:00
|
|
|
new->pid = pid;
|
|
|
|
new->info = info;
|
1998-02-27 07:54:42 +03:00
|
|
|
new->state = Task_Running;
|
2010-04-30 17:31:06 +04:00
|
|
|
new->next = task_list;
|
|
|
|
new->fd = fd;
|
2009-10-20 01:30:55 +04:00
|
|
|
new->to_child_fd = to_child;
|
2010-04-30 17:31:06 +04:00
|
|
|
task_list = new;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
1999-01-14 04:10:32 +03:00
|
|
|
add_select_channel (fd, background_attention, ctx);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-10-30 04:12:04 +03:00
|
|
|
static int
|
2009-10-24 16:47:16 +04:00
|
|
|
destroy_task_and_return_fd (pid_t pid)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
TaskList *p = task_list;
|
|
|
|
TaskList *prev = 0;
|
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
if (p->pid == pid)
|
|
|
|
{
|
|
|
|
if (prev)
|
|
|
|
prev->next = p->next;
|
|
|
|
else
|
|
|
|
task_list = p->next;
|
|
|
|
g_free (p->info);
|
|
|
|
g_free (p);
|
|
|
|
return p->fd;
|
|
|
|
}
|
|
|
|
prev = p;
|
|
|
|
p = p->next;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2009-10-24 16:47:16 +04:00
|
|
|
|
|
|
|
/* pid not found */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-02-27 07:54:42 +03:00
|
|
|
/* {{{ Parent handlers */
|
|
|
|
|
|
|
|
/* Parent/child protocol
|
|
|
|
*
|
|
|
|
* the child (the background) process send the following:
|
|
|
|
* void *routine -- routine to be invoked in the parent
|
|
|
|
* int nargc -- number of arguments
|
|
|
|
* int type -- Return argument type.
|
|
|
|
*
|
|
|
|
* If the routine is zero, then it is a way to tell the parent
|
|
|
|
* that the process is dying.
|
|
|
|
*
|
|
|
|
* nargc arguments in the following format:
|
|
|
|
* int size of the coming block
|
|
|
|
* size bytes with the block
|
|
|
|
*
|
|
|
|
* Now, the parent loads all those and then invokes
|
|
|
|
* the routine with pointers to the information passed
|
|
|
|
* (we just support pointers).
|
|
|
|
*
|
|
|
|
* If the return type is integer:
|
|
|
|
*
|
|
|
|
* the parent then writes an int to the child with
|
|
|
|
* the return value from the routine and the values
|
|
|
|
* of any global variable that is modified in the parent
|
|
|
|
* currently: do_append and recursive_result.
|
|
|
|
*
|
|
|
|
* If the return type is a string:
|
|
|
|
*
|
2003-06-02 22:13:42 +04:00
|
|
|
* the parent writes the resulting string length
|
1998-02-27 07:54:42 +03:00
|
|
|
* if the result string was NULL or the empty string,
|
2003-06-02 22:13:42 +04:00
|
|
|
* then the length is zero.
|
|
|
|
* The parent then writes the string length and frees
|
1998-02-27 07:54:42 +03:00
|
|
|
* the result string.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Receive requests from background process and invoke the
|
2010-11-09 14:02:28 +03:00
|
|
|
* specified routine
|
1998-02-27 07:54:42 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-14 04:10:32 +03:00
|
|
|
static int
|
|
|
|
background_attention (int fd, void *closure)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
1999-01-14 04:10:32 +03:00
|
|
|
FileOpContext *ctx;
|
|
|
|
int have_ctx;
|
2010-04-30 17:31:06 +04:00
|
|
|
union
|
2009-04-24 02:47:22 +04:00
|
|
|
{
|
2010-04-30 17:31:06 +04:00
|
|
|
int (*have_ctx0) (int);
|
|
|
|
int (*have_ctx1) (int, char *);
|
|
|
|
int (*have_ctx2) (int, char *, char *);
|
|
|
|
int (*have_ctx3) (int, char *, char *, char *);
|
|
|
|
int (*have_ctx4) (int, char *, char *, char *, char *);
|
|
|
|
|
|
|
|
int (*non_have_ctx0) (FileOpContext *, int);
|
|
|
|
int (*non_have_ctx1) (FileOpContext *, int, char *);
|
|
|
|
int (*non_have_ctx2) (FileOpContext *, int, char *, char *);
|
|
|
|
int (*non_have_ctx3) (FileOpContext *, int, char *, char *, char *);
|
|
|
|
int (*non_have_ctx4) (FileOpContext *, int, char *, char *, char *, char *);
|
|
|
|
|
|
|
|
char *(*ret_str0) ();
|
|
|
|
char *(*ret_str1) (char *);
|
|
|
|
char *(*ret_str2) (char *, char *);
|
|
|
|
char *(*ret_str3) (char *, char *, char *);
|
|
|
|
char *(*ret_str4) (char *, char *, char *, char *);
|
|
|
|
|
|
|
|
void *pointer;
|
2009-04-24 02:47:22 +04:00
|
|
|
} routine;
|
2010-04-30 17:31:06 +04:00
|
|
|
/* void *routine; */
|
|
|
|
int argc, i, result, status;
|
|
|
|
char *data[MAXCALLARGS];
|
2010-04-30 13:29:28 +04:00
|
|
|
ssize_t bytes, ret;
|
2010-04-30 17:31:06 +04:00
|
|
|
struct TaskList *p;
|
|
|
|
int to_child_fd = -1;
|
1998-02-27 07:54:42 +03:00
|
|
|
enum ReturnType type;
|
1999-01-14 04:10:32 +03:00
|
|
|
|
|
|
|
ctx = closure;
|
|
|
|
|
2009-04-24 02:47:22 +04:00
|
|
|
bytes = read (fd, &routine.pointer, sizeof (routine));
|
2010-04-30 17:31:06 +04:00
|
|
|
if (bytes == -1 || (size_t) bytes < (sizeof (routine)))
|
|
|
|
{
|
2010-05-15 18:45:13 +04:00
|
|
|
const char *background_process_error = _("Background process error");
|
2000-08-08 20:21:25 +04:00
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
unregister_task_running (ctx->pid, fd);
|
|
|
|
if (!waitpid (ctx->pid, &status, WNOHANG))
|
|
|
|
{
|
|
|
|
/* the process is still running, but it misbehaves - kill it */
|
|
|
|
kill (ctx->pid, SIGTERM);
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, background_process_error, _("Unknown error in child"));
|
2010-04-30 17:31:06 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2003-10-25 11:19:31 +04:00
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
/* 0 means happy end */
|
|
|
|
if (WIFEXITED (status) && (WEXITSTATUS (status) == 0))
|
|
|
|
return 0;
|
2003-10-26 08:42:29 +03:00
|
|
|
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, background_process_error, _("Child died unexpectedly"));
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
return 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
1999-01-14 04:10:32 +03:00
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
if ((read (fd, &argc, sizeof (argc)) != sizeof (argc)) ||
|
|
|
|
(read (fd, &type, sizeof (type)) != sizeof (type)) ||
|
2010-04-30 13:29:28 +04:00
|
|
|
(read (fd, &have_ctx, sizeof (have_ctx)) != sizeof (have_ctx)))
|
|
|
|
{
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, _("Background protocol error"), _("Reading failed"));
|
2010-04-30 17:31:06 +04:00
|
|
|
return 0;
|
2010-04-30 13:29:28 +04:00
|
|
|
}
|
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
if (argc > MAXCALLARGS)
|
|
|
|
{
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, _("Background protocol error"),
|
|
|
|
_("Background process sent us a request for more arguments\n"
|
|
|
|
"than we can handle."));
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2010-04-30 13:29:28 +04:00
|
|
|
|
1999-01-14 04:10:32 +03:00
|
|
|
if (have_ctx)
|
2010-04-30 13:29:28 +04:00
|
|
|
{
|
2010-04-30 17:31:06 +04:00
|
|
|
if (read (fd, ctx, sizeof (FileOpContext)) != sizeof (FileOpContext))
|
|
|
|
{
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, _("Background protocol error"), _("Reading failed"));
|
2010-04-30 17:31:06 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2010-04-30 13:29:28 +04:00
|
|
|
}
|
1999-01-14 04:10:32 +03:00
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
if (read (fd, &size, sizeof (size)) != sizeof (size))
|
|
|
|
{
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, _("Background protocol error"), _("Reading failed"));
|
2010-04-30 17:31:06 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
data[i] = g_malloc (size + 1);
|
|
|
|
if (read (fd, data[i], size) != size)
|
|
|
|
{
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, _("Background protocol error"), _("Reading failed"));
|
2010-04-30 17:31:06 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
data[i][size] = 0; /* NULL terminate the blocks (they could be strings) */
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
/* Find child task info by descriptor */
|
|
|
|
/* Find before call, because process can destroy self after */
|
|
|
|
for (p = task_list; p; p = p->next)
|
|
|
|
{
|
|
|
|
if (p->fd == fd)
|
|
|
|
break;
|
|
|
|
}
|
2009-10-24 16:47:16 +04:00
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
if (p)
|
|
|
|
to_child_fd = p->to_child_fd;
|
2009-10-24 16:47:16 +04:00
|
|
|
|
|
|
|
if (to_child_fd == -1)
|
2010-05-15 18:45:13 +04:00
|
|
|
message (D_ERROR, _("Background process error"), _("Unknown error in child"));
|
2009-10-24 16:47:16 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
/* Handle the call */
|
2010-04-30 17:31:06 +04:00
|
|
|
if (type == Return_Integer)
|
|
|
|
{
|
|
|
|
if (!have_ctx)
|
|
|
|
switch (argc)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
result = routine.have_ctx0 (Background);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
result = routine.have_ctx1 (Background, data[0]);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
result = routine.have_ctx2 (Background, data[0], data[1]);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
result = routine.have_ctx3 (Background, data[0], data[1], data[2]);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
result = routine.have_ctx4 (Background, data[0], data[1], data[2], data[3]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
switch (argc)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
result = routine.non_have_ctx0 (ctx, Background);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
result = routine.non_have_ctx1 (ctx, Background, data[0]);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
result = routine.non_have_ctx2 (ctx, Background, data[0], data[1]);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
result = routine.non_have_ctx3 (ctx, Background, data[0], data[1], data[2]);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
result =
|
|
|
|
routine.non_have_ctx4 (ctx, Background, data[0], data[1], data[2], data[3]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send the result code and the value for shared variables */
|
|
|
|
ret = write (to_child_fd, &result, sizeof (int));
|
|
|
|
if (have_ctx && to_child_fd != -1)
|
|
|
|
ret = write (to_child_fd, ctx, sizeof (FileOpContext));
|
|
|
|
}
|
|
|
|
else if (type == Return_String)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
char *resstr = NULL;
|
|
|
|
|
|
|
|
/* FIXME: string routines should also use the Foreground/Background
|
|
|
|
* parameter. Currently, this is not used here
|
|
|
|
*/
|
|
|
|
switch (argc)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
resstr = routine.ret_str0 ();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
resstr = routine.ret_str1 (data[0]);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
resstr = routine.ret_str2 (data[0], data[1]);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
resstr = routine.ret_str3 (data[0], data[1], data[2]);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
resstr = routine.ret_str4 (data[0], data[1], data[2], data[3]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
if (resstr)
|
|
|
|
{
|
|
|
|
len = strlen (resstr);
|
|
|
|
ret = write (to_child_fd, &len, sizeof (len));
|
2010-07-02 19:47:25 +04:00
|
|
|
if (len != 0)
|
|
|
|
ret = write (to_child_fd, resstr, len);
|
2010-04-30 17:31:06 +04:00
|
|
|
g_free (resstr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len = 0;
|
|
|
|
ret = write (to_child_fd, &len, sizeof (len));
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
for (i = 0; i < argc; i++)
|
2010-04-30 17:31:06 +04:00
|
|
|
g_free (data[i]);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2009-06-02 20:15:58 +04:00
|
|
|
repaint_screen ();
|
1998-02-27 07:54:42 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
1998-02-27 07:54:42 +03:00
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ client RPC routines */
|
1999-01-14 04:10:32 +03:00
|
|
|
|
|
|
|
/* Sends the header for a call to a routine in the parent process. If the file
|
|
|
|
* operation context is not NULL, then it requests that the first parameter of
|
|
|
|
* the call be a file operation context.
|
|
|
|
*/
|
2010-11-09 14:02:28 +03:00
|
|
|
|
1998-12-03 00:27:27 +03:00
|
|
|
static void
|
2010-04-30 17:31:06 +04:00
|
|
|
parent_call_header (void *routine, int argc, enum ReturnType type, FileOpContext * ctx)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
1999-01-14 04:10:32 +03:00
|
|
|
int have_ctx;
|
2010-04-30 13:29:28 +04:00
|
|
|
ssize_t ret;
|
1999-01-14 04:10:32 +03:00
|
|
|
|
|
|
|
have_ctx = (ctx != NULL);
|
|
|
|
|
2010-04-30 13:29:28 +04:00
|
|
|
ret = write (parent_fd, &routine, sizeof (routine));
|
|
|
|
ret = write (parent_fd, &argc, sizeof (int));
|
|
|
|
ret = write (parent_fd, &type, sizeof (type));
|
|
|
|
ret = write (parent_fd, &have_ctx, sizeof (have_ctx));
|
1999-01-14 04:10:32 +03:00
|
|
|
|
|
|
|
if (have_ctx)
|
2010-04-30 17:31:06 +04:00
|
|
|
ret = write (parent_fd, ctx, sizeof (FileOpContext));
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/*** public functions ****************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
unregister_task_running (pid_t pid, int fd)
|
|
|
|
{
|
|
|
|
destroy_task_and_return_fd (pid);
|
|
|
|
delete_select_channel (fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void
|
|
|
|
unregister_task_with_pid (pid_t pid)
|
|
|
|
{
|
|
|
|
int fd = destroy_task_and_return_fd (pid);
|
|
|
|
if (fd != -1)
|
|
|
|
delete_select_channel (fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
|
|
* Try to make the Midnight Commander a background job
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 1 for parent
|
|
|
|
* 0 for child
|
|
|
|
* -1 on failure
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
do_background (struct FileOpContext *ctx, char *info)
|
|
|
|
{
|
|
|
|
int comm[2]; /* control connection stream */
|
|
|
|
int back_comm[2]; /* back connection */
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
if (pipe (comm) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (pipe (back_comm) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
pid = fork ();
|
|
|
|
if (pid == -1)
|
|
|
|
{
|
|
|
|
int saved_errno = errno;
|
|
|
|
|
|
|
|
(void) close (comm[0]);
|
|
|
|
(void) close (comm[1]);
|
|
|
|
(void) close (back_comm[0]);
|
|
|
|
(void) close (back_comm[1]);
|
|
|
|
errno = saved_errno;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid == 0)
|
|
|
|
{
|
|
|
|
int nullfd;
|
|
|
|
|
|
|
|
parent_fd = comm[1];
|
|
|
|
from_parent_fd = back_comm[0];
|
|
|
|
|
2011-02-10 18:02:54 +03:00
|
|
|
mc_global.we_are_background = 1;
|
2010-11-09 14:02:28 +03:00
|
|
|
top_dlg = NULL;
|
|
|
|
|
|
|
|
/* Make stdin/stdout/stderr point somewhere */
|
|
|
|
close (0);
|
|
|
|
close (1);
|
|
|
|
close (2);
|
|
|
|
|
|
|
|
nullfd = open ("/dev/null", O_RDWR);
|
|
|
|
if (nullfd != -1)
|
|
|
|
{
|
|
|
|
while (dup2 (nullfd, 0) == -1 && errno == EINTR)
|
|
|
|
;
|
|
|
|
while (dup2 (nullfd, 1) == -1 && errno == EINTR)
|
|
|
|
;
|
|
|
|
while (dup2 (nullfd, 2) == -1 && errno == EINTR)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ctx->pid = pid;
|
|
|
|
register_task_running (ctx, pid, comm[0], back_comm[1], info);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
int
|
2003-10-24 22:28:32 +04:00
|
|
|
parent_call (void *routine, struct FileOpContext *ctx, int argc, ...)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
int i;
|
2010-04-30 13:29:28 +04:00
|
|
|
ssize_t ret;
|
1999-01-14 04:10:32 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
va_start (ap, argc);
|
1999-01-14 04:10:32 +03:00
|
|
|
parent_call_header (routine, argc, Return_Integer, ctx);
|
2010-04-30 17:31:06 +04:00
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
void *value;
|
|
|
|
|
|
|
|
len = va_arg (ap, int);
|
|
|
|
value = va_arg (ap, void *);
|
|
|
|
ret = write (parent_fd, &len, sizeof (int));
|
|
|
|
ret = write (parent_fd, value, len);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2009-10-20 01:30:55 +04:00
|
|
|
|
2010-04-30 13:29:28 +04:00
|
|
|
ret = read (from_parent_fd, &i, sizeof (int));
|
1999-01-14 04:10:32 +03:00
|
|
|
if (ctx)
|
2010-04-30 17:31:06 +04:00
|
|
|
ret = read (from_parent_fd, ctx, sizeof (FileOpContext));
|
1999-01-14 04:10:32 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2003-10-26 01:54:55 +04:00
|
|
|
char *
|
1998-02-27 07:54:42 +03:00
|
|
|
parent_call_string (void *routine, int argc, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
char *str;
|
|
|
|
int i;
|
2010-04-30 17:31:06 +04:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
va_start (ap, argc);
|
1999-01-14 04:10:32 +03:00
|
|
|
parent_call_header (routine, argc, Return_String, NULL);
|
2010-04-30 17:31:06 +04:00
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
void *value;
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
len = va_arg (ap, int);
|
|
|
|
value = va_arg (ap, void *);
|
|
|
|
if ((write (parent_fd, &len, sizeof (int)) != sizeof (int)) ||
|
2010-04-30 13:29:28 +04:00
|
|
|
(write (parent_fd, value, len) != len))
|
2010-04-30 17:31:06 +04:00
|
|
|
return NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2010-04-30 13:29:28 +04:00
|
|
|
if (read (from_parent_fd, &i, sizeof (int)) != sizeof (int))
|
2010-04-30 17:31:06 +04:00
|
|
|
return NULL;
|
1998-02-27 07:54:42 +03:00
|
|
|
if (!i)
|
2010-04-30 17:31:06 +04:00
|
|
|
return NULL;
|
Glibing..... (2)
Wed Jan 27 03:17:44 1999 Timur Bakeyev <mc@bat.ru>
* Converted memory managment to Glib. Now we use g_new()/g_malloc()/
g_strdup()/g_free() routings. Also, copy_strings() replaced by
g_strconcat(), strcasecmp() -> g_strcasecmp(),and sprintf() by
g_snprintf().
* Some sequences of malloc()/sprintf() changed to g_strdup_printf().
* mad.[ch]: Modified, to work with new GLib's memory managment. Fixed
a missing #undef for tempnam, which caused dead loop. Add several new
functions to emulate GLib memory managment.
*main.c, mad.[ch]: Add a new switch "-M", which allows to redirect MAD
messages to the file.
* util.[ch], utilunix.c: Modified, deleted our variants of strcasecmp()
and strdup() - we have g_ equivalences. Remove get_full_name() - it is
similar to concat_dir_and_file(). Some other tricks with g_* functions.
* global.h: Modified, extended. Now it is main memory mangment include -
i.e. all inclusions of <stdlib.h>, <malloc.h>, <glib.h>, "fs.h", "mem.h",
"util.h" and "mad.h" done there. This elimanates problem with proper or-
der of #include's.
* All around the source - changed order of #include's, most of them gone
to global.h (see above), minor changes, like "0" -> NULL in string func-
tions.
1999-01-27 04:08:30 +03:00
|
|
|
str = g_malloc (i + 1);
|
2010-04-30 13:29:28 +04:00
|
|
|
if (read (from_parent_fd, str, i) != i)
|
|
|
|
{
|
2010-04-30 17:31:06 +04:00
|
|
|
g_free (str);
|
2010-04-30 13:29:28 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-04-30 17:31:06 +04:00
|
|
|
str[i] = 0;
|
1998-02-27 07:54:42 +03:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2010-11-09 14:02:28 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2010-04-30 17:31:06 +04:00
|
|
|
#endif /* WITH_BACKGROUND */
|