[Openvas-commits] r6591 - in trunk/openvas-administrator: . src
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Fri Jan 29 15:29:26 CET 2010
Author: mattm
Date: 2010-01-29 15:29:24 +0100 (Fri, 29 Jan 2010)
New Revision: 6591
Modified:
trunk/openvas-administrator/ChangeLog
trunk/openvas-administrator/src/admin.c
trunk/openvas-administrator/src/admin.h
trunk/openvas-administrator/src/oap.c
trunk/openvas-administrator/src/oapd.c
trunk/openvas-administrator/src/openvasad.c
Log:
Make OAP SYNC_FEED simply start the sync, instead of waiting for the
sync to finish. Extent OAP DESCRIBE_FEED with more details of feeds
that are sync'ing.
* src/admin.c (openvas_admin_add_user): Free uuid with free.
(openvas_sync_feed): Add current_user arg. Fork a child to run the sync.
(openvas_currently_syncing): Remove.
(openvas_current_sync): New function.
* src/admin.h: Update headers accordingly.
* src/oap.c (current_error, forked): New variables.
(oap_xml_handle_end_element): In CLIENT_DESCRIBE_FEED add TIMESTAMP and
USER to CURRENTLY_SYNCING. In CLIENT_SYNC_FEED handle fork returns.
(init_oap_process): Init forked and current_error.
(process_oap_client_input): Check for dummy error containing forked child
return.
* src/oapd.c (serve_oap): Handle process_oap_client_input child returns.
* src/openvasad.c (main): Pass dummy user to openvas_sync_feed. Wait for
sync child and report result according the child return.
Modified: trunk/openvas-administrator/ChangeLog
===================================================================
--- trunk/openvas-administrator/ChangeLog 2010-01-29 13:50:10 UTC (rev 6590)
+++ trunk/openvas-administrator/ChangeLog 2010-01-29 14:29:24 UTC (rev 6591)
@@ -1,3 +1,28 @@
+2010-01-28 Matthew Mundell <matthew.mundell at intevation.de>
+
+ Make OAP SYNC_FEED simply start the sync, instead of waiting for the
+ sync to finish. Extent OAP DESCRIBE_FEED with more details of feeds
+ that are sync'ing.
+
+ * src/admin.c (openvas_admin_add_user): Free uuid with free.
+ (openvas_sync_feed): Add current_user arg. Fork a child to run the sync.
+ (openvas_currently_syncing): Remove.
+ (openvas_current_sync): New function.
+
+ * src/admin.h: Update headers accordingly.
+
+ * src/oap.c (current_error, forked): New variables.
+ (oap_xml_handle_end_element): In CLIENT_DESCRIBE_FEED add TIMESTAMP and
+ USER to CURRENTLY_SYNCING. In CLIENT_SYNC_FEED handle fork returns.
+ (init_oap_process): Init forked and current_error.
+ (process_oap_client_input): Check for dummy error containing forked child
+ return.
+
+ * src/oapd.c (serve_oap): Handle process_oap_client_input child returns.
+
+ * src/openvasad.c (main): Pass dummy user to openvas_sync_feed. Wait for
+ sync child and report result according the child return.
+
2010-01-26 Jan-Oliver Wagner <jan-oliver.wagner at greenbone.net>
Post-release version bump.
Modified: trunk/openvas-administrator/src/admin.c
===================================================================
--- trunk/openvas-administrator/src/admin.c 2010-01-29 13:50:10 UTC (rev 6590)
+++ trunk/openvas-administrator/src/admin.c 2010-01-29 14:29:24 UTC (rev 6591)
@@ -571,7 +571,7 @@
}
contents = g_strdup_printf ("%s\n", uuid);
- g_free (uuid);
+ free (uuid);
uuid_file_name = g_build_filename (user_dir_name, "uuid", NULL);
@@ -1182,20 +1182,28 @@
}
/**
- * @brief Calls an NVT sync script to synchronize the local NVT collection.
+ * @brief Forks a child to synchronize the local NVT collection.
*
- * @param[in] sync_script The file name of the synchronization script.
+ * The forked process calls an NVT sync script to sync the feed.
*
- * @return 0 sync finished successfully, 1 sync already in progress, -1 error.
+ * @param[in] sync_script The file name of the synchronization script.
+ * @param[in] current_user The user currently authenticated.
+ *
+ * @return 0 sync requested (parent), 1 sync already in progress (parent),
+ * -1 error (parent), 2 sync complete (child), 11 sync in progress
+ * (child), -10 error (child).
*/
int
-openvas_sync_feed (const gchar * sync_script)
+openvas_sync_feed (const gchar * sync_script, const gchar *current_user)
{
- int fd, ret = 0;
+ int fd, ret = 2;
gchar *lockfile_name, *lockfile_dirname;
gchar *script_identification_string = NULL;
+ pid_t pid;
+ mode_t old_mask;
g_assert (sync_script);
+ g_assert (current_user);
if (!openvas_get_sync_script_identification (sync_script,
&script_identification_string))
@@ -1211,8 +1219,12 @@
sync_script,
NULL);
lockfile_dirname = g_path_get_dirname (lockfile_name);
- if (g_mkdir_with_parents (lockfile_dirname, S_IRWXU))
+ old_mask = umask (0);
+ if (g_mkdir_with_parents (lockfile_dirname,
+ /* "-rwxrwxrwx" */
+ S_IRWXU | S_IRWXG | S_IRWXO))
{
+ umask (old_mask);
g_warning ("Failed to create lock dir '%s': %s",
lockfile_dirname,
strerror (errno));
@@ -1220,11 +1232,12 @@
g_free (lockfile_dirname);
return -1;
}
+ umask (old_mask);
g_free (lockfile_dirname);
fd = open (lockfile_name,
O_RDWR | O_CREAT | O_EXCL,
- S_IWUSR | S_IRUSR /* "-rw-------" */);
+ S_IWUSR | S_IRUSR | S_IROTH | S_IRGRP /* "-rw-r--r--" */);
if (fd == -1)
{
if (errno == EEXIST)
@@ -1236,6 +1249,115 @@
return -1;
}
+ /* Close and remove the lock file around the fork. Another process may get
+ * the lock here, in which case the child will simply fail to get the
+ * lock. */
+
+ if (close (fd))
+ {
+ g_free (lockfile_name);
+ g_warning ("Failed to close lock file: %s", strerror (errno));
+ return -1;
+ }
+
+ if (unlink (lockfile_name))
+ {
+ g_free (lockfile_name);
+ g_warning ("Failed to remove lock file: %s", strerror (errno));
+ return -1;
+ }
+
+ /* Fork a child to run the sync while the parent responds to
+ * the client. */
+
+ pid = fork ();
+ switch (pid)
+ {
+ case 0:
+ /* Child. Carry on to sync. */
+ break;
+ case -1:
+ /* Parent when error. */
+ g_warning ("%s: failed to fork sync child: %s\n",
+ __FUNCTION__,
+ strerror (errno));
+ return -1;
+ break;
+ default:
+ /* Parent. Return, in order to respond to client. */
+ return 0;
+ break;
+ }
+
+ /* Open the lock file. */
+
+ fd = open (lockfile_name,
+ O_RDWR | O_CREAT | O_EXCL,
+ S_IWUSR | S_IRUSR | S_IROTH | S_IRGRP /* "-rw-r--r--" */);
+ if (fd == -1)
+ {
+ if (errno == EEXIST)
+ return 11;
+ g_warning ("Failed to open lock file '%s' (child): %s",
+ lockfile_name,
+ strerror (errno));
+ g_free (lockfile_name);
+ return -10;
+ }
+
+ /* Write the current time and user to the lock file. */
+
+ {
+ const char *output;
+ int count, left;
+ time_t now;
+
+ time (&now);
+ output = ctime (&now);
+ left = strlen (output);
+ while (1)
+ {
+ count = write (fd, output, left);
+ if (count < 0)
+ {
+ if (errno == EINTR || errno == EAGAIN) continue;
+ g_warning ("%s: write: %s", __FUNCTION__, strerror (errno));
+ goto exit;
+ }
+ if (count == left) break;
+ left -= count;
+ output += count;
+ }
+
+ output = current_user;
+ left = strlen (output);
+ while (1)
+ {
+ count = write (fd, output, left);
+ if (count < 0)
+ {
+ if (errno == EINTR || errno == EAGAIN) continue;
+ g_warning ("%s: write: %s", __FUNCTION__, strerror (errno));
+ goto exit;
+ }
+ if (count == left) break;
+ left -= count;
+ output += count;
+ }
+
+ while (1)
+ {
+ count = write (fd, "\n", 1);
+ if (count < 0)
+ {
+ if (errno == EINTR || errno == EAGAIN) continue;
+ g_warning ("%s: write: %s", __FUNCTION__, strerror (errno));
+ goto exit;
+ }
+ if (count == 1) break;
+ }
+ }
+
/* Sync. */
gchar *script_working_dir = g_path_get_dirname (sync_script);
@@ -1253,17 +1375,17 @@
&script_out, &script_err, &script_exit, &error))
{
g_warning ("Failed to execute %s: %s", sync_script, error->message);
- ret = -1;
- goto exit;
+ ret = -10;
+ goto free_exit;
}
if (script_exit != 0)
{
g_warning ("%s returned a non-zero exit code.", sync_script);
- ret = -1;
+ ret = -10;
}
- exit:
+ free_exit:
g_free (script_working_dir);
g_strfreev (argv);
@@ -1271,20 +1393,24 @@
g_free (script_err);
g_free (error);
+ exit:
+
/* Close the lock file. */
if (close (fd))
{
- g_warning ("Failed to close lock file: %s", strerror (errno));
- return -1;
+ g_free (lockfile_name);
+ g_warning ("Failed to close lock file (child): %s", strerror (errno));
+ return -10;
}
/* Remove the lock file. */
if (unlink (lockfile_name))
{
- g_warning ("Failed to remove lock file: %s", strerror (errno));
- return -1;
+ g_free (lockfile_name);
+ g_warning ("Failed to remove lock file (child): %s", strerror (errno));
+ return -10;
}
g_free (lockfile_name);
@@ -1295,15 +1421,17 @@
/**
* @brief Determine if the administrator is synchronizing with a feed.
*
- * @param[in] sync_script The file name of the synchronization script.
+ * @param[in] sync_script The file name of the synchronization script.
+ * @param[out] timestamp Newly allocated time that sync started, if syncing.
+ * @param[out] user Newly allocated user who started sync, if syncing.
*
- * @return TRUE if the administrator is currently synchronizing with the feed,
- * FALSE if not.
+ * @return 0 success, 1 success when sync in progress, -1 error.
*/
-gboolean
-openvas_currently_syncing (const gchar * sync_script)
+int
+openvas_current_sync (const gchar *sync_script, gchar **timestamp, gchar **user)
{
- gchar *lockfile_name;
+ gchar *lockfile_name, *content, **lines;
+ GError *error = NULL;
g_assert (sync_script);
@@ -1311,14 +1439,37 @@
"openvas-feed-sync",
sync_script,
NULL);
- if (g_file_test (lockfile_name, G_FILE_TEST_EXISTS))
+ if (!g_file_get_contents (lockfile_name, &content, NULL, &error))
{
+ if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)
+ || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_ACCES))
+ {
+ g_error_free (error);
+ g_free (lockfile_name);
+ return 0;
+ }
+
+ g_warning ("%s: %s", __FUNCTION__, error->message);
+ g_error_free (error);
g_free (lockfile_name);
- return TRUE;
+ return -1;
}
+ lines = g_strsplit (content, "\n", 2);
+ g_free (content);
+ if (lines[0] && lines[1])
+ {
+ *timestamp = g_strdup (lines[0]);
+ *user = g_strdup (lines[1]);
+
+ g_free (lockfile_name);
+ g_strfreev (lines);
+ return 1;
+ }
+
g_free (lockfile_name);
- return FALSE;
+ g_strfreev (lines);
+ return -1;
}
/**
Modified: trunk/openvas-administrator/src/admin.h
===================================================================
--- trunk/openvas-administrator/src/admin.h 2010-01-29 13:50:10 UTC (rev 6590)
+++ trunk/openvas-administrator/src/admin.h 2010-01-29 14:29:24 UTC (rev 6591)
@@ -48,8 +48,8 @@
int openvas_admin_remove_user (const gchar *, const gchar *);
gboolean openvas_admin_set_rules (const gchar *, const gchar *, const gchar *);
-int openvas_sync_feed (const gchar *);
-gboolean openvas_currently_syncing (const gchar *);
+int openvas_sync_feed (const gchar *, const gchar *);
+int openvas_current_sync (const gchar *, gchar **, gchar **);
gboolean openvas_sync_script_perform_selftest (const gchar *, gchar **);
gboolean openvas_get_sync_script_identification (const gchar *, gchar **);
gboolean openvas_get_sync_script_description (const gchar *, gchar **);
Modified: trunk/openvas-administrator/src/oap.c
===================================================================
--- trunk/openvas-administrator/src/oap.c 2010-01-29 13:50:10 UTC (rev 6590)
+++ trunk/openvas-administrator/src/oap.c 2010-01-29 14:29:24 UTC (rev 6591)
@@ -490,6 +490,16 @@
/* Global variables. */
/**
+ * @brief Hack for returning forked process status from the callbacks.
+ */
+int current_error;
+
+/**
+ * @brief Hack for returning fork status to caller.
+ */
+int forked;
+
+/**
* @brief Flag indicating whether MODIFY_SETTINGS command is served.
*/
gboolean enable_modify_settings = FALSE;
@@ -1381,26 +1391,56 @@
{
gchar *feed_description = NULL;
gchar *feed_identification = NULL;
+
+ assert (current_credentials.username);
+
if (openvas_get_sync_script_description (sync_script,
- &feed_description) &&
- openvas_get_sync_script_identification (sync_script,
- &feed_identification))
+ &feed_description)
+ && openvas_get_sync_script_identification (sync_script,
+ &feed_identification))
{
+ gchar *user, *timestamp;
+ int syncing;
gchar **ident = g_strsplit (feed_identification, "|", 6);
- SEND_TO_CLIENT_OR_FAIL ("<describe_feed_response"
- " status=\"" STATUS_OK "\""
- " status_text=\"" STATUS_OK_TEXT "\">");
- SEND_TO_CLIENT_OR_FAIL ("<feed>");
- SENDF_TO_CLIENT_OR_FAIL ("<name>%s</name>", ident[3]);
- SENDF_TO_CLIENT_OR_FAIL ("<description>%s</description>", feed_description);
- if (openvas_currently_syncing (sync_script))
+
+ syncing = openvas_current_sync (sync_script, ×tamp, &user);
+ if (syncing < 0
+ || ident[0] == NULL
+ || ident[1] == NULL
+ || ident[2] == NULL
+ || ident[3] == NULL)
{
- SEND_TO_CLIENT_OR_FAIL ("<currently_syncing />");
+ g_strfreev (ident);
+ SEND_TO_CLIENT_OR_FAIL (XML_INTERNAL_ERROR ("describe_feed"));
}
- SEND_TO_CLIENT_OR_FAIL ("</feed>");
- SEND_TO_CLIENT_OR_FAIL ("</describe_feed_response>");
- g_strfreev (ident);
- g_free (feed_description);
+ else
+ {
+
+ SENDF_TO_CLIENT_OR_FAIL
+ ("<describe_feed_response"
+ " status=\"" STATUS_OK "\""
+ " status_text=\"" STATUS_OK_TEXT "\">"
+ "<feed>"
+ "<name>%s</name>"
+ "<description>%s</description>",
+ ident[3],
+ feed_description);
+ g_strfreev (ident);
+ if (syncing > 0)
+ {
+ SENDF_TO_CLIENT_OR_FAIL ("<currently_syncing>"
+ "<timestamp>%s</timestamp>"
+ "<user>%s</user>"
+ "</currently_syncing>",
+ timestamp ? timestamp : "",
+ user ? user : "");
+ g_free (timestamp);
+ g_free (user);
+ }
+ SEND_TO_CLIENT_OR_FAIL ("</feed>"
+ "</describe_feed_response>");
+ }
+
g_free (feed_identification);
}
else
@@ -1414,6 +1454,7 @@
SEND_TO_CLIENT_OR_FAIL ("</feed>");
SEND_TO_CLIENT_OR_FAIL ("</describe_feed_response>");
}
+ g_free (feed_description);
set_client_state (CLIENT_AUTHENTIC);
break;
}
@@ -1600,14 +1641,45 @@
break;
case CLIENT_SYNC_FEED:
- switch (openvas_sync_feed (sync_script))
+ assert (current_credentials.username);
+ if (forked == 2)
+ /* Prevent the forked child from forking again, as then both
+ * forked children would be using the same server session. */
+ abort (); // FIX respond with error or something
+ else switch (openvas_sync_feed (sync_script,
+ current_credentials.username))
{
case 0:
- SEND_TO_CLIENT_OR_FAIL (XML_OK ("sync_feed"));
+ SEND_TO_CLIENT_OR_FAIL (XML_OK_REQUESTED ("sync_feed"));
+ forked = 1;
break;
case 1:
SEND_TO_CLIENT_OR_FAIL (XML_ERROR_BUSY ("sync_feed"));
break;
+ case 2:
+ /* Forked sync process: success. */
+ current_error = 2;
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Dummy error for current_error");
+ break;
+ case 11:
+ /* Forked sync process: success busy. */
+ current_error = 2;
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Dummy error for current_error");
+ break;
+ case -10:
+ /* Forked sync process: error. */
+ current_error = -10;
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ "Dummy error for current_error");
+ break;
default:
assert (0);
case -1:
@@ -1776,6 +1848,7 @@
void
init_oap_process ()
{
+ forked = 0;
/* Create the XML parser. */
xml_parser.start_element = oap_xml_handle_start_element;
xml_parser.end_element = oap_xml_handle_end_element;
@@ -1814,6 +1887,7 @@
if (xml_context == NULL) return -1;
+ current_error = 0;
success = g_markup_parse_context_parse (xml_context,
from_client + from_client_start,
from_client_end - from_client_start,
@@ -1831,7 +1905,16 @@
else if (g_error_matches (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_INVALID_CONTENT))
- tracef (" client error: G_MARKUP_ERROR_INVALID_CONTENT\n");
+ {
+ if (current_error)
+ {
+ /* This is the return status for a forked child. */
+ forked = 2; /* Prevent further forking. */
+ g_error_free (error);
+ return current_error;
+ }
+ tracef (" client error: G_MARKUP_ERROR_INVALID_CONTENT\n");
+ }
else if (g_error_matches (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE))
@@ -1849,5 +1932,7 @@
return err;
}
from_client_end = from_client_start = 0;
+ /* The Manager returns a special value here if a fork happened, because
+ * the caller needs to recreate the Scanner connection in the parent. */
return 0;
}
Modified: trunk/openvas-administrator/src/oapd.c
===================================================================
--- trunk/openvas-administrator/src/oapd.c 2010-01-29 13:50:10 UTC (rev 6590)
+++ trunk/openvas-administrator/src/oapd.c 2010-01-29 14:29:24 UTC (rev 6591)
@@ -251,6 +251,33 @@
if (ret == 0)
/* Processed all input. */
client_input_stalled = 0;
+ else if (ret == 2)
+ {
+ /* Now in a process forked to run a sync, which has
+ * successfully finished the sync (or where the sync was
+ * already in progress). Close the client
+ * connection, as the parent process has continued the
+ * session with the client. */
+#if 0
+ // FIX seems to close parent connections, maybe just do part of this
+ openvas_server_free (client_socket,
+ *client_session,
+ *client_credentials);
+#endif
+ return 0;
+ }
+ else if (ret == -10)
+ {
+ /* Now in a process forked to run a sync, which has
+ * failed in starting the sync. */
+#if 0
+ // FIX as above
+ openvas_server_free (client_socket,
+ *client_session,
+ *client_credentials);
+#endif
+ return -1;
+ }
else if (ret == -1 || ret == -4)
{
/* Error. Write rest of to_client to client, so that the
@@ -450,6 +477,33 @@
if (ret == 0)
/* Processed all input. */
client_input_stalled = 0;
+ else if (ret == 2)
+ {
+ /* Now in a process forked to run a sync, which has
+ * successfully finished the sync (or where the sync was
+ * already in progress). Close the client
+ * connection, as the parent process has continued the
+ * session with the client. */
+#if 0
+ // FIX seems to close parent connections, maybe just do part of this
+ openvas_server_free (client_socket,
+ *client_session,
+ *client_credentials);
+#endif
+ return 0;
+ }
+ else if (ret == -10)
+ {
+ /* Now in a process forked to run a sync, which has
+ * failed in starting the sync. */
+#if 0
+ // FIX as above
+ openvas_server_free (client_socket,
+ *client_session,
+ *client_credentials);
+#endif
+ return -1;
+ }
else if (ret == -1 || ret == -4)
{
/* Error. Write rest of to_client to client, so that the
Modified: trunk/openvas-administrator/src/openvasad.c
===================================================================
--- trunk/openvas-administrator/src/openvasad.c 2010-01-29 13:50:10 UTC (rev 6590)
+++ trunk/openvas-administrator/src/openvasad.c 2010-01-29 14:29:24 UTC (rev 6591)
@@ -63,6 +63,8 @@
#include <fcntl.h>
#include <gnutls/gnutls.h>
#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <openvas_logging.h>
#include <openvas_server.h>
@@ -682,20 +684,70 @@
" synchronization.");
exit (EXIT_FAILURE);
}
- switch (openvas_sync_feed (sync_script))
+
+ switch (openvas_sync_feed (sync_script,
+ "openvasad command line user"))
{
case 0:
- g_message ("The feed has been successfully synchronized.");
- exit (EXIT_SUCCESS);
+ {
+ int status;
+
+ /* Parent on success. */
+
+ while (wait (&status) < 0)
+ {
+ if (errno == ECHILD)
+ {
+ g_warning ("Failed to get child exit status");
+ exit (EXIT_FAILURE);
+ }
+ if (errno == EINTR) continue;
+ g_warning ("wait: %s", strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+ if (WIFEXITED (status))
+ switch (WEXITSTATUS (status))
+ {
+ case EXIT_SUCCESS:
+ g_message ("Feed synchronization successfull.");
+ exit (EXIT_SUCCESS);
+ break;
+ case 2:
+ g_warning ("Feed is already synchronizing, exiting.");
+ exit (EXIT_FAILURE);
+ break;
+ case EXIT_FAILURE:
+ g_message ("Error during synchronization.");
+ exit (EXIT_FAILURE);
+ break;
+ }
+ g_message ("Error during synchronization.");
+ exit (EXIT_FAILURE);
+ }
break;
case 1:
- g_warning ("Feed is already being synchronized, aborting");
+ /* Parent. */
+ g_warning ("Feed is already synchronizing, exiting.");
exit (EXIT_FAILURE);
break;
+ case 2:
+ /* Child on success. */
+ exit (EXIT_SUCCESS);
+ break;
+ case 11:
+ /* Child, someone else got the lock. */
+ exit (2);
+ break;
+ case -10:
+ /* Child error. */
+ exit (EXIT_FAILURE);
+ break;
default:
assert (0);
case -1:
- g_warning ("Failed to execute synchronization script (%s)!", sync_script);
+ /* Parent error. */
+ g_warning ("Failed to execute synchronization script (%s)!",
+ sync_script);
exit (EXIT_FAILURE);
break;
}
More information about the Openvas-commits
mailing list