Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/cs/dbm.c
1808 views
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 <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Bell Laboratories
24
*
25
* dbm server
26
*
27
* keys may not contain {<blank>,<newline>,<null>}
28
* vals may not contain {<newline>,<null>}
29
*
30
* commands
31
*
32
* close close
33
* get key return value for key
34
* next [``value''] return next key in scan with optional value
35
* open file [r|w|rw] open [rw] + implicit scan
36
* put key [value] put [delete] value for key
37
* scan initialize for scan
38
*
39
* replies
40
*
41
* I ... information
42
* W ... warning message
43
* E ... error message
44
*
45
* NOTE: the scans cheat by using dbm_blkptr and dbm_keyptr
46
*/
47
48
static const char id[] = "\n@(#)$Id: cs.dbm (AT&T Bell Laboratories) 1995-05-09 $\0\n";
49
50
#include <ast.h>
51
#include <error.h>
52
#include <tok.h>
53
54
#include "FEATURE/ndbm"
55
56
#if !_lib_ndbm
57
58
int
59
main(int argc, char** argv)
60
{
61
NoP(argc);
62
NoP(argv);
63
error(3, "<ndbm.h> library required");
64
}
65
66
#else
67
68
#define keyptr dbm_keyptr
69
#define blkptr dbm_blkptr
70
71
#include <cs.h>
72
#include <error.h>
73
#include <ndbm.h>
74
75
typedef struct /* open dbm info */
76
{
77
DBM* dbm; /* dbm stream pointer */
78
dev_t dev; /* device */
79
ino_t ino; /* inode */
80
int ref; /* reference count */
81
} Db_t;
82
83
typedef struct /* connection info */
84
{
85
long blkptr; /* dbm_blkptr from last next */
86
int keyptr; /* dbm_keyptr from last next */
87
int readonly; /* readonly open */
88
int scan; /* scan in progress */
89
Db_t* db; /* open dbm info */
90
} Con_t;
91
92
typedef struct /* server state */
93
{
94
int active; /* number active connections */
95
int conmax; /* max number connections */
96
int dormant; /* inactivity check */
97
Con_t* con; /* connections */
98
Db_t* dbs; /* open dbs */
99
} State_t;
100
101
/*
102
* initialize the state
103
*/
104
105
static void*
106
svc_init(void* handle, int fdmax)
107
{
108
State_t* state = (State_t*)handle;
109
110
state->conmax = fdmax;
111
if (!(state->con = newof(0, Con_t, state->conmax, 0)))
112
error(3, "out of space [con]");
113
if (!(state->dbs = newof(0, Db_t, state->conmax, 0)))
114
error(3, "out of space [dbs]");
115
cstimeout(CS_SVC_DORMANT * 1000L);
116
return(handle);
117
}
118
119
/*
120
* add a new connection
121
*/
122
123
static int
124
svc_connect(void* handle, int fd, Cs_id_t* id, int clone, char** args)
125
{
126
register State_t* state = (State_t*)handle;
127
register Con_t* cp;
128
129
NoP(id);
130
NoP(clone);
131
NoP(args);
132
cp = state->con + fd;
133
cp->db = 0;
134
cp->scan = 0;
135
state->active++;
136
state->dormant = 0;
137
return(0);
138
}
139
140
/*
141
* service a request
142
*/
143
144
static int
145
svc_read(void* handle, int fd)
146
{
147
register State_t* state = (State_t*)handle;
148
register Con_t* cp;
149
register Db_t* dp;
150
int n;
151
char* cmd;
152
char* s;
153
datum key;
154
datum val;
155
char msg[4 * PATH_MAX];
156
char ret[4 * PATH_MAX];
157
char* nxt = msg;
158
struct stat st;
159
160
cp = state->con + fd;
161
if ((n = csread(fd, nxt, sizeof(msg), CS_LINE)) <= 0) goto drop;
162
nxt[n - 1] = 0;
163
while (tokscan(nxt, &nxt, " %s %s %s", &cmd, &key.dptr, &val.dptr) > 0)
164
{
165
key.dsize = strlen(key.dptr) + 1;
166
val.dsize = strlen(val.dptr) + 1;
167
switch (*cmd)
168
{
169
case 'c':
170
if (!cp->db) goto notopen;
171
if (!--cp->db->ref) dbm_close(cp->db->dbm);
172
cp->db = 0;
173
n = sfsprintf(ret, sizeof(ret), "I closed\n", key.dptr);
174
break;
175
case 'g':
176
if (!cp->db) goto notopen;
177
val = dbm_fetch(cp->db->dbm, key);
178
if (val.dptr) n = sfsprintf(ret, sizeof(ret), "I %s\n", val.dptr);
179
else if (dbm_error(cp->db->dbm))
180
{
181
dbm_clearerr(cp->db->dbm);
182
n = sfsprintf(ret, sizeof(ret), "E db io error\n");
183
}
184
else n = sfsprintf(ret, sizeof(ret), "W %s not in db\n", key.dptr);
185
break;
186
case 'n':
187
if (!cp->db) goto notopen;
188
n = *((char*)key.dptr);
189
if (!cp->scan)
190
{
191
cp->scan = 1;
192
key = dbm_firstkey(cp->db->dbm);
193
}
194
else
195
{
196
cp->db->dbm->dbm_blkptr = cp->blkptr;
197
cp->db->dbm->dbm_keyptr = cp->keyptr;
198
key = dbm_nextkey(cp->db->dbm);
199
}
200
cp->blkptr = cp->db->dbm->dbm_blkptr;
201
cp->keyptr = cp->db->dbm->dbm_keyptr;
202
if (key.dptr)
203
{
204
if (n)
205
{
206
val = dbm_fetch(cp->db->dbm, key);
207
if (val.dptr) n = sfsprintf(ret, sizeof(ret), "I %s %s\n", key.dptr, val.dptr);
208
else
209
{
210
if (dbm_error(cp->db->dbm))
211
{
212
dbm_clearerr(cp->db->dbm);
213
n = sfsprintf(ret, sizeof(ret), "E db io error\n");
214
}
215
else n = sfsprintf(ret, sizeof(ret), "E %s not in db\n", key.dptr);
216
cp->scan = 0;
217
}
218
}
219
else n = sfsprintf(ret, sizeof(ret), "I %s\n", key.dptr);
220
}
221
else
222
{
223
if (dbm_error(cp->db->dbm))
224
{
225
dbm_clearerr(cp->db->dbm);
226
n = sfsprintf(ret, sizeof(ret), "E db io error\n");
227
}
228
else n = sfsprintf(ret, sizeof(ret), "W end of scan\n");
229
cp->scan = 0;
230
}
231
break;
232
case 'o':
233
if (cp->db)
234
{
235
if (!--cp->db->ref) dbm_close(cp->db->dbm);
236
cp->db = 0;
237
}
238
cp->scan = 0;
239
for (s = val.dptr; *s; s++)
240
if (*s == 'w') break;
241
cp->readonly = *((char*)val.dptr) && !*s;
242
sfsprintf(ret, sizeof(ret), "%s.dir", key.dptr);
243
if (!stat(ret, &st))
244
for (dp = state->dbs; dp < state->dbs + state->conmax; dp++)
245
if (dp->ref > 0 && dp->ino == st.st_ino && dp->dev == st.st_dev)
246
{
247
dp->ref++;
248
cp->db = dp;
249
}
250
if (!cp->db)
251
for (dp = state->dbs; dp < state->dbs + state->conmax; dp++)
252
if (dp->ref <= 0)
253
{
254
if (dp->dbm = dbm_open(key.dptr, O_RDWR|O_CREAT, 0666))
255
{
256
cp->db = dp;
257
dp->ref = 1;
258
if (stat(ret, &st))
259
{
260
st.st_dev = 0;
261
st.st_ino = 0;
262
}
263
dp->dev = st.st_dev;
264
dp->ino = st.st_ino;
265
}
266
break;
267
}
268
if (cp->db) n = sfsprintf(ret, sizeof(ret), "I %s opened\n", key.dptr);
269
else n = sfsprintf(ret, sizeof(ret), "E %s cannot open\n", key.dptr);
270
break;
271
case 'p':
272
if (!cp->db) goto notopen;
273
if (cp->readonly)
274
{
275
n = sfsprintf(ret, sizeof(ret), "E db is readonly\n");
276
break;
277
}
278
if (*((char*)val.dptr))
279
{
280
if (!dbm_store(cp->db->dbm, key, val, DBM_REPLACE)) n = sfsprintf(ret, sizeof(ret), "I entered\n");
281
else if (dbm_error(cp->db->dbm))
282
{
283
dbm_clearerr(cp->db->dbm);
284
n = sfsprintf(ret, sizeof(ret), "E db io error\n");
285
}
286
else n = sfsprintf(ret, sizeof(ret), "E %s not changed\n", key.dptr);
287
}
288
else if (!dbm_delete(cp->db->dbm, key)) n = sfsprintf(ret, sizeof(ret), "I deleted\n");
289
else if (dbm_error(cp->db->dbm))
290
{
291
dbm_clearerr(cp->db->dbm);
292
n = sfsprintf(ret, sizeof(ret), "E db io error\n");
293
}
294
else n = sfsprintf(ret, sizeof(ret), "W %s not in db\n", key.dptr);
295
break;
296
case 'q':
297
case 'Q':
298
n = sfsprintf(ret, sizeof(ret), "I quit\n");
299
break;
300
case 's':
301
if (!cp->db) goto notopen;
302
cp->scan = 0;
303
n = sfsprintf(ret, sizeof(ret), "I ready to scan\n");
304
break;
305
case 'v':
306
n = sfsprintf(ret, sizeof(ret), "I %s %s %u\n", id + 10, csname(0L), getpid());
307
break;
308
default:
309
n = sfsprintf(ret, sizeof(ret), "E invalid command %s\n", cmd);
310
break;
311
notopen:
312
n = sfsprintf(ret, sizeof(ret), "E db not open\n");
313
break;
314
}
315
if (cswrite(fd, ret, n) != n || *cmd == 'q') goto drop;
316
if (*cmd == 'Q')
317
{
318
if (state->active == 1) exit(0);
319
goto drop;
320
}
321
}
322
return(0);
323
drop:
324
if (cp->db && !--cp->db->ref) dbm_close(cp->db->dbm);
325
state->active--;
326
return(-1);
327
}
328
329
/*
330
* exit if no open dbm's on timeout
331
*/
332
333
static int
334
svc_timeout(void* handle)
335
{
336
State_t* state = (State_t*)handle;
337
338
if (!state->active)
339
{
340
if (state->dormant)
341
exit(0);
342
state->dormant = 1;
343
}
344
return(0);
345
}
346
347
/*
348
* close the open dbm's
349
*/
350
351
static int
352
svc_done(void* handle, int sig)
353
{
354
register State_t* state = (State_t*)handle;
355
register Db_t* dp;
356
357
NoP(sig);
358
for (dp = state->dbs; dp < state->dbs + state->conmax; dp++)
359
if (dp->ref > 0)
360
{
361
dp->ref = 0;
362
dbm_close(dp->dbm);
363
}
364
return(0);
365
}
366
367
int
368
main(int argc, char** argv)
369
{
370
static State_t state;
371
372
NoP(argc);
373
csserve(&state, argv[1], svc_init, svc_done, svc_connect, svc_read, NiL, svc_timeout);
374
exit(1);
375
}
376
377
#endif
378
379