Implemented startup script registration command-line interface.
authorshort <>
Sun, 23 May 2004 17:40:30 +0000 (17:40 +0000)
committershort <>
Sun, 23 May 2004 17:40:30 +0000 (17:40 +0000)
Fixes of the startup script engine.

src/Makefile.am
src/bundle-util.c [new file with mode: 0644]
src/bundle-util.h [new file with mode: 0644]
src/bundle.pl
src/main.c
src/startup-chkconfig.c [new file with mode: 0644]
src/startup-chkconfig.h [new file with mode: 0644]
src/startup.c [new file with mode: 0644]
src/startup.h [new file with mode: 0644]

index cb6d3ba..8c4a7f5 100644 (file)
@@ -41,7 +41,9 @@ if ENABLE_BUNDLE
 nodist_udpgate_SOURCES=bundle.c
 
 BUNDLE_SRCS= \
-               bundle.h
+               bundle.h \
+               bundle-util.c \
+               bundle-util.h
 
 EXTRA_DIST+= \
                bundle.pl
@@ -62,6 +64,10 @@ udpgate_SOURCES= \
                network.h \
                packet.c \
                packet.h \
+               startup-chkconfig.c \
+               startup-chkconfig.h \
+               startup.c \
+               startup.h \
                ui-line.c \
                ui-line.h \
                $(GNOME_SRCS) \
@@ -70,7 +76,7 @@ udpgate_SOURCES= \
 EXTRA_DIST+= \
                $(GLADE_IN)
 
-udpgate_CFLAGS=
+udpgate_CFLAGS=-DSYSCONFDIR="$(sysconfdir)"
 udpgate_LDADD=
 
 udpgate-ui-gnome-interface.$(OBJEXT): ui-gnome-callbacks.h
