1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1990-2011 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 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 
22 /*
23  * Glenn Fowler
24  * AT&T Bell Laboratories
25  *
26  * file cat service
27  * this gets around NonFS multi-client file cache inconsistencies
28  */
29 
30 static const char id[] = "\n@(#)$Id: cs.cat (AT&T Bell Laboratories) 1995-05-09 $\0\n";
31 
32 #include <ast.h>
33 #include <cs.h>
34 #include <error.h>
35 #include <hash.h>
36 #include <msg.h>
37 
38 #define CAT_MSG		(1<<0)		/* cs msg with size		*/
39 
40 typedef struct				/* open file id key		*/
41 {
42 	unsigned long	dev;		/* st_dev			*/
43 	unsigned long	ino;		/* st_ino			*/
44 } Fid_t;
45 
46 typedef struct				/* open file info		*/
47 {
48 	HASH_HEADER;
49 	int		fd;		/* O_APPEND fd			*/
50 	int		flags;		/* CAT_* flags			*/
51 	int		reference;	/* user reference count		*/
52 } File_t;
53 
54 typedef struct				/* server state			*/
55 {
56 	Hash_table_t*	files;		/* Fid_t hash			*/
57 	int		active;		/* # open connections		*/
58 	int		dormant;	/* dormant timeout check	*/
59 	char		buf[MSG_SIZE_BUF];/* io buffer			*/
60 	File_t*		cat[1];		/* user file reference		*/
61 } State_t;
62 
63 /*
64  * initialize the state
65  */
66 
67 static void*
svc_init(void * handle,int fdmax)68 svc_init(void* handle, int fdmax)
69 {
70 	State_t*	state;
71 
72 	NoP(handle);
73 	if (!(state = newof(0, State_t, 1, (fdmax - 1) * sizeof(File_t*))))
74 		error(3, "out of space [state]");
75 	if (!(state->files = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_namesize, sizeof(Fid_t), HASH_name, "files", 0)))
76 		error(3, "out of space [files]");
77 	cstimeout(CS_SVC_DORMANT * 1000L);
78 	return((void*)state);
79 }
80 
81 /*
82  * add a new connection
83  */
84 
85 static int
svc_connect(void * handle,int fd,Cs_id_t * id,int clone,char ** argv)86 svc_connect(void* handle, int fd, Cs_id_t* id, int clone, char** argv)
87 {
88 	register State_t*	state = (State_t*)handle;
89 	register File_t*	fp;
90 	register char*		s;
91 	int			ad;
92 	int			flags = 0;
93 	Fid_t			fid;
94 	struct stat		st;
95 
96 	NoP(id);
97 	NoP(clone);
98 	if (!argv)
99 		return(-1);
100 	while ((s = *argv++) && *s != '/')
101 		switch (*s)
102 		{
103 		case 'm':
104 			flags |= CAT_MSG;
105 			break;
106 		}
107 	if (!s || (ad = csopen(s, 0)) < 0 && (ad = open(s, O_CREAT|O_APPEND|O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
108 		return(-1);
109 	if (fstat(ad, &st))
110 	{
111 		close(ad);
112 		return(-1);
113 	}
114 	fid.dev = st.st_dev;
115 	fid.ino = st.st_ino;
116 	if (!(fp = (File_t*)hashlook(state->files, (char*)&fid, HASH_CREATE|HASH_SIZE(sizeof(File_t)), NiL)))
117 	{
118 		close(ad);
119 		return(-1);
120 	}
121 	if (!fp->reference++) fp->fd = ad;
122 	else close(ad);
123 	fp->flags |= flags;
124 	state->cat[fd] = fp;
125 	state->active++;
126 	state->dormant = 0;
127 	return(0);
128 }
129 
130 /*
131  * service a request
132  */
133 
134 static int
svc_read(void * handle,int fd)135 svc_read(void* handle, int fd)
136 {
137 	register State_t*	state = (State_t*)handle;
138 	register ssize_t	n;
139 	register ssize_t	m;
140 	register ssize_t	i;
141 	register File_t*	fp = state->cat[fd];
142 	int			ok;
143 
144 	if (fp->flags & CAT_MSG)
145 	{
146 		if (cspeek(fd, state->buf, MSG_SIZE_SIZE) == MSG_SIZE_SIZE)
147 		{
148 			ok = 1;
149 			if ((m = msggetsize(state->buf)) > MSG_SIZE_SIZE) do
150 			{
151 				i = (m > sizeof(state->buf)) ? sizeof(state->buf) : m;
152 				if ((n = csread(fd, state->buf, i, CS_EXACT)) <= 0)
153 				{
154 					ok = 0;
155 					memzero(state->buf, n = i);
156 				}
157 				if (cswrite(fp->fd, state->buf, n) != n)
158 				{
159 					ok = 0;
160 					break;
161 				}
162 			} while ((m -= n) > 0);
163 			if (ok) return(0);
164 		}
165 	}
166 	else if ((n = csread(fd, state->buf, sizeof(state->buf), CS_LIMIT)) > 0 && cswrite(fp->fd, state->buf, n) == n)
167 		return(0);
168 	if (!--fp->reference)
169 	{
170 		close(fp->fd);
171 		hashlook(state->files, fp->name, HASH_DELETE, NiL);
172 	}
173 	state->active--;
174 	return(-1);
175 }
176 
177 /*
178  * exit if no open connections on timeout
179  */
180 
181 static int
svc_timeout(void * handle)182 svc_timeout(void* handle)
183 {
184 	State_t*	state = (State_t*)handle;
185 
186 	if (!state->active)
187 	{
188 		if (state->dormant)
189 			exit(0);
190 		state->dormant = 1;
191 	}
192 	return(0);
193 }
194 
195 int
main(int argc,char ** argv)196 main(int argc, char** argv)
197 {
198 	NoP(argc);
199 	csserve(NiL, argv[1], svc_init, NiL, svc_connect, svc_read, NiL, svc_timeout);
200 	exit(1);
201 }
202