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