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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2569 - (show annotations) (download) (as text)
Tue Apr 10 11:24:58 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 13479 byte(s)
Fix indentation
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 int len = sizeof (char *) * 10;
452 file = rc_xmalloc (len);
453 snprintf (file, len, "%03d", indx);
454 retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
455 free (file);
456 }
457 else
458 {
459 char **files = rc_ls_dir (NULL, dirpath, 0);
460 STRLIST_FOREACH (files, file, i)
461 {
462 retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
463 if (retval)
464 break;
465 }
466 free (files);
467 }
468
469 free (mexec);
470 return (retval);
471 }
472
473 bool rc_service_daemons_crashed (const char *service)
474 {
475 char *dirpath;
476 char **files;
477 char *file;
478 char *path;
479 int i;
480 FILE *fp;
481 char buffer[RC_LINEBUFFER];
482 char *exec = NULL;
483 char *name = NULL;
484 char *pidfile = NULL;
485 pid_t pid = 0;
486 pid_t *pids = NULL;
487 char *p;
488 char *token;
489 bool retval = false;
490
491 if (! service)
492 return (false);
493
494 dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service),
495 (char *) NULL);
496 if (! rc_is_dir (dirpath))
497 {
498 free (dirpath);
499 return (false);
500 }
501
502 memset (buffer, 0, sizeof (buffer));
503 files = rc_ls_dir (NULL, dirpath, 0);
504 STRLIST_FOREACH (files, file, i)
505 {
506 path = rc_strcatpaths (dirpath, file, (char *) NULL);
507 fp = fopen (path, "r");
508 free (path);
509 if (! fp)
510 {
511 eerror ("fopen `%s': %s", file, strerror (errno));
512 continue;
513 }
514
515 while ((fgets (buffer, RC_LINEBUFFER, fp)))
516 {
517 int lb = strlen (buffer) - 1;
518 if (buffer[lb] == '\n')
519 buffer[lb] = 0;
520
521 p = buffer;
522 if ((token = strsep (&p, "=")) == NULL || ! p)
523 continue;
524
525 if (strlen (p) == 0)
526 continue;
527
528 if (strcmp (token, "exec") == 0)
529 {
530 if (exec)
531 free (exec);
532 exec = strdup (p);
533 }
534 else if (strcmp (token, "name") == 0)
535 {
536 if (name)
537 free (name);
538 name = strdup (p);
539 }
540 else if (strcmp (token, "pidfile") == 0)
541 {
542 if (pidfile)
543 free (pidfile);
544 pidfile = strdup (p);
545 }
546 }
547 fclose (fp);
548
549 pid = 0;
550 if (pidfile)
551 {
552 if (! rc_exists (pidfile))
553 {
554 retval = true;
555 break;
556 }
557
558 if ((fp = fopen (pidfile, "r")) == NULL)
559 {
560 eerror ("fopen `%s': %s", pidfile, strerror (errno));
561 retval = true;
562 break;
563 }
564
565 if (fscanf (fp, "%d", &pid) != 1)
566 {
567 eerror ("no pid found in `%s'", pidfile);
568 fclose (fp);
569 retval = true;
570 break;
571 }
572
573 fclose (fp);
574 free (pidfile);
575 pidfile = NULL;
576 }
577
578 if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL)
579 {
580 retval = true;
581 break;
582 }
583 free (pids);
584
585 if (exec)
586 {
587 free (exec);
588 exec = NULL;
589 }
590 if (name)
591 {
592 free (name);
593 name = NULL;
594 }
595 }
596
597 if (exec)
598 {
599 free (exec);
600 exec = NULL;
601 }
602 if (name)
603 {
604 free (name);
605 name = NULL;
606 }
607
608 free (dirpath);
609 rc_strlist_free (files);
610
611 return (retval);
612 }

  ViewVC Help
Powered by ViewVC 1.1.20