1/* this code is broken - there is a race condition with the unlink (tridge) */ 2 3/* 4 Unix SMB/CIFS implementation. 5 pidfile handling 6 Copyright (C) Andrew Tridgell 1998 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23 24#ifndef O_NONBLOCK 25#define O_NONBLOCK 26#endif 27 28static char *pidFile_name = NULL; 29 30/* return the pid in a pidfile. return 0 if the process (or pidfile) 31 does not exist */ 32pid_t pidfile_pid(const char *name) 33{ 34 int fd; 35 char pidstr[20]; 36 pid_t pid; 37 unsigned int ret; 38 char * pidFile; 39 40 if (asprintf(&pidFile, "%s/%s.pid", lp_piddir(), name) == -1) { 41 return 0; 42 } 43 44 fd = sys_open(pidFile, O_NONBLOCK | O_RDONLY, 0644); 45 if (fd == -1) { 46 SAFE_FREE(pidFile); 47 return 0; 48 } 49 50 ZERO_ARRAY(pidstr); 51 52 if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) { 53 goto noproc; 54 } 55 56 ret = atoi(pidstr); 57 58 if (ret == 0) { 59 /* Obviously we had some garbage in the pidfile... */ 60 DEBUG(1, ("Could not parse contents of pidfile %s\n", 61 pidFile)); 62 goto noproc; 63 } 64 65 pid = (pid_t)ret; 66 if (!process_exists_by_pid(pid)) { 67 goto noproc; 68 } 69 70 if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_RDLCK)) { 71 /* we could get the lock - it can't be a Samba process */ 72 goto noproc; 73 } 74 75 SAFE_FREE(pidFile); 76 close(fd); 77 return (pid_t)ret; 78 79 noproc: 80 close(fd); 81 unlink(pidFile); 82 SAFE_FREE(pidFile); 83 return 0; 84} 85 86/* create a pid file in the pid directory. open it and leave it locked */ 87void pidfile_create(const char *program_name) 88{ 89 int fd; 90 char buf[20]; 91 const char *short_configfile; 92 char *name; 93 pid_t pid; 94 95 /* Add a suffix to the program name if this is a process with a 96 * none default configuration file name. */ 97 if (strcmp( CONFIGFILE, get_dyn_CONFIGFILE()) == 0) { 98 name = SMB_STRDUP(program_name); 99 } else { 100 short_configfile = strrchr( get_dyn_CONFIGFILE(), '/'); 101 if (short_configfile == NULL) { 102 /* conf file in current directory */ 103 short_configfile = get_dyn_CONFIGFILE(); 104 } else { 105 /* full/relative path provided */ 106 short_configfile++; 107 } 108 if (asprintf(&name, "%s-%s", program_name, 109 short_configfile) == -1) { 110 smb_panic("asprintf failed"); 111 } 112 } 113 114 if (asprintf(&pidFile_name, "%s/%s.pid", lp_piddir(), name) == -1) { 115 smb_panic("asprintf failed"); 116 } 117 118 pid = pidfile_pid(name); 119 if (pid != 0) { 120 DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n", 121 name, pidFile_name, (int)pid)); 122 exit(1); 123 } 124 125 fd = sys_open(pidFile_name, O_NONBLOCK | O_CREAT | O_WRONLY | O_EXCL, 126 0644); 127 if (fd == -1) { 128 DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile_name, 129 strerror(errno))); 130 exit(1); 131 } 132 133 if (fcntl_lock(fd,SMB_F_SETLK,0,1,F_WRLCK)==False) { 134 DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n", 135 name, pidFile_name, strerror(errno))); 136 exit(1); 137 } 138 139 memset(buf, 0, sizeof(buf)); 140 slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) sys_getpid()); 141 if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) { 142 DEBUG(0,("ERROR: can't write to file %s: %s\n", 143 pidFile_name, strerror(errno))); 144 exit(1); 145 } 146 /* Leave pid file open & locked for the duration... */ 147 SAFE_FREE(name); 148} 149 150void pidfile_unlink(void) 151{ 152 if (pidFile_name == NULL) { 153 return; 154 } 155 unlink(pidFile_name); 156 SAFE_FREE(pidFile_name); 157} 158