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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20