Update.
[platform/upstream/glibc.git] / sysdeps / unix / sysv / linux / shm_open.c
1 /* Copyright (C) 2000 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <mntent.h>
22 #include <paths.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/mman.h>
28 #include <sys/statfs.h>
29 #include <bits/libc-lock.h>
30 #include "linux_fsinfo.h"
31
32
33 /* Mount point of the shared memory filesystem.  */
34 static struct
35 {
36   char *dir;
37   size_t dirlen;
38 } mountpoint;
39
40 /* This is the default directory.  */
41 static const char defaultdir[] = "/dev/shm/";
42
43 /* Protect the `mountpoint' variable above.  */
44 __libc_once_define (static, once);
45
46
47 /* Determine where the shmfs is mounted (if at all).  */
48 static void
49 where_is_shmfs (void)
50 {
51   char buf[512];
52   struct statfs f;
53   struct mntent resmem;
54   struct mntent *mp;
55   FILE *fp;
56
57   /* The canonical place is /dev/shm.  This is at least what the
58      documentation tells everybody to do.  */
59   if (__statfs (defaultdir, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
60     {
61       /* It is in the normal place.  */
62       mountpoint.dir = (char *) defaultdir;
63       mountpoint.dirlen = sizeof (defaultdir) - 1;
64
65       return;
66     }
67
68   /* OK, do it the hard way.  Look through the /proc/mounts file and if
69      this does not exist through /etc/fstab to find the mount point.  */
70   fp = __setmntent ("/proc/mounts", "r");
71   if (__builtin_expect (fp == NULL, 0))
72     {
73       fp = __setmntent (_PATH_MNTTAB, "r");
74       if (__builtin_expect (fp == NULL, 0))
75         /* There is nothing we can do.  Blind guesses are not helpful.  */
76         return;
77     }
78
79   /* Now read the entries.  */
80   while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
81     if (strcmp (mp->mnt_type, "shm") == 0)
82       {
83         /* Found it.  There might be more than one place where the
84            filesystem is mounted but one is enough for us.  */
85         size_t namelen;
86
87         /* First make sure this really is the correct entry.  At least
88            some versions of the kernel give wrong information because
89            of the implicit mount of the shmfs for SysV IPC.  */
90         if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC)
91           continue;
92
93         namelen = strlen (mp->mnt_dir);
94
95         if (namelen == 0)
96           /* Hum, maybe some crippled entry.  Keep on searching.  */
97           continue;
98
99         mountpoint.dir = (char *) malloc (namelen + 2);
100         if (mountpoint.dir != NULL)
101           {
102             char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
103             if (cp[-1] != '/')
104               *cp++ = '/';
105             *cp = '\0';
106             mountpoint.dirlen = cp - mountpoint.dir;
107           }
108
109         break;
110       }
111
112   /* Close the stream.  */
113   __endmntent (fp);
114 }
115
116
117 /* Open shared memory object.  This implementation assumes the shmfs
118    implementation introduced in the late 2.3.x kernel series to be
119    available.  Normally the filesystem will be mounted at /dev/shm but
120    we fall back on searching for the actual mount point should opening
121    such a file fail.  */
122 int
123 shm_open (const char *name, int oflag, mode_t mode)
124 {
125   size_t namelen;
126   char *fname;
127   int fd;
128
129   /* Determine where the shmfs is mounted.  */
130   __libc_once (once, where_is_shmfs);
131
132   /* If we don't know the mount points there is nothing we can do.  Ever.  */
133   if (mountpoint.dir == NULL)
134     {
135       __set_errno (ENOSYS);
136       return -1;
137     }
138
139   /* Construct the filename.  */
140   while (name[0] == '/')
141     ++name;
142
143   if (name[0] == '\0')
144     {
145       /* The name "/" is not supported.  */
146       __set_errno (EINVAL);
147       return -1;
148     }
149
150   namelen = strlen (name);
151   fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
152   __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
153              name, namelen + 1);
154
155   /* And get the file descriptor.
156      XXX Maybe we should test each descriptor whether it really is for a
157      file on the shmfs.  If this is what should be done the whole function
158      should be revamped since we can determine whether shmfs is available
159      while trying to open the file, all in one turn.  */
160   fd = open (fname, oflag, mode);
161   if (fd != -1)
162     {
163       /* We got a descriptor.  Now set the FD_CLOEXEC bit.  */
164       int flags = fcntl (fd, F_GETFD, 0);
165
166       if (__builtin_expect (flags, 0) >= 0)
167         {
168           flags |= FD_CLOEXEC;
169           flags = fcntl (fd, F_SETFD, flags);
170         }
171
172       if (flags == -1)
173         {
174           /* Something went wrong.  We cannot return the descriptor.  */
175           int save_errno = errno;
176           close (fd);
177           fd = -1;
178           __set_errno (save_errno);
179         }
180     }
181
182   return fd;
183 }
184
185
186 /* Unlink a shared memory object.  */
187 int
188 shm_unlink (const char *name)
189 {
190   size_t namelen;
191   char *fname;
192
193   /* Determine where the shmfs is mounted.  */
194   __libc_once (once, where_is_shmfs);
195
196   if (mountpoint.dir == NULL)
197     {
198       /* We cannot find the shmfs.  If `name' is really a shared
199          memory object it must have been created by another process
200          and we have no idea where that process found the mountpoint.  */
201       __set_errno (ENOENT);
202       return -1;
203     }
204
205   /* Construct the filename.  */
206   while (name[0] == '/')
207     ++name;
208
209   if (name[0] == '\0')
210     {
211       /* The name "/" is not supported.  */
212       __set_errno (ENOENT);
213       return -1;
214     }
215
216   namelen = strlen (name);
217   fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
218   __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
219              name, namelen + 1);
220
221   /* And remove the file.  */
222   return unlink (fname);
223 }
224
225
226 static void  __attribute__ ((unused))
227 freeit (void)
228 {
229   if (mountpoint.dir != defaultdir)
230     free (mountpoint.dir);
231 }
232
233
234 /* Make sure the table is freed if we want to free everything before
235    exiting.  */
236 text_set_element (__libc_subfreeres, freeit);