1 /* Copyright (C) 2002 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 #include <semaphore.h>
33 #include <sys/statfs.h>
34 #include <linux_fsinfo.h>
35 #include "semaphoreP.h"
39 /* Information about the mount point. */
40 struct mountpoint_info mountpoint attribute_hidden
;
42 /* This is the default mount point. */
43 static const char defaultmount
[] = "/dev/shm";
44 /* This is the default directory. */
45 static const char defaultdir
[] = "/dev/shm/sem.";
47 /* Protect the `mountpoint' variable above. */
48 pthread_once_t __namedsem_once attribute_hidden
= PTHREAD_ONCE_INIT
;
51 /* Determine where the shmfs is mounted (if at all). */
54 __where_is_shmfs (void)
62 /* The canonical place is /dev/shm. This is at least what the
63 documentation tells everybody to do. */
64 if (__statfs (defaultmount
, &f
) == 0 && f
.f_type
== SHMFS_SUPER_MAGIC
)
66 /* It is in the normal place. */
67 mountpoint
.dir
= (char *) defaultdir
;
68 mountpoint
.dirlen
= sizeof (defaultdir
) - 1;
73 /* OK, do it the hard way. Look through the /proc/mounts file and if
74 this does not exist through /etc/fstab to find the mount point. */
75 fp
= __setmntent ("/proc/mounts", "r");
76 if (__builtin_expect (fp
== NULL
, 0))
78 fp
= __setmntent (_PATH_MNTTAB
, "r");
79 if (__builtin_expect (fp
== NULL
, 0))
80 /* There is nothing we can do. Blind guesses are not helpful. */
84 /* Now read the entries. */
85 while ((mp
= __getmntent_r (fp
, &resmem
, buf
, sizeof buf
)) != NULL
)
86 /* The original name is "shm" but this got changed in early Linux
88 if (strcmp (mp
->mnt_type
, "tmpfs") == 0
89 || strcmp (mp
->mnt_type
, "shm") == 0)
91 /* Found it. There might be more than one place where the
92 filesystem is mounted but one is enough for us. */
95 /* First make sure this really is the correct entry. At least
96 some versions of the kernel give wrong information because
97 of the implicit mount of the shmfs for SysV IPC. */
98 if (__statfs (mp
->mnt_dir
, &f
) != 0 || f
.f_type
!= SHMFS_SUPER_MAGIC
)
101 namelen
= strlen (mp
->mnt_dir
);
104 /* Hum, maybe some crippled entry. Keep on searching. */
107 mountpoint
.dir
= (char *) malloc (namelen
+ 4 + 2);
108 if (mountpoint
.dir
!= NULL
)
110 char *cp
= __mempcpy (mountpoint
.dir
, mp
->mnt_dir
, namelen
);
113 cp
= stpcpy (cp
, "sem.");
114 mountpoint
.dirlen
= cp
- mountpoint
.dir
;
120 /* Close the stream. */
126 sem_open (const char *name
, int oflag
, ...)
133 /* Determine where the shmfs is mounted. */
134 pthread_once (&__namedsem_once
, __where_is_shmfs
);
136 /* If we don't know the mount points there is nothing we can do. Ever. */
137 if (mountpoint
.dir
== NULL
)
139 __set_errno (ENOSYS
);
143 /* Construct the filename. */
144 while (name
[0] == '/')
149 /* The name "/" is not supported. */
150 __set_errno (EINVAL
);
153 namelen
= strlen (name
);
155 /* Create the name of the final file. */
156 finalname
= (char *) alloca (mountpoint
.dirlen
+ namelen
+ 1);
157 __mempcpy (__mempcpy (finalname
, mountpoint
.dir
, mountpoint
.dirlen
),
160 /* If the semaphore object has to exist simply open it. */
161 if ((oflag
& O_CREAT
) == 0)
163 fd
= open (finalname
, oflag
| O_NOFOLLOW
);
166 /* Return. errno is already set. */
169 /* Map the sem_t structure from the file. */
170 result
= (sem_t
*) mmap (NULL
, sizeof (sem_t
), PROT_READ
| PROT_WRITE
,
175 /* We have to open a temporary file first since it must have the
176 correct form before we can start using it. */
182 va_start (ap
, oflag
);
184 mode
= va_arg (ap
, mode_t
);
185 value
= va_arg (ap
, unsigned int);
189 if (value
> SEM_VALUE_MAX
)
191 __set_errno (EINVAL
);
195 tmpfname
= (char *) alloca (mountpoint
.dirlen
+ 6 + 1);
196 strcpy (__mempcpy (tmpfname
, mountpoint
.dir
, mountpoint
.dirlen
),
199 fd
= mkstemp (tmpfname
);
203 /* Create the initial file content. */
206 struct sem
*iinitsem
= (struct sem
*) &initsem
;
207 iinitsem
->count
= value
;
209 /* Initialize the remaining bytes as well. */
210 memset ((char *) &initsem
+ sizeof (struct sem
), '\0',
211 sizeof (sem_t
) - sizeof (struct sem
));
213 if (TEMP_FAILURE_RETRY (write (fd
, &initsem
, sizeof (sem_t
)))
215 /* Adjust the permission. */
216 || fchmod (fd
, mode
) != 0)
223 /* Map the sem_t structure from the file. */
224 result
= (sem_t
*) mmap (NULL
, sizeof (sem_t
), PROT_READ
| PROT_WRITE
,
226 if (result
== MAP_FAILED
)
229 /* Create or overwrite the file. Depending on what is wanted we
230 use rename or link. */
231 if ((oflag
& O_EXCL
) == 0)
233 /* An existing file gets overwritten. */
234 if (rename (tmpfname
, finalname
) != 0)
237 munmap (result
, sizeof (sem_t
));
243 /* Don't overwrite an existing file. */
244 if (link (tmpfname
, finalname
) != 0)
245 goto unmap_unlink_return
;
247 /* This went well. Now remove the temporary name. This
248 should never fail. If it fails we leak a file name.
249 Better fix the kernel. */
250 (void) unlink (tmpfname
);
254 /* We don't need the file descriptor anymore. */