char *my_open(t_shell *shell, t_array *array, char **env, int *indicateur) { int i; char *path; i = -1; if (all_check(shell, array, env) == 0) { if (shell->buffer[0][0] == '.') my_exec(shell, array, env); else { while (shell->tab_path[++i] != NULL) { path = my_strcat(shell->tab_path[i], "/"); if ((access( my_strcat(shell->tab_path[i], shell->buffer[0]), F_OK) == 0)) { *indicateur = *indicateur + 1; return (path); } } my_error_2(shell->buffer[0]); } } }
/* Locking core for Windows. This version does not need a temporary file but uses the plain lock file along with record locking. We create this file here so that we later only need to do the file locking. For error reporting it is useful to keep the name of the file in the handle. */ static dotlock_t dotlock_create_w32 (dotlock_t h, const char *file_to_lock) { LOCK_all_lockfiles (); h->next = all_lockfiles; all_lockfiles = h; h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 ); if (!h->lockname) { all_lockfiles = h->next; UNLOCK_all_lockfiles (); jnlib_free (h); return NULL; } strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock"); /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE along with FILE_SHARE_DELETE but that does not work due to a race condition: Despite the OPEN_ALWAYS flag CreateFile may return an error and we can't reliable create/open the lock file unless we would wait here until it works - however there are other valid reasons why a lock file can't be created and thus the process would not stop as expected but spin until Windows crashes. Our solution is to keep the lock file open; that does not harm. */ { #ifdef HAVE_W32CE_SYSTEM wchar_t *wname = utf8_to_wchar (h->lockname); if (wname) h->lockhd = CreateFile (wname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); else h->lockhd = INVALID_HANDLE_VALUE; jnlib_free (wname); #else h->lockhd = CreateFile (h->lockname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); #endif } if (h->lockhd == INVALID_HANDLE_VALUE) { all_lockfiles = h->next; UNLOCK_all_lockfiles (); my_error_2 (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1)); jnlib_free (h->lockname); jnlib_free (h); return NULL; } return h; }
/* Windows specific code of make_dotlock. Returns 0 on success and -1 on error. */ static int dotlock_take_w32 (dotlock_t h, long timeout) { int wtime = 0; int w32err; OVERLAPPED ovl; again: /* Lock one byte at offset 0. The offset is given by OVL. */ memset (&ovl, 0, sizeof ovl); if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl)) { h->locked = 1; return 0; /* okay */ } w32err = GetLastError (); if (w32err != ERROR_LOCK_VIOLATION) { my_error_2 (_("lock `%s' not made: %s\n"), h->lockname, w32_strerror (w32err)); return -1; } if (timeout) { /* Wait until lock has been released. We use retry intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s. */ if (!wtime) wtime = 50; else if (wtime < 800) wtime *= 2; else if (wtime == 800) wtime = 2000; else if (wtime < 8000) wtime *= 2; if (timeout > 0) { if (wtime > timeout) wtime = timeout; timeout -= wtime; } if (wtime >= 800) my_info_1 (_("waiting for lock %s...\n"), h->lockname); Sleep (wtime); goto again; } return -1; }
/* Windows specific code of release_dotlock. */ static int dotlock_release_w32 (dotlock_t h) { OVERLAPPED ovl; memset (&ovl, 0, sizeof ovl); if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl)) { my_error_2 ("release_dotlock: error removing lockfile `%s': %s\n", h->lockname, w32_strerror (-1)); return -1; } return 0; }
/* Unix specific code of make_dotlock. Returns 0 on success and -1 on error. */ static int dotlock_take_unix (dotlock_t h, long timeout) { int wtime = 0; int sumtime = 0; int pid; int lastpid = -1; int ownerchanged; const char *maybe_dead=""; int same_node; again: if (h->use_o_excl) { /* No hardlink support - use open(O_EXCL). */ int fd; do { jnlib_set_errno (0); fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR ); } while (fd == -1 && errno == EINTR); if (fd == -1 && errno == EEXIST) ; /* Lock held by another process. */ else if (fd == -1) { my_error_2 ("lock not made: open(O_EXCL) of `%s' failed: %s\n", h->lockname, strerror (errno)); return -1; } else { char pidstr[16]; snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid()); if (write (fd, pidstr, 11 ) == 11 && write (fd, h->tname + h->nodename_off,h->nodename_len) == h->nodename_len && write (fd, "\n", 1) == 1 && !close (fd)) { h->locked = 1; return 0; } /* Write error. */ my_error_2 ("lock not made: writing to `%s' failed: %s\n", h->lockname, strerror (errno)); close (fd); unlink (h->lockname); return -1; } } else /* Standard method: Use hardlinks. */ { struct stat sb; link (h->tname, h->lockname); if (stat (h->tname, &sb)) { my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n", strerror (errno)); /* In theory this might be a severe error: It is possible that link succeeded but stat failed due to changed permissions. We can't do anything about it, though. */ return -1; } if (sb.st_nlink == 2) { h->locked = 1; return 0; /* Okay. */ } } /* Check for stale lock files. */ if ( (pid = read_lockfile (h, &same_node)) == -1 ) { if ( errno != ENOENT ) { my_info_0 ("cannot read lockfile\n"); return -1; } my_info_0 ("lockfile disappeared\n"); goto again; } else if ( pid == getpid() && same_node ) { my_info_0 ("Oops: lock already held by us\n"); h->locked = 1; return 0; /* okay */ } else if ( same_node && kill (pid, 0) && errno == ESRCH ) { /* Note: It is unlikley that we get a race here unless a pid is reused too fast or a new process with the same pid as the one of the stale file tries to lock right at the same time as we. */ my_info_1 (_("removing stale lockfile (created by %d)\n"), pid); unlink (h->lockname); goto again; } if (lastpid == -1) lastpid = pid; ownerchanged = (pid != lastpid); if (timeout) { struct timeval tv; /* Wait until lock has been released. We use increasing retry intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s but reset it if the lock owner meanwhile changed. */ if (!wtime || ownerchanged) wtime = 50; else if (wtime < 800) wtime *= 2; else if (wtime == 800) wtime = 2000; else if (wtime < 8000) wtime *= 2; if (timeout > 0) { if (wtime > timeout) wtime = timeout; timeout -= wtime; } sumtime += wtime; if (sumtime >= 1500) { sumtime = 0; my_info_3 (_("waiting for lock (held by %d%s) %s...\n"), pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):""); } tv.tv_sec = wtime / 1000; tv.tv_usec = (wtime % 1000) * 1000; select (0, NULL, NULL, NULL, &tv); goto again; } jnlib_set_errno (EACCES); return -1; }
/* Locking core for Unix. It used a temporary file and the link system call to make locking an atomic operation. */ static dotlock_t dotlock_create_unix (dotlock_t h, const char *file_to_lock) { int fd = -1; char pidstr[16]; const char *nodename; const char *dirpart; int dirpartlen; struct utsname utsbuf; size_t tnamelen; snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() ); /* Create a temporary file. */ if ( uname ( &utsbuf ) ) nodename = "unknown"; else nodename = utsbuf.nodename; if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) ) { dirpart = EXTSEP_S; dirpartlen = 1; } else { dirpartlen = dirpart - file_to_lock; dirpart = file_to_lock; } LOCK_all_lockfiles (); h->next = all_lockfiles; all_lockfiles = h; tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1; h->tname = jnlib_malloc (tnamelen + 1); if (!h->tname) { all_lockfiles = h->next; UNLOCK_all_lockfiles (); jnlib_free (h); return NULL; } h->nodename_len = strlen (nodename); snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h ); h->nodename_off = strlen (h->tname); snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off, "%s.%d", nodename, (int)getpid ()); do { jnlib_set_errno (0); fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR ); } while (fd == -1 && errno == EINTR); if ( fd == -1 ) { all_lockfiles = h->next; UNLOCK_all_lockfiles (); my_error_2 (_("failed to create temporary file `%s': %s\n"), h->tname, strerror(errno)); jnlib_free (h->tname); jnlib_free (h); return NULL; } if ( write (fd, pidstr, 11 ) != 11 ) goto write_failed; if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) ) goto write_failed; if ( write (fd, "\n", 1 ) != 1 ) goto write_failed; if ( close (fd) ) goto write_failed; /* Check whether we support hard links. */ switch (use_hardlinks_p (h->tname)) { case 0: /* Yes. */ break; case 1: /* No. */ unlink (h->tname); h->use_o_excl = 1; break; default: my_error_2 ("can't check whether hardlinks are supported for `%s': %s\n", h->tname, strerror(errno)); goto write_failed; } h->lockname = jnlib_malloc (strlen (file_to_lock) + 6 ); if (!h->lockname) { all_lockfiles = h->next; UNLOCK_all_lockfiles (); unlink (h->tname); jnlib_free (h->tname); jnlib_free (h); return NULL; } strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock"); UNLOCK_all_lockfiles (); if (h->use_o_excl) my_debug_1 ("locking for `%s' done via O_EXCL\n", h->lockname); return h; write_failed: all_lockfiles = h->next; UNLOCK_all_lockfiles (); my_error_2 (_("error writing to `%s': %s\n"), h->tname, strerror (errno)); close (fd); unlink (h->tname); jnlib_free (h->tname); jnlib_free (h); return NULL; }
static int read_lockfile (dotlock_t h, int *same_node ) { char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node names are usually shorter. */ int fd; int pid = -1; char *buffer, *p; size_t expected_len; int res, nread; *same_node = 0; expected_len = 10 + 1 + h->nodename_len + 1; if ( expected_len >= sizeof buffer_space) { buffer = jnlib_malloc (expected_len); if (!buffer) return -1; } else buffer = buffer_space; if ( (fd = open (h->lockname, O_RDONLY)) == -1 ) { int e = errno; my_info_2 ("error opening lockfile `%s': %s\n", h->lockname, strerror(errno) ); if (buffer != buffer_space) jnlib_free (buffer); jnlib_set_errno (e); /* Need to return ERRNO here. */ return -1; } p = buffer; nread = 0; do { res = read (fd, p, expected_len - nread); if (res == -1 && errno == EINTR) continue; if (res < 0) { my_info_1 ("error reading lockfile `%s'\n", h->lockname ); close (fd); if (buffer != buffer_space) jnlib_free (buffer); jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */ return -1; } p += res; nread += res; } while (res && nread != expected_len); close(fd); if (nread < 11) { my_info_1 ("invalid size of lockfile `%s'\n", h->lockname); if (buffer != buffer_space) jnlib_free (buffer); jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */ return -1; } if (buffer[10] != '\n' || (buffer[10] = 0, pid = atoi (buffer)) == -1 || !pid ) { my_error_2 ("invalid pid %d in lockfile `%s'\n", pid, h->lockname); if (buffer != buffer_space) jnlib_free (buffer); jnlib_set_errno (0); return -1; } if (nread == expected_len && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len) && buffer[11+h->nodename_len] == '\n') *same_node = 1; if (buffer != buffer_space) jnlib_free (buffer); return pid; }
static duk_ret_t test_error_va_return(duk_context *ctx, void *udata) { (void) udata; duk_set_top(ctx, 0); return my_error_2(ctx, DUK_ERR_RANGE_ERROR, "my error %d %d %s", 123, 234, "foobar"); }