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