summaryrefslogtreecommitdiff
path: root/nptl
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-02-25 06:19:22 +0000
committerUlrich Drepper <drepper@redhat.com>2003-02-25 06:19:22 +0000
commit3857ca787c88f420b7ead5b52fd6495ae65083e4 (patch)
treeee61b34feec0b8f28c50bd882bc61774f9f9dac0 /nptl
parent80d807799f5d0cadb9d7e28788b51e6930fb286c (diff)
downloadglibc-3857ca787c88f420b7ead5b52fd6495ae65083e4.tar.gz
Update.
* sem_open.c (sem_open): Fix handling of O_CREAT without O_EXCL.
Diffstat (limited to 'nptl')
-rw-r--r--nptl/ChangeLog2
-rw-r--r--nptl/sem_open.c84
2 files changed, 45 insertions, 41 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 05aee28cb5..d8ccec38a2 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,5 +1,7 @@
2003-02-24 Ulrich Drepper <drepper@redhat.com>
+ * sem_open.c (sem_open): Fix handling of O_CREAT without O_EXCL.
+
* tst-cond2.c: Fix sychronization with child.
* tst-rwlock8.c (reader_thread): Remove unused variable.
diff --git a/nptl/sem_open.c b/nptl/sem_open.c
index 0ed8001204..5def4ff9bb 100644
--- a/nptl/sem_open.c
+++ b/nptl/sem_open.c
@@ -126,7 +126,7 @@ sem_t *
sem_open (const char *name, int oflag, ...)
{
char *finalname;
- size_t namelen;
+ size_t namelen = SEM_FAILED;
sem_t *result;
int fd;
@@ -158,19 +158,24 @@ sem_open (const char *name, int oflag, ...)
name, namelen + 1);
/* If the semaphore object has to exist simply open it. */
- if ((oflag & O_CREAT) == 0)
+ if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0)
{
- fd = __libc_open (finalname, oflag | O_NOFOLLOW);
+ try_again:
+ fd = __libc_open (finalname,
+ (oflag & ~(O_CREAT|O_ACCMODE)) | O_NOFOLLOW | O_RDWR);
if (fd == -1)
- /* Return. errno is already set. */
- return SEM_FAILED;
+ {
+ /* If we are supposed to create the file try this next. */
+ if ((oflag & O_CREAT) != 0)
+ goto try_create;
- /* Map the sem_t structure from the file. */
- result = (sem_t *) mmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0);
- if (MAP_FAILED != (void *) SEM_FAILED && result == MAP_FAILED)
- result = SEM_FAILED;
+ /* Return. errno is already set. */
+ }
+ else
+ /* Map the sem_t structure from the file. */
+ result = (sem_t *) mmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
}
else
{
@@ -181,6 +186,7 @@ sem_open (const char *name, int oflag, ...)
unsigned int value;
va_list ap;
+ try_create:
va_start (ap, oflag);
mode = va_arg (ap, mode_t);
@@ -213,46 +219,42 @@ sem_open (const char *name, int oflag, ...)
sizeof (sem_t) - sizeof (struct sem));
if (TEMP_FAILURE_RETRY (__libc_write (fd, &initsem, sizeof (sem_t)))
- != sizeof (sem_t)
+ == sizeof (sem_t)
/* Adjust the permission. */
- || fchmod (fd, mode) != 0)
+ && fchmod (fd, mode) == 0
+ /* Map the sem_t structure from the file. */
+ && (result = (sem_t *) mmap (NULL, sizeof (sem_t),
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, 0)) != MAP_FAILED)
{
- unlink_return:
- unlink (tmpfname);
- return SEM_FAILED;
- }
+ /* Create the file. Don't overwrite an existing file. */
+ if (link (tmpfname, finalname) != 0)
+ {
+ /* Remove the file. */
+ unlink (tmpfname);
- /* Map the sem_t structure from the file. */
- result = (sem_t *) mmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0);
- if (result == MAP_FAILED)
- goto unlink_return;
+ /* Undo the mapping. */
+ (void) munmap (result, sizeof (sem_t));
- /* Create or overwrite the file. Depending on what is wanted we
- use rename or link. */
- if ((oflag & O_EXCL) == 0)
- {
- /* An existing file gets overwritten. */
- if (rename (tmpfname, finalname) != 0)
- {
- unmap_unlink_return:
- munmap (result, sizeof (sem_t));
- goto unlink_return;
+ /* Reinitialize 'result'. */
+ result = SEM_FAILED;
+
+ /* This failed. If O_EXCL is not set and the problem was
+ that the file exists, try again. */
+ if ((oflag & O_EXCL) == 0 && errno == EEXIST)
+ goto try_again;
}
}
- else
- {
- /* Don't overwrite an existing file. */
- if (link (tmpfname, finalname) != 0)
- goto unmap_unlink_return;
- /* This went well. Now remove the temporary name. This
- should never fail. If it fails we leak a file name.
- Better fix the kernel. */
- (void) unlink (tmpfname);
- }
+ /* Now remove the temporary name. This should never fail. If
+ it fails we leak a file name. Better fix the kernel. */
+ (void) unlink (tmpfname);
}
+ /* Map the mmap error to the error we need. */
+ if (MAP_FAILED != (void *) SEM_FAILED && result == MAP_FAILED)
+ result = SEM_FAILED;
+
/* We don't need the file descriptor anymore. */
__libc_close (fd);