/[baselayout]/trunk/src/librc-daemon.c
Gentoo

Contents of /trunk/src/librc-daemon.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2966 - (show annotations) (download) (as text)
Tue Oct 2 09:04:10 2007 UTC (7 years, 1 month ago) by uberlord
File MIME type: text/x-csrc
File size: 10940 byte(s)
rc_set_service_daemon -> rc_service_daemon_set
1 /*
2 librc-daemon
3 Finds PID for given daemon criteria
4 Copyright 2007 Gentoo Foundation
5 Released under the GPLv2
6 */
7
8 #include "librc.h"
9
10 #if defined(__linux__)
11 static bool pid_is_cmd (pid_t pid, const char *cmd)
12 {
13 char buffer[32];
14 FILE *fp;
15 int c;
16
17 snprintf(buffer, sizeof (buffer), "/proc/%d/stat", pid);
18 if ((fp = fopen (buffer, "r")) == NULL)
19 return (false);
20
21 while ((c = getc (fp)) != EOF && c != '(')
22 ;
23
24 if (c != '(') {
25 fclose(fp);
26 return (false);
27 }
28
29 while ((c = getc (fp)) != EOF && c == *cmd)
30 cmd++;
31
32 fclose (fp);
33
34 return ((c == ')' && *cmd == '\0') ? true : false);
35 }
36
37 static bool pid_is_exec (pid_t pid, const char *exec)
38 {
39 char cmdline[32];
40 char buffer[PATH_MAX];
41 char *p;
42 int fd = -1;
43 int r;
44
45 snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid);
46 memset (buffer, 0, sizeof (buffer));
47 if (readlink (cmdline, buffer, sizeof (buffer)) != -1) {
48 if (strcmp (exec, buffer) == 0)
49 return (true);
50
51 /* We should cater for deleted binaries too */
52 if (strlen (buffer) > 10) {
53 p = buffer + (strlen (buffer) - 10);
54 if (strcmp (p, " (deleted)") == 0) {
55 *p = 0;
56 if (strcmp (buffer, exec) == 0)
57 return (true);
58 }
59 }
60 }
61
62 snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid);
63 if ((fd = open (cmdline, O_RDONLY)) < 0)
64 return (false);
65
66 r = read(fd, buffer, sizeof (buffer));
67 close (fd);
68
69 if (r == -1)
70 return 0;
71
72 buffer[r] = 0;
73 return (strcmp (exec, buffer) == 0 ? true : false);
74 }
75
76 pid_t *rc_find_pids (const char *exec, const char *cmd,
77 uid_t uid, pid_t pid)
78 {
79 DIR *procdir;
80 struct dirent *entry;
81 int npids = 0;
82 pid_t p;
83 pid_t *pids = NULL;
84 pid_t *tmp = NULL;
85 char buffer[PATH_MAX];
86 struct stat sb;
87 pid_t runscript_pid = 0;
88 char *pp;
89
90 if ((procdir = opendir ("/proc")) == NULL)
91 return (NULL);
92
93 /*
94 We never match RC_RUNSCRIPT_PID if present so we avoid the below
95 scenario
96
97 /etc/init.d/ntpd stop does
98 start-stop-daemon --stop --name ntpd
99 catching /etc/init.d/ntpd stop
100
101 nasty
102 */
103
104 if ((pp = getenv ("RC_RUNSCRIPT_PID"))) {
105 if (sscanf (pp, "%d", &runscript_pid) != 1)
106 runscript_pid = 0;
107 }
108
109 while ((entry = readdir (procdir)) != NULL) {
110 if (sscanf (entry->d_name, "%d", &p) != 1)
111 continue;
112
113 if (runscript_pid != 0 && runscript_pid == p)
114 continue;
115
116 if (pid != 0 && pid != p)
117 continue;
118
119 if (uid) {
120 snprintf (buffer, sizeof (buffer), "/proc/%d", p);
121 if (stat (buffer, &sb) != 0 || sb.st_uid != uid)
122 continue;
123 }
124
125 if (cmd && ! pid_is_cmd (p, cmd))
126 continue;
127
128 if (exec && ! cmd && ! pid_is_exec (p, exec))
129 continue;
130
131 tmp = realloc (pids, sizeof (pid_t) * (npids + 2));
132 if (! tmp) {
133 free (pids);
134 closedir (procdir);
135 errno = ENOMEM;
136 return (NULL);
137 }
138 pids = tmp;
139
140 pids[npids] = p;
141 pids[npids + 1] = 0;
142 npids++;
143 }
144 closedir (procdir);
145
146 return (pids);
147 }
148 librc_hidden_def(rc_find_pids)
149
150 #elif defined(__DragonFly__) || defined(__FreeBSD__) || \
151 defined(__NetBSD__) || defined(__OpenBSD__)
152
153 # if defined(__DragonFly__) || defined(__FreeBSD__)
154 # ifndef KERN_PROC_PROC
155 # define KERN_PROC_PROC KERN_PROC_ALL
156 # endif
157 # define _KINFO_PROC kinfo_proc
158 # define _KVM_GETARGV kvm_getargv
159 # define _GET_KINFO_UID(kp) (kp.ki_ruid)
160 # define _GET_KINFO_COMM(kp) (kp.ki_comm)
161 # define _GET_KINFO_PID(kp) (kp.ki_pid)
162 # else
163 # define _KINFO_PROC kinfo_proc2
164 # define _KVM_GETARGV kvm_getargv2
165 # define _GET_KINFO_UID(kp) (kp.p_ruid)
166 # define _GET_KINFO_COMM(kp) (kp.p_comm)
167 # define _GET_KINFO_PID(kp) (kp.p_pid)
168 # endif
169
170 pid_t *rc_find_pids (const char *exec, const char *cmd,
171 uid_t uid, pid_t pid)
172 {
173 static kvm_t *kd = NULL;
174 char errbuf[_POSIX2_LINE_MAX];
175 struct _KINFO_PROC *kp;
176 int i;
177 int processes = 0;
178 int argc = 0;
179 char **argv;
180 pid_t *pids = NULL;
181 pid_t *tmp;
182 int npids = 0;
183
184 if ((kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) {
185 fprintf (stderr, "kvm_open: %s", errbuf);
186 return (NULL);
187 }
188
189 #if defined(__DragonFly__) || defined( __FreeBSD__)
190 kp = kvm_getprocs (kd, KERN_PROC_PROC, 0, &processes);
191 #else
192 kp = kvm_getproc2 (kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
193 &processes);
194 #endif
195 for (i = 0; i < processes; i++) {
196 pid_t p = _GET_KINFO_PID (kp[i]);
197 if (pid != 0 && pid != p)
198 continue;
199
200 if (uid != 0 && uid != _GET_KINFO_UID (kp[i]))
201 continue;
202
203 if (cmd) {
204 if (! _GET_KINFO_COMM (kp[i]) ||
205 strcmp (cmd, _GET_KINFO_COMM (kp[i])) != 0)
206 continue;
207 }
208
209 if (exec && ! cmd) {
210 if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv)
211 continue;
212
213 if (strcmp (*argv, exec) != 0)
214 continue;
215 }
216
217 tmp = realloc (pids, sizeof (pid_t) * (npids + 2));
218 if (! tmp) {
219 free (pids);
220 kvm_close (kd);
221 errno = ENOMEM;
222 return (NULL);
223 }
224 pids = tmp;
225
226 pids[npids] = p;
227 pids[npids + 1] = 0;
228 npids++;
229 }
230 kvm_close (kd);
231
232 return (pids);
233 }
234 librc_hidden_def(rc_find_pids)
235
236 #else
237 # error "Platform not supported!"
238 #endif
239
240 static bool _match_daemon (const char *path, const char *file,
241 const char *mexec, const char *mname,
242 const char *mpidfile)
243 {
244 char buffer[RC_LINEBUFFER];
245 char *ffile = rc_strcatpaths (path, file, (char *) NULL);
246 FILE *fp;
247 int lc = 0;
248 int m = 0;
249
250 if ((fp = fopen (ffile, "r")) == NULL) {
251 free (ffile);
252 return (false);
253 }
254
255 if (! mname)
256 m += 10;
257 if (! mpidfile)
258 m += 100;
259
260 memset (buffer, 0, sizeof (buffer));
261 while ((fgets (buffer, RC_LINEBUFFER, fp))) {
262 int lb = strlen (buffer) - 1;
263 if (buffer[lb] == '\n')
264 buffer[lb] = 0;
265
266 if (strcmp (buffer, mexec) == 0)
267 m += 1;
268 else if (mname && strcmp (buffer, mname) == 0)
269 m += 10;
270 else if (mpidfile && strcmp (buffer, mpidfile) == 0)
271 m += 100;
272
273 if (m == 111)
274 break;
275
276 lc++;
277 if (lc > 5)
278 break;
279 }
280 fclose (fp);
281 free (ffile);
282
283 return (m == 111 ? true : false);
284 }
285
286 void rc_service_daemon_set (const char *service, const char *exec,
287 const char *name, const char *pidfile,
288 bool started)
289 {
290 char *svc = rc_xstrdup (service);
291 char *dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (svc),
292 (char *) NULL);
293 char **files = NULL;
294 char *file;
295 char *ffile = NULL;
296 int i;
297 char *mexec;
298 char *mname;
299 char *mpidfile;
300 int nfiles = 0;
301
302 free (svc);
303 if (! exec && ! name && ! pidfile)
304 return;
305
306 if (exec) {
307 i = strlen (exec) + 6;
308 mexec = rc_xmalloc (sizeof (char *) * i);
309 snprintf (mexec, i, "exec=%s", exec);
310 } else
311 mexec = rc_xstrdup ("exec=");
312
313 if (name) {
314 i = strlen (name) + 6;
315 mname = rc_xmalloc (sizeof (char *) * i);
316 snprintf (mname, i, "name=%s", name);
317 } else
318 mname = rc_xstrdup ("name=");
319
320 if (pidfile) {
321 i = strlen (pidfile) + 9;
322 mpidfile = rc_xmalloc (sizeof (char *) * i);
323 snprintf (mpidfile, i, "pidfile=%s", pidfile);
324 } else
325 mpidfile = rc_xstrdup ("pidfile=");
326
327 /* Regardless, erase any existing daemon info */
328 if (rc_is_dir (dirpath)) {
329 char *oldfile = NULL;
330 files = rc_ls_dir (dirpath, 0);
331 STRLIST_FOREACH (files, file, i) {
332 ffile = rc_strcatpaths (dirpath, file, (char *) NULL);
333 nfiles++;
334
335 if (! oldfile) {
336 if (_match_daemon (dirpath, file, mexec, mname, mpidfile)) {
337 unlink (ffile);
338 oldfile = ffile;
339 nfiles--;
340 }
341 } else {
342 rename (ffile, oldfile);
343 free (oldfile);
344 oldfile = ffile;
345 }
346 }
347 free (ffile);
348 rc_strlist_free (files);
349 }
350
351 /* Now store our daemon info */
352 if (started) {
353 char buffer[10];
354 FILE *fp;
355
356 if (mkdir (dirpath, 0755) == 0 || errno == EEXIST) {
357 snprintf (buffer, sizeof (buffer), "%03d", nfiles + 1);
358 file = rc_strcatpaths (dirpath, buffer, (char *) NULL);
359 if ((fp = fopen (file, "w")))
360 fprintf (fp, "%s\n%s\n%s\n", mexec, mname, mpidfile);
361 fclose (fp);
362 free (file);
363 }
364 }
365
366 free (mexec);
367 free (mname);
368 free (mpidfile);
369 free (dirpath);
370 }
371 librc_hidden_def(rc_service_daemon_set)
372
373 bool rc_service_started_daemon (const char *service, const char *exec,
374 int indx)
375 {
376 char *dirpath;
377 char *file;
378 int i;
379 char *mexec;
380 bool retval = false;
381 char *svc;
382
383 if (! service || ! exec)
384 return (false);
385
386 svc = rc_xstrdup (service);
387 dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (svc),
388 (char *) NULL);
389 free (svc);
390
391 if (! rc_is_dir (dirpath)) {
392 free (dirpath);
393 return (false);
394 }
395
396 i = strlen (exec) + 6;
397 mexec = rc_xmalloc (sizeof (char *) * i);
398 snprintf (mexec, i, "exec=%s", exec);
399
400 if (indx > 0) {
401 int len = sizeof (char *) * 10;
402 file = rc_xmalloc (len);
403 snprintf (file, len, "%03d", indx);
404 retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
405 free (file);
406 } else {
407 char **files = rc_ls_dir (dirpath, 0);
408 STRLIST_FOREACH (files, file, i) {
409 retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
410 if (retval)
411 break;
412 }
413 rc_strlist_free (files);
414 }
415
416 free (mexec);
417 return (retval);
418 }
419 librc_hidden_def(rc_service_started_daemon)
420
421 bool rc_service_daemons_crashed (const char *service)
422 {
423 char *dirpath;
424 char **files;
425 char *file;
426 char *path;
427 int i;
428 FILE *fp;
429 char buffer[RC_LINEBUFFER];
430 char *exec = NULL;
431 char *name = NULL;
432 char *pidfile = NULL;
433 pid_t pid = 0;
434 pid_t *pids = NULL;
435 char *p;
436 char *token;
437 bool retval = false;
438 char *svc;
439
440 if (! service)
441 return (false);
442
443 svc = rc_xstrdup (service);
444 dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (svc),
445 (char *) NULL);
446 free (svc);
447
448 if (! rc_is_dir (dirpath)) {
449 free (dirpath);
450 return (false);
451 }
452
453 memset (buffer, 0, sizeof (buffer));
454 files = rc_ls_dir (dirpath, 0);
455 STRLIST_FOREACH (files, file, i) {
456 path = rc_strcatpaths (dirpath, file, (char *) NULL);
457 fp = fopen (path, "r");
458 free (path);
459 if (! fp)
460 break;
461
462 while ((fgets (buffer, RC_LINEBUFFER, fp))) {
463 int lb = strlen (buffer) - 1;
464 if (buffer[lb] == '\n')
465 buffer[lb] = 0;
466
467 p = buffer;
468 if ((token = strsep (&p, "=")) == NULL || ! p)
469 continue;
470
471 if (strlen (p) == 0)
472 continue;
473
474 if (strcmp (token, "exec") == 0) {
475 if (exec)
476 free (exec);
477 exec = rc_xstrdup (p);
478 } else if (strcmp (token, "name") == 0) {
479 if (name)
480 free (name);
481 name = rc_xstrdup (p);
482 } else if (strcmp (token, "pidfile") == 0) {
483 if (pidfile)
484 free (pidfile);
485 pidfile = rc_xstrdup (p);
486 }
487 }
488 fclose (fp);
489
490 pid = 0;
491 if (pidfile) {
492 if (! rc_exists (pidfile)) {
493 retval = true;
494 break;
495 }
496
497 if ((fp = fopen (pidfile, "r")) == NULL) {
498 retval = true;
499 break;
500 }
501
502 if (fscanf (fp, "%d", &pid) != 1) {
503 fclose (fp);
504 retval = true;
505 break;
506 }
507
508 fclose (fp);
509 free (pidfile);
510 pidfile = NULL;
511
512 /* We have the pid, so no need to match on name */
513 free (exec);
514 exec = NULL;
515 free (name);
516 name = NULL;
517 }
518
519 if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL) {
520 retval = true;
521 break;
522 }
523 free (pids);
524
525 free (exec);
526 exec = NULL;
527 free (name);
528 name = NULL;
529 }
530
531 free (exec);
532 free (name);
533 free (dirpath);
534 rc_strlist_free (files);
535
536 return (retval);
537 }
538 librc_hidden_def(rc_service_daemons_crashed)

  ViewVC Help
Powered by ViewVC 1.1.20