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