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