daemon.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <?php
  2. /**
  3. * StatusNet - the distributed open-source microblogging tool
  4. * Copyright (C) 2008, 2009, StatusNet, Inc.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. if (!defined('STATUSNET') && !defined('LACONICA')) {
  20. exit(1);
  21. }
  22. class Daemon
  23. {
  24. var $daemonize = true;
  25. var $_id = 'generic';
  26. function __construct($daemonize = true)
  27. {
  28. $this->daemonize = $daemonize;
  29. }
  30. function name()
  31. {
  32. return null;
  33. }
  34. function get_id()
  35. {
  36. return $this->_id;
  37. }
  38. function set_id($id)
  39. {
  40. $this->_id = $id;
  41. }
  42. function background()
  43. {
  44. /*
  45. * This prefers to Starting PHP 5.4 (dotdeb), maybe earlier for some version/distrib
  46. * seems MySQL connection using mysqli driver get lost when fork.
  47. * Need to unset it so that child process recreate it.
  48. *
  49. * @todo FIXME cleaner way to do it ?
  50. */
  51. global $_DB_DATAOBJECT;
  52. unset($_DB_DATAOBJECT['CONNECTIONS']);
  53. $pid = pcntl_fork();
  54. if ($pid < 0) { // error
  55. common_log(LOG_ERR, "Could not fork.");
  56. return false;
  57. } else if ($pid > 0) { // parent
  58. common_log(LOG_INFO, "Successfully forked.");
  59. exit(0);
  60. } else { // child
  61. return true;
  62. }
  63. }
  64. function alreadyRunning()
  65. {
  66. $pidfilename = $this->pidFilename();
  67. if (!$pidfilename) {
  68. return false;
  69. }
  70. if (!file_exists($pidfilename)) {
  71. return false;
  72. }
  73. $contents = file_get_contents($pidfilename);
  74. if (posix_kill(trim($contents), 0)) {
  75. return true;
  76. } else {
  77. return false;
  78. }
  79. }
  80. function writePidFile()
  81. {
  82. $pidfilename = $this->pidFilename();
  83. if (!$pidfilename) {
  84. return false;
  85. }
  86. return file_put_contents($pidfilename, posix_getpid() . "\n");
  87. }
  88. function clearPidFile()
  89. {
  90. $pidfilename = $this->pidFilename();
  91. if (!$pidfilename) {
  92. return false;
  93. }
  94. return unlink($pidfilename);
  95. }
  96. function pidFilename()
  97. {
  98. $piddir = common_config('daemon', 'piddir');
  99. if (!$piddir) {
  100. return null;
  101. }
  102. $name = $this->name();
  103. if (!$name) {
  104. return null;
  105. }
  106. return $piddir . '/' . $name . '.pid';
  107. }
  108. function changeUser()
  109. {
  110. $groupname = common_config('daemon', 'group');
  111. if ($groupname) {
  112. $group_info = posix_getgrnam($groupname);
  113. if (!$group_info) {
  114. common_log(LOG_WARNING,
  115. 'Ignoring unknown group for daemon: ' . $groupname);
  116. } else {
  117. common_log(LOG_INFO, "Setting group to " . $groupname);
  118. posix_setgid($group_info['gid']);
  119. }
  120. }
  121. $username = common_config('daemon', 'user');
  122. if ($username) {
  123. $user_info = posix_getpwnam($username);
  124. if (!$user_info) {
  125. common_log(LOG_WARNING,
  126. 'Ignoring unknown user for daemon: ' . $username);
  127. } else {
  128. common_log(LOG_INFO, "Setting user to " . $username);
  129. posix_setuid($user_info['uid']);
  130. }
  131. }
  132. }
  133. function runOnce()
  134. {
  135. if ($this->alreadyRunning()) {
  136. common_log(LOG_INFO, $this->name() . ' already running. Exiting.');
  137. exit(0);
  138. }
  139. if ($this->daemonize) {
  140. common_log(LOG_INFO, 'Backgrounding daemon "'.$this->name().'"');
  141. $this->background();
  142. }
  143. $this->writePidFile();
  144. $this->changeUser();
  145. $this->run();
  146. $this->clearPidFile();
  147. }
  148. function run()
  149. {
  150. return true;
  151. }
  152. }