diff --git a/src/bundle-util.c b/src/bundle-util.c
new file mode 100644 (file)
index 0000000..83057b2
--- /dev/null
@@ -0,0 +1,152 @@
+/* $Id$
+ * UDP Gateway single-file bundle utility functions
+ * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
+ * 
+ * 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; exactly version 2 of June 1991 is required
+ * 
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include <glib/gmessages.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <glib/gmem.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+
+#include "bundle-util.h"       /* self */
+#include "bundle.h"
+
+
+static const guint8 *bundle_util_file_retrieve(guint32 *data_length_return,const gchar *pathname,const gchar *basename)
+{
+const guint8 *data;
+
+       g_return_val_if_fail(data_length_return!=NULL,NULL);
+       g_return_val_if_fail(pathname!=NULL,NULL);
+       g_return_val_if_fail(basename!=NULL,NULL);
+
+       data=g_hash_table_lookup(bundle_hash_new(),basename);
+       g_return_val_if_fail(data!=NULL,NULL);
+       *data_length_return=GUINT32_FROM_BE(*(guint32 *)data);
+       data+=sizeof(*data_length_return);
+
+       return data;
+}
+
+/* Returns TRUE if it safe to overwrite/unlink the file.
+ */
+static gboolean bundle_util_file_backup_conditional(const gchar *pathname,const gchar *basename)
+{
+const guint8 *data;
+guint32 data_length;
+int fd;
+guint8 *data_found;
+int got;
+char strftime_buffer[LINE_MAX];
+const gchar *destination;
+time_t time_current;
+
+       g_return_val_if_fail(pathname!=NULL,FALSE);
+       g_return_val_if_fail(basename!=NULL,FALSE);
+
+       if (!(data=bundle_util_file_retrieve(&data_length,pathname,basename)))
+               return FALSE;
+
+       if (-1==(fd=open(pathname,O_RDONLY))) {
+               if (errno==ENOENT)
+                       return TRUE;
+               else {
+                       g_warning(_("Error checking file modifications of \"%s\": %m"),pathname);
+                       return FALSE;
+                       }
+               }
+
+       /* WARNING: 'data_found' allocated in this block! */
+       data_found=g_malloc(data_length+1);
+       if (-1==(got=read(fd,data_found,data_length+1)))
+               g_warning(_("Error reading during the check of file modifications of \"%s\": %m"),pathname);
+       if (close(fd))
+               g_warning(_("Error closing the file \"%s\" during the check of its modifications: %m"),pathname);
+       g_free(data_found);
+
+       if (got==(int)data_length && !memcmp(data_found,data,data_length))
+               return TRUE;
+
+       time_current=time(NULL);        /* It is segfault to gmtime(NULL). */
+       if (!strftime(strftime_buffer,sizeof(strftime_buffer),"GMT%FT%T",gmtime(&time_current))) {
+               g_warning("strftime(3): %m");   /* shouldn't happen */
+               return FALSE;
+               }
+       destination=udpgate_printf_alloca("%s-%s-%d",pathname,strftime_buffer,(int)getpid());
+       if (rename(pathname,destination)) {
+               g_warning(_("Error renaming your modified file \"%s\" to the backup \"%s\", giving up: %m"),
+                               pathname,destination);
+               return FALSE;
+               }
+
+       return TRUE;
+}
+
+gboolean bundle_util_file_remove(const gchar *pathname,const gchar *basename)
+{
+       g_return_val_if_fail(pathname!=NULL,FALSE);
+       g_return_val_if_fail(basename!=NULL,FALSE);
+
+       if (!bundle_util_file_backup_conditional(pathname,basename))
+               return FALSE;
+
+       if (unlink(pathname) && errno!=ENOENT) {
+               g_warning(_("Error removing the file \"%s\": %m"),pathname);
+               return FALSE;
+               }
+       
+       return TRUE;
+}
+
+gboolean bundle_util_file_write(const gchar *pathname,const gchar *basename,mode_t pathname_mode)
+{
+const guint8 *data;
+guint32 data_length;
+int fd;
+
+       g_return_val_if_fail(pathname!=NULL,FALSE);
+       g_return_val_if_fail(basename!=NULL,FALSE);
+
+       if (!(data=bundle_util_file_retrieve(&data_length,pathname,basename)))
+               return FALSE;
+
+       if (!bundle_util_file_backup_conditional(pathname,basename))
+               return FALSE;
+
+       if (-1==(fd=open(pathname,O_WRONLY|O_CREAT|O_TRUNC,pathname_mode))) {
+               g_warning(_("Error opening the file \"%s\" for rewrite: %m"),pathname);
+               return FALSE;
+               }
+       if ((int)data_length!=write(fd,data,data_length)) {
+               g_warning(_("Error writing the data of the file \"%s\" being overwritten: %m"),pathname);
+               close(fd);      /* errors ignored */
+               return FALSE;
+               }
+       if (close(fd)) {
+               g_warning(_("Error closing the file \"%s\" after its rewrite: %m"),pathname);
+               return FALSE;
+               }
+       return TRUE;
+}
diff --git a/src/bundle-util.h b/src/bundle-util.h
new file mode 100644 (file)
index 0000000..482f92f
--- /dev/null
@@ -0,0 +1,35 @@
+/* $Id$
+ * Include file for UDP Gateway single-file bundle utility functions
+ * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
+ * 
+ * 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; exactly version 2 of June 1991 is required
+ * 
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _UDPGATE_BUNDLE_UTIL_H
+#define _UDPGATE_BUNDLE_UTIL_H 1
+
+
+#include <glib/gtypes.h>
+
+
+G_BEGIN_DECLS
+
+gboolean bundle_util_file_remove(const gchar *pathname,const gchar *basename);
+gboolean bundle_util_file_write(const gchar *pathname,const gchar *basename,mode_t pathname_mode);
+
+G_END_DECLS
+
+
+#endif /* _UDPGATE_BUNDLE_UTIL_H */
index fdd252b..ba30a48 100755 (executable)
@@ -42,6 +42,7 @@ print <<"EOH";
 GHashTable *bundle_hash_new(void)
 {
 static GHashTable *hash;
+/* Prefixed 32-bit network byte order file length. */
 EOH
 my @files;
 for my $pathname (@ARGV) {
@@ -57,6 +58,7 @@ for my $pathname (@ARGV) {
                        "filename"    =>$filename,
                        "filename_sym"=>$filename_sym,
                        };
+       $F=pack("N*",length($F)).$F;    # Prefix 32-bit network byte order file length.
        my $Fout=unpack "H*",$F;
        $Fout=~s/../0x$&,/g;
        $Fout=~s/(?:.....){1,16}/\t\t$&\n/g;
index a0917e6..4e38270 100644 (file)
@@ -37,6 +37,7 @@
 #include "ui-line.h"
 #include "network.h"
 #include "configuration.h"
+#include "startup.h"
 
 #ifdef HAVE_GNOME
 #include "ui-gnome.h"
@@ -53,6 +54,9 @@ int optarg_port=LOCAL_PORT_DEFAULT;
 static int optarg_start;
 static int optarg_stop;
 int optarg_no_fork;
+static int optarg_startup_query;
+static int optarg_startup_on;
+static int optarg_startup_off;
 
 void (*ui_interactive)(void);
 
@@ -74,19 +78,25 @@ static const struct poptOption popt_table[]={
 #else /* HAVE_GNOME */
 #define OPT_TEXT_IF_GNOME N_("(no Gnome UI compiled - stub only); --text must be first argument")
 #endif /* HAVE_GNOME */
-               UDPGATE_POPT(0  ,"text"   ,POPT_ARG_NONE                          ,&optarg_text   ,0,
-                               OPT_TEXT_IF_GNOME,NULL),
-#undef OPT_TEXT_IF_GNOME
-               UDPGATE_POPT('v',"verbose",POPT_ARG_NONE                          ,&optarg_verbose,0,
-                               N_("Display additional debug information"),NULL),
-               UDPGATE_POPT('p',"port"   ,POPT_ARG_INT |POPT_ARGFLAG_SHOW_DEFAULT,&optarg_port   ,0,
-                               N_("Listen on this UDP port"),NULL),
-               UDPGATE_POPT('s',"start"  ,POPT_ARG_NONE                          ,&optarg_start  ,0,
-                               N_("Start the daemon"),NULL),
-               UDPGATE_POPT('S',"stop"   ,POPT_ARG_NONE                          ,&optarg_stop   ,0,
+               UDPGATE_POPT(0  ,"text"         ,POPT_ARG_NONE                          ,&optarg_text         ,0,
+                               OPT_TEXT_IF_GNOME,NULL),                                                                  
+#undef OPT_TEXT_IF_GNOME                                                                          
+               UDPGATE_POPT('v',"verbose"      ,POPT_ARG_NONE                          ,&optarg_verbose      ,0,
+                               N_("Display additional debug information"),NULL),                                         
+               UDPGATE_POPT('p',"port"         ,POPT_ARG_INT |POPT_ARGFLAG_SHOW_DEFAULT,&optarg_port         ,0,
+                               N_("Listen on this UDP port"),NULL),                                                      
+               UDPGATE_POPT('s',"start"        ,POPT_ARG_NONE                          ,&optarg_start        ,0,
+                               N_("Start the daemon"),NULL),                                                             
+               UDPGATE_POPT('S',"stop"         ,POPT_ARG_NONE                          ,&optarg_stop         ,0,
                                N_("Stop the daemon"),NULL),
-               UDPGATE_POPT('1',"no-fork",POPT_ARG_NONE                          ,&optarg_no_fork,0,
+               UDPGATE_POPT('1',"no-fork"      ,POPT_ARG_NONE                          ,&optarg_no_fork      ,0,
                                N_("Do not detach from the current process"),NULL),
+               UDPGATE_POPT(0  ,"startup-query",POPT_ARG_NONE                          ,&optarg_startup_query,0,
+                               N_("Query the current state of the system startup registrance"),NULL),
+               UDPGATE_POPT(0  ,"startup-on"   ,POPT_ARG_NONE                          ,&optarg_startup_on   ,0,
+                               N_("Register for the automatic system startup"),NULL),
+               UDPGATE_POPT(0  ,"startup-off"  ,POPT_ARG_NONE                          ,&optarg_startup_off  ,0,
+                               N_("Unregister from the automatic system startup"),NULL),
 
 #undef UDPGATE_POPT
                POPT_TABLEEND
@@ -129,6 +139,7 @@ gboolean is_interactive;
 #ifdef HAVE_GNOME
 gboolean no_gnome;
 #endif /* HAVE_GNOME */
+int exit_rc=EXIT_SUCCESS;
 
 #if 0
        g_log_set_always_fatal(~(0
@@ -213,7 +224,10 @@ guint handler_id;
 
        is_interactive=(1
                        && !optarg_start
-                       && !optarg_stop);
+                       && !optarg_stop
+                       && !optarg_startup_query
+                       && !optarg_startup_on
+                       && !optarg_startup_off);
 
        /* Initialize UI here to catch all GLog errors below. */
        if (is_interactive
@@ -224,10 +238,38 @@ guint handler_id;
                g_error(_("No UI interface could be initialized"));
 
        if (!is_interactive) {
+
+               if (optarg_startup_query || optarg_startup_off || optarg_startup_on)
+                       startup_init();
+
                if (optarg_stop)
-                       network_stop();
+                       if (!network_stop())
+                               exit_rc=2;
+               if (optarg_startup_query) {
+gboolean is_on;
+
+                       if (startup_query(&is_on)) {
+                               g_message((is_on
+                                               ? _("System startup registrance is turned on.")
+                                               : _("System startup registrance is turned off.")));
+                               if (exit_rc<2)
+                                       exit_rc=(is_on ? 0 : 1);
+                               }
+                       else
+                               exit_rc=2;
+                       }
+               if (optarg_startup_off) {
+                       if (!startup_off())
+                               exit_rc=2;
+                       }
+               if (optarg_startup_on) {
+                       if (!startup_on())
+                               exit_rc=2;
+                       }
                if (optarg_start)
-                       network_start(optarg_port);
+                       if (!network_start(optarg_port))
+                               exit_rc=2;
+
                network_detach();
                }
        else
@@ -235,5 +277,5 @@ guint handler_id;
 
        configuration_write();
 
-       return EXIT_SUCCESS;
+       exit(exit_rc);
 }
diff --git a/src/startup-chkconfig.c b/src/startup-chkconfig.c
new file mode 100644 (file)
index 0000000..c397f46
--- /dev/null
@@ -0,0 +1,126 @@
+/* $Id$
+ * UDP Gateway utility startup scripts support using chkconfig(8)
+ * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
+ * 
+ * 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; exactly version 2 of June 1991 is required
+ * 
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include <glib/gmessages.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <glib/gmem.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "startup-chkconfig.h" /* self */
+
+#ifdef ENABLE_BUNDLE
+#include "bundle-util.h"
+#endif
+
+
+/* Config: */
+#define INIT_D_PATHNAME G_STRINGIFY(SYSCONFDIR) "/rc.d/init.d/" PACKAGE
+
+
+#define STATUS_0_1(status) ( \
+               !(WIFEXITED((status)) && (WEXITSTATUS((status))==0 || WEXITSTATUS((status))==1) \
+                                               && !WIFSIGNALED((status)) \
+                                               && !WIFSTOPPED((status))) \
+                               ? -1 : WEXITSTATUS((status)))
+
+gboolean startup_chkconfig_init(void)
+{
+static gboolean r,r_set=FALSE;
+
+       if (!r_set) {
+int status;
+const gchar *command="chkconfig " PACKAGE;
+
+               status=system(command);
+               if (STATUS_0_1(status)<0) {
+                       g_warning(_("Error checking validity of chkconfig(8) setup; automatic startup disabled; failed command: %s"),command);
+                       r=FALSE;
+                       }
+               else
+                       r=TRUE;
+               r_set=TRUE;
+               }
+       return r;
+}
+
+gboolean startup_chkconfig_query(gboolean *is_on)
+{
+int status,status_0_1;
+const gchar *command="chkconfig " PACKAGE;
+
+       g_return_val_if_fail(is_on!=NULL,FALSE);
+
+       if (!startup_chkconfig_init())
+               return FALSE;
+
+       status=system(command);
+       status_0_1=STATUS_0_1(status);
+       if (status_0_1<0) {
+               g_warning(_("Error checking registrance of this program automatic startup by: %s"),command);
+               return FALSE;
+               }
+       *is_on=(status_0_1==0);
+       return TRUE;
+}
+
+gboolean startup_chkconfig_on(void)
+{
+int status;
+const gchar *command="chkconfig --add " PACKAGE;
+
+       if (!startup_chkconfig_init())
+               return FALSE;
+
+#ifdef ENABLE_BUNDLE
+       if (!bundle_util_file_write(INIT_D_PATHNAME,PACKAGE ".init",0755))
+               return FALSE;
+#endif /* ENABLE_BUNDLE */
+       status=system(command);
+       if (0!=STATUS_0_1(status)) {
+               g_warning(_("Error registering automatic program startup by: %s"),command);
+               return FALSE;
+               }
+       return TRUE;
+}
+
+gboolean startup_chkconfig_off(void)
+{
+const gchar *command="chkconfig --del " PACKAGE;
+int status;
+
+       if (!startup_chkconfig_init())
+               return FALSE;
+
+       status=system(command);
+       if (0!=STATUS_0_1(status)) {
+               g_warning(_("Error removing program's system startup registrance by: %s"),command);
+               return FALSE;
+               }
+#ifdef ENABLE_BUNDLE
+       if (!bundle_util_file_remove(INIT_D_PATHNAME,PACKAGE ".init"))
+               return FALSE;
+#endif /* ENABLE_BUNDLE */
+       return TRUE;
+}
diff --git a/src/startup-chkconfig.h b/src/startup-chkconfig.h
new file mode 100644 (file)
index 0000000..829d21d
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id$
+ * Include file for UDP Gateway utility startup scripts support using chkconfig(8)
+ * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
+ * 
+ * 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; exactly version 2 of June 1991 is required
+ * 
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _UDPGATE_STARTUP_CHKCONFIG_H
+#define _UDPGATE_STARTUP_CHKCONFIG_H 1
+
+
+#include <glib/gtypes.h>
+
+
+G_BEGIN_DECLS
+
+gboolean startup_chkconfig_init(void);
+gboolean startup_chkconfig_query(gboolean *is_on);
+gboolean startup_chkconfig_on(void);
+gboolean startup_chkconfig_off(void);
+
+G_END_DECLS
+
+
+#endif /* _UDPGATE_STARTUP_CHKCONFIG_H */
diff --git a/src/startup.c b/src/startup.c
new file mode 100644 (file)
index 0000000..16114fd
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id$
+ * UDP Gateway utility startup scripts support
+ * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
+ * 
+ * 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; exactly version 2 of June 1991 is required
+ * 
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include <glib/gmessages.h>
+
+#include "startup.h"   /* self */
+#include "startup-chkconfig.h"
+
+
+/* FIXME: Provide some layer for multiple 'startup' handling backends. */
+
+
+gboolean startup_init(void)
+{
+       return startup_chkconfig_init();
+}
+
+gboolean startup_query(gboolean *is_on)
+{
+       g_return_val_if_fail(is_on!=NULL,FALSE);
+
+       return startup_chkconfig_query(is_on);
+}
+
+gboolean startup_on(void)
+{
+       return startup_chkconfig_on();
+}
+
+gboolean startup_off(void)
+{
+       return startup_chkconfig_off();
+}
diff --git a/src/startup.h b/src/startup.h
new file mode 100644 (file)
index 0000000..da8727d
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id$
+ * Include file for UDP Gateway utility startup scripts support
+ * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
+ * 
+ * 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; exactly version 2 of June 1991 is required
+ * 
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _UDPGATE_STARTUP_H
+#define _UDPGATE_STARTUP_H 1
+
+
+#include <glib/gtypes.h>
+
+
+G_BEGIN_DECLS
+
+gboolean startup_init(void);
+gboolean startup_query(gboolean *is_on);
+gboolean startup_on(void);
+gboolean startup_off(void);
+
+G_END_DECLS
+
+
+#endif /* _UDPGATE_STARTUP_H */