cf28648cf90d3e6cc490d4b2d37f13b532ba41c3
[udpgate.git] / src / startup-debian.c
1 /* $Id$
2  * UDP Gateway utility startup scripts support using debian(8)
3  * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include <glib/gmessages.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #include <glib/gmem.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <stdio.h>
32 #include <ctype.h>
33
34 #include "startup-debian.h"     /* self */
35
36 #ifdef ENABLE_BUNDLE
37 #include "bundle-util.h"
38 #endif
39
40
41 /* Config: */
42 /* Do not: /etc/rc.d/init.d/...
43  * to comply with http://www.linuxbase.org/spec/booksets/LSB-Core/LSB-Core.html#INITSRCINSTRM
44  */
45 #define INIT_D_PATHNAME G_STRINGIFY(SYSCONFDIR) "/init.d/" PACKAGE
46
47
48 #define STATUS_0_1(status) ( \
49                 !(WIFEXITED((status)) && (WEXITSTATUS((status))==0 || WEXITSTATUS((status))==1) \
50                                                 && !WIFSIGNALED((status)) \
51                                                 && !WIFSTOPPED((status))) \
52                                 ? -1 : WEXITSTATUS((status)))
53
54
55 static gboolean udpgate_startup_debian_init(UdpgateStartup *udpgate_startup)
56 {
57 int status;
58 /* ">/dev/null" for: Adding system startup for /etc/init.d/PACKAGE ...
59  * "2>/dev/null" for: bash: update-rc.d: command not found
60  */
61 const gchar *command="update-rc.d -n " PACKAGE " defaults &>/dev/null";
62
63         g_return_val_if_fail(UDPGATE_IS_STARTUP_DEBIAN(udpgate_startup),FALSE);
64
65         status=system(command);
66         if (STATUS_0_1(status)<0) {
67                 g_warning(_("Error checking validity of update-rc.d(8) setup; automatic startup disabled; failed command: %s"),command);
68                 return FALSE;
69                 }
70         return TRUE;
71 }
72
73 static gboolean udpgate_startup_debian_query(UdpgateStartup *udpgate_startup,gboolean *is_on)
74 {
75 const gchar *command="update-rc.d -n " PACKAGE " defaults 2>/dev/null";
76 static char buffer[0x1000];
77 char *s;
78 size_t fread_got;
79 FILE *f;
80
81         g_return_val_if_fail(UDPGATE_IS_STARTUP_DEBIAN(udpgate_startup),FALSE);
82
83         if (!(f=popen(command,"r"))) {
84 #if 0
85                 g_warning(_("Error checking registrance of this program automatic startup opening \"%s\": %m"),command);
86 #endif
87                 return FALSE;
88                 }
89         fread_got=fread(buffer,1,sizeof(buffer),f);
90         if (fclose(f)) {
91 #if 0
92                 g_warning(_("Error checking registrance of this program automatic startup closing \"%s\": %m"),command);
93 #endif
94                 return FALSE;
95         }
96         if (fread_got<=0 || fread_got>=sizeof(buffer)) {
97 #if 0
98                 g_warning(_("Error checking registrance of this program automatic startup reading \"%s\": %m"),command);
99 #endif
100                 return FALSE;
101         }
102         buffer[fread_got]='\0';
103         for (s=buffer;*s && isspace(*s);s++);
104         /* Fortunately update-rc.d(8) is just a dumb script without messages localization. */
105
106 #define TEXT_ADDING_SYSTEM_STARTUP_FOR "Adding system startup for"
107 /*
108  Adding system startup for /etc/init.d/PACKAGE ...
109    /etc/rc0.d/K20PACKAGE -> ../init.d/PACKAGE
110 ...
111    /etc/rc5.d/S20PACKAGE -> ../init.d/PACKAGE
112 */
113         if (!strncasecmp(s,TEXT_ADDING_SYSTEM_STARTUP_FOR,strlen(TEXT_ADDING_SYSTEM_STARTUP_FOR))) {
114                 if (is_on)
115                         *is_on=FALSE;
116                 return TRUE;
117                 }
118
119 #define TEXT_SYSTEM_STARTUP_LINKS_FOR "System startup links for"
120 /*
121  System startup links for /etc/init.d/PACKAGE already exist.
122 */
123         if (!strncasecmp(s,TEXT_SYSTEM_STARTUP_LINKS_FOR,strlen(TEXT_SYSTEM_STARTUP_LINKS_FOR))) {
124                 if (is_on)
125                         *is_on=TRUE;
126                 return TRUE;
127                 }
128
129         /* Failed: */
130         if ((s=strchr(buffer,'\n')))
131                 *s='\0';
132         g_warning(_("Error checking registrance of this program, unknown output of \"%s\": %s"),command,buffer);
133         return FALSE;
134 }
135
136 static gboolean udpgate_startup_debian_on(UdpgateStartup *udpgate_startup)
137 {
138 /* Do not: " >/dev/null"
139  * as it is useful for: Adding system startup for /etc/init.d/PACKAGE ...
140  * but it is bad for:
141  *       Adding system startup for /etc/init.d/PACKAGE ...
142  *         /etc/rc0.d/K20PACKAGE -> ../init.d/PACKAGE
143  *      update-rc.d: symlink: Permission denied
144  * as the second line also gets hidden.
145  */
146 const gchar *command="update-rc.d " PACKAGE " defaults";
147 int status;
148
149         g_return_val_if_fail(UDPGATE_IS_STARTUP_DEBIAN(udpgate_startup),FALSE);
150
151 #ifdef ENABLE_BUNDLE
152         if (!bundle_util_file_write(
153                         INIT_D_PATHNAME,        /* pathname */
154                         PACKAGE ".init",        /* basename */
155                         0755,   /* pathname_mode */
156                         TRUE))  /* pathname_backup */
157                 return FALSE;
158 #endif /* ENABLE_BUNDLE */
159
160         status=system(command);
161
162         if (0!=STATUS_0_1(status)) {
163                 g_warning(_("Error registering automatic program startup by: %s"),command);
164                 return FALSE;
165                 }
166         return TRUE;
167 }
168
169 static gboolean udpgate_startup_debian_off(UdpgateStartup *udpgate_startup)
170 {
171 /* Do not: " >/dev/null"
172  * as it is useful for: Removing any system startup links for /etc/init.d/PACKAGE ...
173  * but it is bad for:
174  *       Removing any system startup links for /etc/init.d/PACKAGE ...
175  *         /etc/rc0.d/S30PACKAGE
176  *       update-rc.d: unlink: Permission denied
177  * as the second line also gets hidden.
178  */
179 /* "-f" can be prevented for: ENABLE_BUNDLE
180  * by removing 'INIT_D_PATHNAME' first but it would still not work for
181  * regular non-bundled packaging.
182  */
183 const gchar *command="update-rc.d -f " PACKAGE " remove";
184 int status;
185
186         g_return_val_if_fail(UDPGATE_IS_STARTUP_DEBIAN(udpgate_startup),FALSE);
187
188 #ifdef ENABLE_BUNDLE
189         /* init.d file must no longer exist for: update-rc.d PACKAGE remove
190          * without using its: -f|--force
191          */
192         if (!bundle_util_file_remove(INIT_D_PATHNAME,PACKAGE ".init"))
193                 return FALSE;
194 #endif /* ENABLE_BUNDLE */
195
196         status=system(command);
197         if (0!=STATUS_0_1(status)) {
198                 g_warning(_("Error removing program's system startup registrance by: %s"),command);
199                 return FALSE;
200                 }
201
202         return TRUE;
203 }
204
205 static void udpgate_startup_debian_class_init (UdpgateStartupDebianClass *class)
206 {
207         UdpgateStartupClass *udpgate_startup_class = UDPGATE_STARTUP_CLASS(class);
208
209         udpgate_startup_class->init = udpgate_startup_debian_init;
210         udpgate_startup_class->query = udpgate_startup_debian_query;
211         udpgate_startup_class->on = udpgate_startup_debian_on;
212         udpgate_startup_class->off = udpgate_startup_debian_off;
213 }
214
215 GType udpgate_startup_debian_get_type(void)
216 {
217   static GType udpgate_startup_debian_type=0;
218
219   if (!udpgate_startup_debian_type) {
220                 static const GTypeInfo udpgate_startup_debian_info={
221                         sizeof(UdpgateStartupDebianClass),
222                         NULL,           /* base_init */
223                         NULL,           /* base_finalize */
224                         (GClassInitFunc)udpgate_startup_debian_class_init,
225                         NULL,           /* class_finalize */
226                         NULL,           /* class_data */
227                         sizeof(UdpgateStartupDebian),
228                         0,              /* n_preallocs */
229                         NULL,           /* instance_init */
230                         NULL,           /* value_table */
231       };
232
233                 udpgate_startup_debian_type=g_type_register_static(UDPGATE_TYPE_STARTUP,"UdpgateStartupDebian",
234                                  &udpgate_startup_debian_info,0);
235     }
236
237   return udpgate_startup_debian_type;
238 }