1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 
24 #include "asohdr.h"
25 
26 #if defined(_UWIN) && defined(_BLD_ast) || !_aso_fcntl
27 
28 NoN(aso_meth_fcntl)
29 
30 #else
31 
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 
36 typedef struct APL_s
37 {
38 	int		fd;
39 	size_t		size;
40 	char		path[1];
41 } APL_t;
42 
43 static void*
44 aso_init_fcntl(void* data, const char* details)
45 {
46 	APL_t*		apl = (APL_t*)data;
47 	char*		path;
48 	char*		opt;
49 	size_t		size;
50 	size_t		references;
51 	int		n;
52 	int		fd;
53 	int		drop;
54 	int		perm;
55 	struct flock	lock;
56 	char		buf[PATH_MAX];
57 	char		tmp[64];
58 
59 	if (apl)
60 	{
61 		lock.l_type = F_WRLCK;
62 		lock.l_whence = SEEK_SET;
63 		lock.l_start = apl->size;
64 		lock.l_len = sizeof(references);
65 		if (fcntl(apl->fd, F_SETLKW, &lock) >= 0)
66 		{
67 			if (lseek(apl->fd, apl->size, SEEK_SET) != apl->size)
68 				references = 0;
69 			else if (read(apl->fd, &references, sizeof(references)) != sizeof(references))
70 				references = 0;
71 			else if (references > 0)
72 			{
73 				references--;
74 				if (lseek(apl->fd, apl->size, SEEK_SET) != apl->size)
75 					references = 0;
76 				else if (write(apl->fd, &references, sizeof(references)) != sizeof(references))
77 					references = 0;
78 			}
79 			lock.l_type = F_UNLCK;
80 			fcntl(apl->fd, F_SETLK, &lock);
81 			if (!references)
82 				remove(apl->path);
83 		}
84 		close(apl->fd);
85 		free(apl);
86 		return 0;
87 	}
88 	fd = -1;
89 	perm = S_IRUSR|S_IWUSR;
90 	drop = 0;
91 	size = 32 * 1024 - sizeof(references);
92 	if (path = (char*)details)
93 		while (opt = strchr(path, ','))
94 		{
95 			if (strneq(path, "perm=", 5))
96 			{
97 				if ((n = opt - (path + 5)) >= sizeof(tmp))
98 					n = sizeof(tmp) - 1;
99 				memcpy(tmp, path + 5, n);
100 				tmp[n] = 0;
101 				perm = strperm(tmp, NiL, perm);
102 			}
103 			else if (strneq(path, "size=", 5))
104 			{
105 				size = strtoul(path + 5, NiL, 0);
106 				if (size <= sizeof(references))
107 					goto bad;
108 				size -= sizeof(references);
109 			}
110 			path = opt + 1;
111 		}
112 	if (!path || !*path)
113 	{
114 		if (!(path = pathtemp(buf, sizeof(buf), NiL, "aso", &fd)))
115 			return 0;
116 		drop = 1;
117 	}
118 	if (!(apl = newof(0, APL_t, 1, strlen(path))))
119 		goto bad;
120 	if (fd >= 0 || (fd = open(path, O_RDWR|O_cloexec)) < 0 && (fd = open(path, O_CREAT|O_RDWR|O_cloexec, perm)) >= 0)
121 	{
122 		if (lseek(fd, size, SEEK_SET) != size)
123 			goto bad;
124 		references = 1;
125 		if (write(fd, &references, sizeof(references)) != sizeof(references))
126 			goto bad;
127 	}
128 	else
129 	{
130 		if ((size = lseek(fd, 0, SEEK_END)) <= sizeof(references))
131 			goto bad;
132 		size -= sizeof(references);
133 		lock.l_type = F_WRLCK;
134 		lock.l_whence = SEEK_SET;
135 		lock.l_start = 0;
136 		lock.l_len = sizeof(references);
137 		if (fcntl(fd, F_SETLKW, &lock) < 0)
138 			goto bad;
139 		if (lseek(fd, size, SEEK_SET) != size)
140 			goto bad;
141 		if (read(fd, &references, sizeof(references)) != sizeof(references))
142 			goto bad;
143 		references++;
144 		if (lseek(fd, size, SEEK_SET) != size)
145 			goto bad;
146 		if (write(fd, &references, sizeof(references)) != sizeof(references))
147 			goto bad;
148 		lock.l_type = F_UNLCK;
149 		fcntl(fd, F_SETLK, &lock);
150 	}
151 	apl->fd = fd;
152 	apl->size = size;
153 	strcpy(apl->path, path);
154 	return apl;
155  bad:
156 	if (apl)
157 		free(apl);
158 	if (fd >= 0)
159 		close(fd);
160 	if (drop)
161 		remove(path);
162 	return 0;
163 }
164 
165 static ssize_t
166 aso_lock_fcntl(void* data, ssize_t k, void volatile* p)
167 {
168 	APL_t*		apl = (APL_t*)data;
169 	struct flock	lock;
170 
171 	if (!apl)
172 		return -1;
173 	if (k > 0)
174 		lock.l_type = F_UNLCK;
175 	else
176 	{
177 		lock.l_type = F_WRLCK;
178 		k = HASH(p, apl->size) + 1;
179 	}
180 	lock.l_whence = SEEK_SET;
181 	lock.l_start = k - 1;
182 	lock.l_len = 1;
183 	return fcntl(apl->fd, F_SETLKW, &lock) < 0 ? -1 : k;
184 }
185 
186 Asometh_t	_aso_meth_fcntl = { "fcntl", ASO_PROCESS, aso_init_fcntl, aso_lock_fcntl };
187 
188 #endif
189