1 /*
2  *
3   ***** BEGIN LICENSE BLOCK *****
4 
5   Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
6 
7   This file is part of CLIXON.
8 
9   Licensed under the Apache License, Version 2.0 (the "License");
10   you may not use this file except in compliance with the License.
11   You may obtain a copy of the License at
12 
13     http://www.apache.org/licenses/LICENSE-2.0
14 
15   Unless required by applicable law or agreed to in writing, software
16   distributed under the License is distributed on an "AS IS" BASIS,
17   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   See the License for the specific language governing permissions and
19   limitations under the License.
20 
21   Alternatively, the contents of this file may be used under the terms of
22   the GNU General Public License Version 3 or later (the "GPL"),
23   in which case the provisions of the GPL are applicable instead
24   of those above. If you wish to allow use of your version of this file only
25   under the terms of the GPL, and not to allow others to
26   use your version of this file under the terms of Apache License version 2,
27   indicate your decision by deleting the provisions above and replace them with
28   the  notice and other provisions required by the GPL. If you do not delete
29   the provisions above, a recipient may use your version of this file under
30   the terms of any one of the Apache License version 2 or the GPL.
31 
32   ***** END LICENSE BLOCK *****
33 
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #include "clixon_config.h" /* generated by config & autoconf */
38 #endif
39 
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <stdarg.h>
45 #include <signal.h>
46 #include <syslog.h>
47 #include <errno.h>
48 
49 /* clicon */
50 #include "clixon_err.h"
51 #include "clixon_log.h"
52 #include "clixon_sig.h"
53 
54 /*! Set a signal handler.
55  * @param[in]  signo      Signal number
56  * @param[in]  handler    Function to call when signal occurs
57  * @param[out] oldhandler Pointer to old handler
58  */
59 int
set_signal(int signo,void (* handler)(int),void (** oldhandler)(int))60 set_signal(int     signo,
61 	   void  (*handler)(int),
62 	   void (**oldhandler)(int))
63 {
64 #if defined(HAVE_SIGACTION)
65     struct sigaction sold, snew;
66 
67     snew.sa_handler = handler;
68     sigemptyset(&snew.sa_mask);
69      snew.sa_flags = 0;
70      if (sigaction (signo, &snew, &sold) < 0){
71 	clicon_err(OE_UNIX, errno, "sigaction");
72 	return -1;
73      }
74      if (oldhandler)
75 	 *oldhandler = sold.sa_handler;
76     return 0;
77 #elif defined(HAVE_SIGVEC)
78     assert(0);
79     return 0;
80 #endif
81 }
82 
83 
84 /*! Block signal.
85  * @param[in] sig   Signal number to block, If 0, block all signals
86  */
87 void
clicon_signal_block(int sig)88 clicon_signal_block (int sig)
89 {
90 	sigset_t
91 		set;
92 
93 	sigemptyset (&set);
94 	if (sig)
95 		sigaddset (&set, sig);
96 	else
97 		sigfillset (&set);
98 
99 	sigprocmask (SIG_BLOCK, &set, NULL);
100 }
101 
102 /*! Unblock signal.
103  * @param[in] sig   Signal number to unblock. If 0, unblock all signals
104  */
105 void
clicon_signal_unblock(int sig)106 clicon_signal_unblock (int sig)
107 {
108 	sigset_t
109 		set;
110 
111 	sigemptyset (&set);
112 	if (sig)
113 		sigaddset (&set, sig);
114 	else
115 		sigfillset (&set);
116 
117 	sigprocmask (SIG_UNBLOCK, &set, NULL);
118 }
119 
120 /*! Read pidfile and return pid, if any
121  *
122  * @param[in]  pidfile  Name of pidfile
123  * @param[out] pid0     Process id of (eventual) existing daemon process
124  * @retval    0         OK. if pid > 0 old process exists w that pid
125  * @retval    -1        Error, and clicon_err() called
126  */
127 int
pidfile_get(char * pidfile,pid_t * pid0)128 pidfile_get(char  *pidfile,
129 	    pid_t *pid0)
130 {
131     FILE   *f;
132     char   *ptr;
133     char    buf[32];
134     pid_t   pid;
135 
136     if ((f = fopen (pidfile, "r")) != NULL){
137 	ptr = fgets(buf, sizeof(buf), f);
138 	fclose (f);
139 	if (ptr != NULL && (pid = atoi (ptr)) > 1) {
140 	    if (kill (pid, 0) == 0 || errno != ESRCH) {
141 		/* Yes there is a process */
142 		*pid0 = pid;
143 		return 0;
144 	    }
145 	}
146     }
147     *pid0 = 0;
148     return 0;
149 }
150 
151 /*! Given a pid, kill that process
152  *
153  * @param[in] pid   Process id
154  * @retval    0     Killed OK
155  * @retval    -1    Could not kill.
156  * Maybe shouldk not belong to pidfile code,..
157  */
158 int
pidfile_zapold(pid_t pid)159 pidfile_zapold(pid_t pid)
160 {
161     clicon_log(LOG_NOTICE, "Killing old daemon with pid: %d", pid);
162     killpg(pid, SIGTERM);
163     kill(pid, SIGTERM);
164     sleep(1); /* check again */
165     if ((kill (pid, 0)) != 0 && errno == ESRCH) /* Nothing there */
166 	;
167     else{ /* problem: couldnt kill it */
168 	clicon_err(OE_DAEMON, errno, "Killing old demon");
169 	return -1;
170     }
171     return 0;
172 }
173 
174 /*! Write a pid-file
175  *
176  * @param[in] pidfile   Name of pidfile
177  */
178 int
pidfile_write(char * pidfile)179 pidfile_write(char *pidfile)
180 {
181     FILE *f = NULL;
182     int   retval = -1;
183 
184     /* Here, there should be no old agent and no pidfile */
185     if ((f = fopen(pidfile, "w")) == NULL){
186 	if (errno == EACCES)
187 	    clicon_err(OE_DAEMON, errno, "Creating pid-file %s (Try run as root?)", pidfile);
188 	else
189 	    clicon_err(OE_DAEMON, errno, "Creating pid-file %s", pidfile);
190 	goto done;
191     }
192     if ((retval = fprintf(f, "%ld\n", (long) getpid())) < 1){
193 	clicon_err(OE_DAEMON, errno, "Could not write pid to %s", pidfile);
194 	goto done;
195     }
196     clicon_debug(1, "Opened pidfile %s with pid %d", pidfile, getpid());
197     retval = 0;
198  done:
199     if (f != NULL)
200 	fclose(f);
201     return retval;
202 }
203