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
125   /* Determine where the shmfs is mounted.  */
126   __libc_once (once, where_is_shmfs);
127
128   /* If we don't know the mount points there is nothing we can do.  Ever.  */
129   if (mountpoint.dir == NULL)
130     {
131       __set_errno (ENOSYS);
132       return -1;
133     }
134
135   /* Construct the filename.  */
136   while (name[0] == '/')
137     ++name;
138
139   if (name[0] == '\0')
140     {
141       /* The name "/" is not supported.  */
142       __set_errno (EINVAL);
143       return -1;
144     }
145
146   namelen = strlen (name);
147   fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
148   __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
149              name, namelen + 1);
150
151   /* And get the file descriptor.
152      XXX Maybe we should test each descriptor whether it really is for a
153      file on the shmfs.  If this is what should be done the whole function
154      should be revamped since we can determine whether shmfs is available
155      while trying to open the file, all in one turn.  */
156   return open (fname, oflag, mode);
157 }
158
159
160 /* Unlink a shared memory object.  */
161 int
162 shm_unlink (const char *name)
163 {
164   size_t namelen;
165   char *fname;
166
167   /* Determine where the shmfs is mounted.  */
168   __libc_once (once, where_is_shmfs);
169
170   if (mountpoint.dir == NULL)
171     {
172       /* We cannot find the shmfs.  If `name' is really a shared
173          memory object it must have been created by another process
174          and we have no idea where that process found the mountpoint.  */
175       __set_errno (ENOENT);
176       return -1;
177     }
178
179   /* Construct the filename.  */
180   while (name[0] == '/')
181     ++name;
182
183   if (name[0] == '\0')
184     {
185       /* The name "/" is not supported.  */
186       __set_errno (ENOENT);
187       return -1;
188     }
189
190   namelen = strlen (name);
191   fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
192   __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
193              name, namelen + 1);
194
195   /* And get the file descriptor.
196      XXX Maybe we should test each descriptor whether it really is for a
197      file on the shmfs.  If this is what should be done the whole function
198      should be revamped since we can determine whether shmfs is available
199      while trying to open the file, all in one turn.  */
200   return unlink (fname);
201 }
202
203
204 void
205 freeit (void)
206 {
207   if (mountpoint.dir != NULL && mountpoint.dir != defaultdir)
208     free (mountpoint.dir);
209 }
210
211
212 /* Make sure the table is freed if we want to free everything before
213    exiting.  */
214 text_set_element (__libc_subfreeres, freeit);