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
31
32 /* XXX Currently the Linux kernel sources do not define a super magic number
33    for the shmfs and the kernel assigns the value 0 to f_type.  */
34 #ifndef SHMFS_SUPER_MAGIC
35 # define SHMFS_SUPER_MAGIC      0
36 #endif
37
38 /* Mount point of the shared memory filesystem.  */
39 static struct
40 {
41   char *dir;
42   size_t dirlen;
43 } mountpoint;
44
45 /* This is the default directory.  */
46 const char defaultdir[] = "/var/shm/";
47
48 /* Protect the `mountpoint' variable above.  */
49 __libc_once_define (static, once);
50
51
52 /* Determine where the shmfs is mounted (if at all).  */
53 static void
54 where_is_shmfs (void)
55 {
56   char buf[512];
57   struct statfs f;
58   struct mntent resmem;
59   struct mntent *mp;
60   FILE *fp;
61
62   /* The canonical place is /var/shm.  This is at least what the
63      documentation tells everybody to do.  */
64   if (__statfs ("/var/shm", &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
65     {
66       /* It is in the normal place.  */
67       mountpoint.dir = (char *) defaultdir;
68       mountpoint.dirlen = strlen ("/var/shm/");
69
70       return;
71     }
72
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))
77     {
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.  */
81         return;
82     }
83
84   /* Now read the entries.  */
85   while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
86     if (strcmp (mp->mnt_type, "shm") == 0)
87       {
88         /* Found it.  There might be more than one place where the
89            filesystem is mounted but one is enough for us.  */
90         size_t namelen = strlen (mp->mnt_dir);
91
92         if (namelen == 0)
93           /* Hum, maybe some crippled entry.  Keep on searching.  */
94           continue;
95
96         mountpoint.dir = (char *) malloc (namelen + 2);
97         if (mountpoint.dir != NULL)
98           {
99             char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
100             if (cp[-1] != '/')
101               *cp++ = '/';
102             *cp = '\0';
103             mountpoint.dirlen = cp - mountpoint.dir;
104           }
105
106         break;
107       }
108
109   /* Close the stream.  */
110   __endmntent (fp);
111 }
112
113
114 /* Open shared memory object.  This implementation assumes the shmfs
115    implementation introduced in the late 2.3.x kernel series to be
116    available.  Normally the filesystem will be mounted at /var/shm but
117    we fall back on searching for the actual mount point should opening
118    such a file fail.  */
119 int
120 shm_open (const char *name, int oflag, mode_t mode)
121 {
122   size_t namelen;
123   char *fname;
124   int fd;
125
126   /* Determine where the shmfs is mounted.  */
127   __libc_once (once, where_is_shmfs);
128
129   /* If we don't know the mount points there is nothing we can do.  Ever.  */
130   if (mountpoint.dir == NULL)
131     {
132       __set_errno (ENOSYS);
133       return -1;
134     }
135
136   /* Construct the filename.  */
137   while (name[0] == '/')
138     ++name;
139
140   if (name[0] == '\0')
141     {
142       /* The name "/" is not supported.  */
143       __set_errno (EINVAL);
144       return -1;
145     }
146
147   namelen = strlen (name);
148   fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
149   __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
150              name, namelen + 1);
151
152   /* And get the file descriptor.
153      XXX Maybe we should test each descriptor whether it really is for a
154      file on the shmfs.  If this is what should be done the whole function
155      should be revamped since we can determine whether shmfs is available
156      while trying to open the file, all in one turn.  */
157   fd = open (fname, oflag, mode);
158   if (fd != -1)
159     {
160       /* We got a descriptor.  Now set the FD_CLOEXEC bit.  */
161       int flags = fcntl (fd, F_GETFD, 0);
162
163       if (__builtin_expect (flags, 0) >= 0)
164         {
165           flags |= FD_CLOEXEC;
166           flags = fcntl (fd, F_SETFD, flags);
167         }
168
169       if (flags == -1)
170         {
171           /* Something went wrong.  We cannot return the descriptor.  */
172           int save_errno = errno;
173           close (fd);
174           fd = -1;
175           __set_errno (save_errno);
176         }
177     }
178
179   return fd;
180 }
181
182
183 /* Unlink a shared memory object.  */
184 int
185 shm_unlink (const char *name)
186 {
187   size_t namelen;
188   char *fname;
189
190   /* Determine where the shmfs is mounted.  */
191   __libc_once (once, where_is_shmfs);
192
193   if (mountpoint.dir == NULL)
194     {
195       /* We cannot find the shmfs.  If `name' is really a shared
196          memory object it must have been created by another process
197          and we have no idea where that process found the mountpoint.  */
198       __set_errno (ENOENT);
199       return -1;
200     }
201
202   /* Construct the filename.  */
203   while (name[0] == '/')
204     ++name;
205
206   if (name[0] == '\0')
207     {
208       /* The name "/" is not supported.  */
209       __set_errno (ENOENT);
210       return -1;
211     }
212
213   namelen = strlen (name);
214   fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
215   __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
216              name, namelen + 1);
217
218   /* And get the file descriptor.
219      XXX Maybe we should test each descriptor whether it really is for a
220      file on the shmfs.  If this is what should be done the whole function
221      should be revamped since we can determine whether shmfs is available
222      while trying to open the file, all in one turn.  */
223   return unlink (fname);
224 }
225
226
227 void
228 freeit (void)
229 {
230   if (mountpoint.dir != NULL && mountpoint.dir != defaultdir)
231     free (mountpoint.dir);
232 }
233
234
235 /* Make sure the table is freed if we want to free everything before
236    exiting.  */
237 text_set_element (__libc_subfreeres, freeit);