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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20