| 115 | | /** |
| 116 | | * Tests for a lock file and returns the pid of any process already running |
| 117 | | */ |
| 118 | | pid_t |
| 119 | | test_lock(gchar *file_name) |
| | 123 | static gint rm_stale_lockdir(const gchar* tmp, const gchar *file_name, pid_t stalepid, gboolean acquired) { |
| | 124 | // shall we delete their lock? |
| | 125 | // if they dont exist, rm /tmp/mediaplayer/theirpid |
| | 126 | // renameo on top of empty dirs rm's the old dir. |
| | 127 | char *theircmdline; |
| | 128 | FILE * fp; |
| | 129 | char * line = NULL; |
| | 130 | size_t len = 0; |
| | 131 | gboolean dellock; |
| | 132 | /** XXX must be better way than parsing proc...*/ |
| | 133 | if(-1 == asprintf(&theircmdline, "%s/%d/cmdline", "/proc", stalepid)) return -1; |
| | 134 | |
| | 135 | fp = fopen(theircmdline, "r"); |
| | 136 | |
| | 137 | if (fp == NULL) { |
| | 138 | if(errno == ENOENT) { |
| | 139 | g_printf(_("Couldn't find process in dir %s\n"), theircmdline); |
| | 140 | // other process has exited. |
| | 141 | dellock = TRUE; |
| | 142 | } else { |
| | 143 | perror("Error checking to see if old process still exists"); |
| | 144 | return -1; |
| | 145 | } |
| | 146 | } else { |
| | 147 | int found = 0; |
| | 148 | if(-1 == getdelim(&line, &len, 0, fp)) { |
| | 149 | if(feof(fp)) { |
| | 150 | g_printerr(_("Unexpected eof reading from /%s/%d/cmdline. Assuming other mediaplayer died\n"),"/proc",stalepid); |
| | 151 | } else { |
| | 152 | perror("Error reading from /proc/?/cmdline"); |
| | 153 | return -1; |
| | 154 | } |
| | 155 | } else { |
| | 156 | // XXX gross / slow; looking at cmdline is a hack. |
| | 157 | for(int i = 0; i < strlen(line); i++) { |
| | 158 | if(!strncmp(line+i, "openmoko-mediaplayer", strlen("openmoko-mediaplayer"))) { |
| | 159 | found = 1; |
| | 160 | break; |
| | 161 | } |
| | 162 | } |
| | 163 | } |
| | 164 | if(found) { |
| | 165 | // Their name contains "openmoko-mediaplayer"; the lock is valid. |
| | 166 | g_printf(_("found another openmoko-mediaplayer process\n")); |
| | 167 | dellock = FALSE; |
| | 168 | } else { |
| | 169 | // Some interloper has the pid of a dead mediaplayer. |
| | 170 | g_printf(_("%s doesn't contain with %s\n"),line,"openmoko-mediaplayer"); |
| | 171 | dellock = TRUE; |
| | 172 | } |
| | 173 | assert(fp); |
| | 174 | if(-1 == fclose(fp)) { perror("couldn't close file in proc"); return -1; } |
| | 175 | } |
| | 176 | |
| | 177 | if(dellock) { |
| | 178 | char * theirlockfile; |
| | 179 | if(acquired) { |
| | 180 | if(-1 == asprintf(&theirlockfile, "%s/%s/%d",tmp,file_name,stalepid)) return -1; |
| | 181 | } else { |
| | 182 | if(-1 == asprintf(&theirlockfile, "%s/%s.%d/%d",tmp,file_name,stalepid,stalepid)) return -1; |
| | 183 | } |
| | 184 | if(-1 == unlink(theirlockfile)) { |
| | 185 | g_printf(_("removing stale lockfile %s\n"),theirlockfile); |
| | 186 | if(errno != ENOENT) { |
| | 187 | perror("Couldn't remove stale lockfile"); |
| | 188 | return -1; |
| | 189 | } |
| | 190 | } |
| | 191 | free(theirlockfile); |
| | 192 | char * theirlockdir; |
| | 193 | if(acquired) { |
| | 194 | if(-1 == asprintf(&theirlockdir, "%s/%s",tmp,file_name)) return -1; |
| | 195 | } else { |
| | 196 | if(-1 == asprintf(&theirlockdir, "%s/%s.%d",tmp,file_name,stalepid)) return -1; |
| | 197 | } |
| | 198 | if(-1 == rmdir(theirlockfile)) { |
| | 199 | g_printf(_("removing stale lockdir %s\n"),theirlockdir); |
| | 200 | if(errno != ENOENT) { |
| | 201 | perror("Couldn't remove stale lockdir"); |
| | 202 | return -1; |
| | 203 | } |
| | 204 | } |
| | 205 | free(theirlockdir); |
| | 206 | } |
| | 207 | |
| | 208 | free(theircmdline); |
| | 209 | return dellock; |
| | 210 | } |
| | 211 | |
| | 212 | static int test_and_set_lockdir(gchar *file_name, pid_t * theirpid) |
| 174 | | if (fcntl(fd, F_SETLK, &fl) < 0) |
| 175 | | { |
| 176 | | g_printerr("Failed writing lock file\n"); |
| 177 | | close(fd); |
| 178 | | } |
| | 273 | while((d = readdir(olddir))) { |
| | 274 | if(!((!strcmp(d->d_name,".")) || (!strcmp(d->d_name,"..")))) { |
| | 275 | // parse int |
| | 276 | char * end; |
| | 277 | errno = 0; |
| | 278 | *theirpid = strtoul(d->d_name, &end, 10); |
| | 279 | if(errno || strlen(d->d_name) != end - d->d_name) { |
| | 280 | if(errno) { |
| | 281 | perror("Found junk in lockdir"); |
| | 282 | } else { |
| | 283 | g_printerr(_("Found junk in lockdir %d != %d"), strlen(d->d_name), end - d->d_name); |
| | 284 | } |
| | 285 | return -1; |
| | 286 | } else { |
| | 287 | break; |
| | 288 | } |
| | 289 | } |
| | 290 | errno = 0; |
| | 291 | } |
| | 292 | if(errno) { |
| | 293 | perror("Couldn't read from existing lock dir"); |
| | 294 | } |
| | 295 | if(-1 == closedir(olddir)) { |
| | 296 | perror("Couldn't close existing lock dir"); |
| | 297 | return -1; |
| | 298 | } |
| | 299 | |
| | 300 | int rm_ret = rm_stale_lockdir(tmp,file_name, *theirpid, TRUE); |
| | 301 | if(rm_ret == -1) { |
| | 302 | return -1; |
| | 303 | } else if (rm_ret == 1) { |
| | 304 | // deleted stale lock |
| | 305 | *theirpid = 0; |
| | 306 | } else { |
| | 307 | // found valid lock |
| | 308 | assert(*theirpid); |
| | 309 | break; |
| | 310 | } |
| | 311 | // Deleting their lock doesn't imply that we get to obtain the |
| | 312 | // lock; go back up to the top, and retry the rename. |
| | 313 | g_printf(_("rename %s -> %s : "),mydirname, dirname); |
| | 314 | } |
| | 315 | if(*theirpid) { |
| | 316 | // unlink our directory |
| | 317 | if(-1 == unlink(mylockfilename)) { perror("deleting lockfile"); } |
| | 318 | if(-1 == rmdir(mydirname)) {perror("deleting lockdir"); } |
| | 319 | // don't bother with error checking; there's nothing to to about |
| | 320 | // it if we fail. |
| | 321 | } else { |
| | 322 | g_printf(_("obtained lock\n")); |
| | 323 | // delete stale locks |
| | 324 | DIR * tmpdir = opendir("/tmp"); |
| | 325 | struct dirent * d; |
| | 326 | if(!tmpdir) { |
| | 327 | perror("Couldn't open /tmp to scan for stale lockfiles"); |
| | 328 | return -1; |
| | 329 | } |
| | 330 | size_t len = strlen(file_name); |
| | 331 | errno = 0; |
| | 332 | |
| | 333 | while((d = readdir(tmpdir))) { |
| | 334 | if(!strncmp(file_name,d->d_name,len) && strlen(d->d_name) > len) { |
| | 335 | g_printf(_("potentially stale lock %s\n"), d->d_name); |
| | 336 | // looks like a incomplete lockfile. |
| | 337 | *theirpid = strtoul(d->d_name+len+1,0,10); |
| | 338 | if(-1 == rm_stale_lockdir(tmp,file_name,*theirpid,FALSE)) { |
| | 339 | return -1; |
| | 340 | } |
| | 341 | } |
| | 342 | } |
| | 343 | if(-1 == closedir(tmpdir)) { |
| | 344 | perror("Failed to close /tmp after scanning for stale lockfiles"); |
| | 345 | return -1; |
| | 346 | } |
| | 347 | *theirpid = 0; |
| | 348 | } |
| | 349 | |
| | 350 | free(dirname); |
| | 351 | free(mydirname); |
| | 352 | free(mylockfilename); |
| | 353 | |
| | 354 | return *theirpid ? 1 : 0; // 0 iff we have the lock. |
| 192 | | pid = test_lock(lock_file); |
| 193 | | if (pid > 0) |
| 194 | | { |
| 195 | | g_printf(_("Already running an instance of the Media Player, bringing that to the front instead.\n")); |
| 196 | | |
| 197 | | // Was signaling the other process successful? |
| 198 | | if (kill(pid, SIGUSR1) == 0) |
| 199 | | { |
| 200 | | return TRUE; |
| 201 | | } else { |
| 202 | | g_printf(_("Previous instance invalid, proceeding with regular startup.\n")); |
| 203 | | } |
| | 368 | int alreadylocked = test_and_set_lockdir(lock_file, &pid); |
| | 369 | if(alreadylocked == -1) { |
| | 370 | //error |
| | 371 | return TRUE; |
| | 372 | } else if(alreadylocked == 1) { |
| | 373 | g_printf(_("Already running an instance of the Media Player, bringing that to the front instead.\n")); |
| | 374 | // Don't care if signaling the other process was successful, so don't check return value. |
| | 375 | kill(pid, SIGUSR1); |
| | 376 | return TRUE; |