/[hyperestraier]/upstream/0.5.0/mastermod.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.5.0/mastermod.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Fri Jul 29 21:52:03 2005 UTC (18 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 27224 byte(s)
import of HyperEstraier 0.5.0

1 /*************************************************************************************************
2 * Implementation of mastermod
3 * Copyright (C) 2004-2005 Mikio Hirabayashi
4 * This file is part of Hyper Estraier.
5 * Hyper Estraier is free software; you can redistribute it and/or modify it under the terms of
6 * the GNU Lesser General Public License as published by the Free Software Foundation; either
7 * version 2.1 of the License or any later version. Hyper Estraier is distributed in the hope
8 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10 * License for more details.
11 * You should have received a copy of the GNU Lesser General Public License along with Hyper
12 * Estraier; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13 * Boston, MA 02111-1307 USA.
14 *************************************************************************************************/
15
16
17 #include "mastermod.h"
18
19
20 /* private function prototypes */
21 static void log_close(void);
22 static void db_inform(const char *msg);
23 static int resdoc_compare(const void *ap, const void *bp);
24
25
26
27 /*************************************************************************************************
28 * pseudo API
29 *************************************************************************************************/
30
31
32 /* The handles of the log file. */
33 FILE *log_fp = NULL;
34
35
36 /* Level of logging. */
37 int log_level = LL_INFO;
38
39
40 /* Open the log file. */
41 int log_open(const char *rootdir, int level){
42 char path[URIBUFSIZ];
43 assert(rootdir);
44 log_level = level;
45 if(log_fp) return TRUE;
46 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, LOGFILE);
47 if(!(log_fp = fopen(path, "ab"))) return FALSE;
48 atexit(log_close);
49 return TRUE;
50 }
51
52
53 /* Print formatted string into the log file. */
54 void log_print(int level, const char *format, ...){
55 static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
56 va_list ap;
57 const char *lvstr;
58 char *date;
59 if(level < log_level) return;
60 if(pthread_mutex_lock(&mymutex) != 0) return;
61 va_start(ap, format);
62 switch(level){
63 case LL_DEBUG: lvstr = "DEBUG"; break;
64 case LL_INFO: lvstr = "INFO"; break;
65 case LL_WARN: lvstr = "WARN"; break;
66 default: lvstr = "ERROR"; break;
67 }
68 date = cbdatestrwww(time(NULL), 0);
69 printf("%s\t%s\t", date, lvstr);
70 vprintf(format, ap);
71 putchar('\n');
72 fflush(stdout);
73 if(log_fp){
74 fprintf(log_fp, "%s\t%s\t", date, lvstr);
75 vfprintf(log_fp, format, ap);
76 fputc('\n', log_fp);
77 fflush(log_fp);
78 }
79 free(date);
80 va_end(ap);
81 pthread_mutex_unlock(&mymutex);
82 }
83
84
85 /* Initialize the root directory. */
86 int master_init(const char *rootdir){
87 DEPOT *depot;
88 FILE *ofp;
89 char path[URIBUFSIZ];
90 int err;
91 assert(rootdir);
92 if(est_mkdir(rootdir) == -1 && errno != EEXIST) return FALSE;
93 err = FALSE;
94 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, METAFILE);
95 if((depot = dpopen(path, DP_OWRITER | DP_OCREAT | DP_OTRUNC, MINIBNUM))){
96 if(!dpput(depot, MMKMAGIC, -1, MMKMAGVAL, -1, FALSE)) err = TRUE;
97 if(!dpclose(depot)) err = TRUE;
98 } else {
99 err = TRUE;
100 }
101 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, CONFFILE);
102 if((ofp = fopen(path, "wb")) != NULL){
103 fprintf(ofp, "# fully quarified hostname\n");
104 fprintf(ofp, "hostname: localhost\n");
105 fprintf(ofp, "\n");
106 fprintf(ofp, "# port number of TCP\n");
107 fprintf(ofp, "portnum: 1978\n");
108 fprintf(ofp, "\n");
109 fprintf(ofp, "# running mode (1:normal, 2:readonly)\n");
110 fprintf(ofp, "runmode: 1\n");
111 fprintf(ofp, "\n");
112 fprintf(ofp, "# authorization mode (1:none, 2:admin, 3:all)\n");
113 fprintf(ofp, "authmode: 2\n");
114 fprintf(ofp, "\n");
115 fprintf(ofp, "# maximum number of connections at the same time\n");
116 fprintf(ofp, "maxconn: 30\n");
117 fprintf(ofp, "\n");
118 fprintf(ofp, "# timeout of a session, in seconds\n");
119 fprintf(ofp, "sessiontimeout: 600\n");
120 fprintf(ofp, "\n");
121 fprintf(ofp, "# timeout of search, in seconds\n");
122 fprintf(ofp, "searchtimeout: 8\n");
123 fprintf(ofp, "\n");
124 fprintf(ofp, "# maximum depth of meta search\n");
125 fprintf(ofp, "searchdepth: 5\n");
126 fprintf(ofp, "\n");
127 fprintf(ofp, "# host name of the proxy\n");
128 fprintf(ofp, "proxyhost:\n");
129 fprintf(ofp, "\n");
130 fprintf(ofp, "# port number of the proxy\n");
131 fprintf(ofp, "proxyport:\n");
132 fprintf(ofp, "\n");
133 fprintf(ofp, "# logging level (1:debug, 2:information, 3:warning, 4:error, 5:none)\n");
134 fprintf(ofp, "loglevel: 2\n");
135 fprintf(ofp, "\n");
136 fprintf(ofp, "# document root directory (full path of a directory to be public)\n");
137 fprintf(ofp, "docroot:\n");
138 fprintf(ofp, "\n");
139 fprintf(ofp, "# index file (name of directory index files)\n");
140 fprintf(ofp, "indexfile:\n");
141 fprintf(ofp, "\n");
142 fprintf(ofp, "# decimal IP addresses of trusted nodes (list separated by comma)\n");
143 fprintf(ofp, "trustednodes:\n");
144 fprintf(ofp, "\n");
145 fprintf(ofp, "# whether to deny all nodes except for trusted nodes (0:no, 1:yes)\n");
146 fprintf(ofp, "denyuntrusted: 0\n");
147 fprintf(ofp, "\n");
148 fprintf(ofp, "# name of the attribute of special cache\n");
149 fprintf(ofp, "specialcache:\n");
150 fprintf(ofp, "\n");
151 fprintf(ofp, "# whole width of the snippet of each shown document\n");
152 fprintf(ofp, "snipwwidth: 480\n");
153 fprintf(ofp, "\n");
154 fprintf(ofp, "# width of strings picked up from the beginning of the text\n");
155 fprintf(ofp, "sniphwidth: 96\n");
156 fprintf(ofp, "\n");
157 fprintf(ofp, "# width of strings picked up around each highlighted word\n");
158 fprintf(ofp, "snipawidth: 96\n");
159 if(fclose(ofp) == EOF) err = TRUE;
160 } else {
161 err = TRUE;
162 }
163 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, PIDFILE);
164 unlink(path);
165 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, STOPFILE);
166 unlink(path);
167 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, USERFILE);
168 if((ofp = fopen(path, "wb")) != NULL){
169 if(fclose(ofp) == EOF) err = TRUE;
170 } else {
171 err = TRUE;
172 }
173 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, LOGFILE);
174 if((ofp = fopen(path, "wb")) != NULL){
175 if(fclose(ofp) == EOF) err = TRUE;
176 } else {
177 err = TRUE;
178 }
179 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, NODEDIR);
180 est_rmdir_rec(path);
181 if(est_mkdir(path) == -1) err = TRUE;
182 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, SESSDIR);
183 est_rmdir_rec(path);
184 if(est_mkdir(path) == -1) err = TRUE;
185 return err ? FALSE : TRUE;
186 }
187
188
189 /* Get the PID of the process locking the root directory. */
190 int lockerpid(const char *rootdir){
191 char path[URIBUFSIZ], *vbuf;
192 int pid;
193 pid = -1;
194 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, PIDFILE);
195 if((vbuf = cbreadfile(path, NULL)) != NULL){
196 pid = atoi(vbuf);
197 free(vbuf);
198 }
199 return pid;
200 }
201
202
203 /* Check whether a name includes alpha numeric characters only. */
204 int check_alnum_name(const char *name){
205 while(*name != '\0'){
206 if(!(*name >= 'a' && *name <= 'z') && !(*name >= '0' && *name <= '9') &&
207 *name != '-' && *name != '_'){
208 return FALSE;
209 }
210 name++;
211 }
212 return TRUE;
213 }
214
215
216 /* Create a user manager object. */
217 UMGR *umgr_new(const char *rootdir){
218 UMGR *umgr;
219 assert(rootdir);
220 log_print(LL_INFO, "starting the user manager");
221 umgr = cbmalloc(sizeof(UMGR));
222 umgr->rootdir = cbmemdup(rootdir, -1);
223 umgr->users = cbmapopen();
224 return umgr;
225 }
226
227
228 /* Destroy a user manager object. */
229 int umgr_delete(UMGR *umgr){
230 USER *user;
231 const char *kbuf, *vbuf;
232 int err, ksiz;
233 assert(umgr);
234 log_print(LL_INFO, "finishing the user manager");
235 err = FALSE;
236 if(!umgr_sync(umgr)) err = TRUE;
237 cbmapiterinit(umgr->users);
238 while((kbuf = cbmapiternext(umgr->users, &ksiz)) != NULL){
239 vbuf = cbmapget(umgr->users, kbuf, ksiz, NULL);
240 user = (USER *)vbuf;
241 pthread_mutex_destroy(&(user->mutex));
242 if(user->sess) cbmapclose(user->sess);
243 free(user->misc);
244 free(user->fname);
245 free(user->flags);
246 free(user->passwd);
247 free(user->name);
248 }
249 cbmapclose(umgr->users);
250 free(umgr->rootdir);
251 free(umgr);
252 return err ? FALSE : TRUE;
253 }
254
255
256 /* Load all users from the user file. */
257 int umgr_load(UMGR *umgr){
258 CBLIST *lines, *elems;
259 const char *line;
260 char path[URIBUFSIZ];
261 int i, size;
262 assert(umgr);
263 log_print(LL_INFO, "loading the user list");
264 sprintf(path, "%s%c%s", umgr->rootdir, ESTPATHCHR, USERFILE);
265 if(!(lines = cbreadlines(path))){
266 log_print(LL_ERROR, "loading the user list failed");
267 return FALSE;
268 }
269 for(i = 0; i < cblistnum(lines); i++){
270 line = cblistval(lines, i, &size);
271 if(size < 1) continue;
272 elems = cbsplit(line, size, "\t");
273 if(cblistnum(elems) >= 5){
274 umgr_put(umgr, cblistval(elems, 0, NULL), cblistval(elems, 1, NULL),
275 cblistval(elems, 2, NULL), cblistval(elems, 3, NULL), cblistval(elems, 4, NULL));
276 } else {
277 log_print(LL_WARN, "invalid line: %d", i + 1);
278 }
279 cblistclose(elems);
280 }
281 cblistclose(lines);
282 return TRUE;
283 }
284
285
286 /* Synchronize all users into the user file. */
287 int umgr_sync(UMGR *umgr){
288 FILE *ofp;
289 USER *user;
290 const char *kbuf, *vbuf;
291 char path[URIBUFSIZ];
292 int err, ksiz;
293 assert(umgr);
294 log_print(LL_INFO, "saving the user list");
295 sprintf(path, "%s%c%s", umgr->rootdir, ESTPATHCHR, USERFILE);
296 if(!(ofp = fopen(path, "wb"))){
297 log_print(LL_ERROR, "synchronizing the user list failed");
298 return FALSE;
299 }
300 err = FALSE;
301 cbmapiterinit(umgr->users);
302 while((kbuf = cbmapiternext(umgr->users, &ksiz)) != NULL){
303 vbuf = cbmapget(umgr->users, kbuf, ksiz, NULL);
304 user = (USER *)vbuf;
305 fprintf(ofp, "%s\t%s\t%s\t%s\t%s\n",
306 user->name, user->passwd, user->flags, user->fname, user->misc);
307 }
308 if(fclose(ofp) == EOF){
309 log_print(LL_ERROR, "saving the user list failed");
310 err = TRUE;
311 }
312 return err ? FALSE : TRUE;
313 }
314
315
316 /* Add a user to a user manager object. */
317 int umgr_put(UMGR *umgr, const char *name, const char *passwd, const char *flags,
318 const char *fname, const char *misc){
319 USER user;
320 assert(umgr && name && passwd && flags && fname && misc);
321 log_print(LL_DEBUG, "umgr_put: %s:%s:%s:%s:%s", name, passwd, flags, fname, misc);
322 if(name[0] == '\0' || cbmapget(umgr->users, name, -1, NULL)){
323 log_print(LL_WARN, "duplicated or empty user name: %s", name);
324 return FALSE;
325 }
326 if(!check_alnum_name(name)){
327 log_print(LL_WARN, "invalid user name: %s", name);
328 return FALSE;
329 }
330 user.name = cbmemdup(name, -1);
331 user.passwd = cbmemdup(passwd, -1);
332 user.flags = cbmemdup(flags, -1);
333 user.fname = cbmemdup(fname, -1);
334 user.misc = cbmemdup(misc, -1);
335 user.atime = 0;
336 user.sess = NULL;
337 pthread_mutex_init(&(user.mutex), NULL);
338 cbmapput(umgr->users, name, -1, (char *)&user, sizeof(USER), FALSE);
339 return TRUE;
340 }
341
342
343 /* Remove a user from a user manager object. */
344 int umgr_out(UMGR *umgr, const char *name){
345 USER *user;
346 const char *vbuf;
347 assert(umgr && name);
348 log_print(LL_DEBUG, "umgr_out: %s", name);
349 if(!(vbuf = cbmapget(umgr->users, name, -1, NULL))) return FALSE;
350 user = (USER *)vbuf;
351 pthread_mutex_destroy(&(user->mutex));
352 if(user->sess) cbmapclose(user->sess);
353 free(user->misc);
354 free(user->fname);
355 free(user->flags);
356 free(user->passwd);
357 free(user->name);
358 cbmapout(umgr->users, name, -1);
359 return TRUE;
360 }
361
362
363 /* Get a list of names of users in a user manager object. */
364 CBLIST *umgr_names(UMGR *umgr){
365 CBLIST *names;
366 assert(umgr);
367 names = cbmapkeys(umgr->users);
368 cblistsort(names);
369 return names;
370 }
371
372
373 /* Get a user object in a user manager object. */
374 USER *umgr_get(UMGR *umgr, const char *name){
375 const char *vbuf;
376 assert(umgr && name);
377 if(!(vbuf = cbmapget(umgr->users, name, -1, NULL))) return NULL;
378 return (USER *)vbuf;
379 }
380
381
382 /* Make the session of a user object. */
383 void user_make_sess(USER *user){
384 assert(user);
385 if(pthread_mutex_lock(&(user->mutex)) != 0) return;
386 if(user->sess) cbmapclose(user->sess);
387 user->sess = cbmapopenex(MINIBNUM);
388 pthread_mutex_unlock(&(user->mutex));
389 }
390
391
392 /* Clear the session of a user object. */
393 void user_clear_sess(USER *user){
394 assert(user);
395 if(pthread_mutex_lock(&(user->mutex)) != 0) return;
396 if(user->sess) cbmapclose(user->sess);
397 user->sess = NULL;
398 pthread_mutex_unlock(&(user->mutex));
399 }
400
401
402 /* Set a session variable of a user object. */
403 void user_set_sess_val(USER *user, const char *name, const char *value){
404 assert(user && name);
405 if(pthread_mutex_lock(&(user->mutex)) != 0) return;
406 if(user->sess){
407 if(value){
408 cbmapput(user->sess, name, -1, value, -1, TRUE);
409 } else {
410 cbmapout(user->sess, name, -1);
411 }
412 }
413 pthread_mutex_unlock(&(user->mutex));
414 }
415
416
417 /* Get the value of a session variable of a user object. */
418 char *user_sess_val(USER *user, const char *name){
419 const char *value;
420 char *rv;
421 assert(user && name);
422 if(pthread_mutex_lock(&(user->mutex)) != 0) return NULL;
423 value = user->sess ? cbmapget(user->sess, name, -1, NULL) : NULL;
424 rv = value ? cbmemdup(value, -1) : NULL;
425 pthread_mutex_unlock(&(user->mutex));
426 return rv;
427 }
428
429
430 /* Create a node manager object. */
431 NMGR *nmgr_new(const char *rootdir){
432 NMGR *nmgr;
433 assert(rootdir);
434 log_print(LL_INFO, "starting the node manager");
435 nmgr = cbmalloc(sizeof(NMGR));
436 nmgr->rootdir = cbmemdup(rootdir, -1);
437 nmgr->nodes = cbmapopen();
438 return nmgr;
439 }
440
441
442 /* Destroy a user manager object. */
443 int nmgr_delete(NMGR *nmgr){
444 NODE *node;
445 const char *kbuf, *vbuf;
446 int err, ksiz, ecode;
447 assert(nmgr);
448 log_print(LL_INFO, "finishing the node manager");
449 err = FALSE;
450 if(!nmgr_sync(nmgr, FALSE)) err = TRUE;
451 cbmapiterinit(nmgr->nodes);
452 while((kbuf = cbmapiternext(nmgr->nodes, &ksiz)) != NULL){
453 vbuf = cbmapget(nmgr->nodes, kbuf, ksiz, NULL);
454 node = (NODE *)vbuf;
455 pthread_mutex_destroy(&(node->mutex));
456 cbmapclose(node->links);
457 cbmapclose(node->users);
458 cbmapclose(node->admins);
459 free(node->label);
460 free(node->name);
461 est_mtdb_close(node->db, &ecode);
462 }
463 cbmapclose(nmgr->nodes);
464 free(nmgr->rootdir);
465 free(nmgr);
466 return err ? FALSE : TRUE;
467 }
468
469
470 /* Load all nodes from the node directory. */
471 int nmgr_load(NMGR *nmgr, int wmode){
472 CBLIST *list;
473 const char *file;
474 char path[URIBUFSIZ];
475 int i, err;
476 assert(nmgr);
477 sprintf(path, "%s%c%s", nmgr->rootdir, ESTPATHCHR, NODEDIR);
478 if(!(list = cbdirlist(path))){
479 log_print(LL_ERROR, "loading the node directory failed");
480 return FALSE;
481 }
482 err = FALSE;
483 for(i = 0; i < cblistnum(list); i++){
484 file = cblistval(list, i, NULL);
485 if(!strcmp(file, ESTCDIRSTR) || !strcmp(file, ESTPDIRSTR)) continue;
486 if(!nmgr_put(nmgr, file, wmode)) err = TRUE;
487 }
488 cblistclose(list);
489 return err ? FALSE : TRUE;
490 }
491
492
493 /* Synchronize all nodes into the node directory. */
494 int nmgr_sync(NMGR *nmgr, int phis){
495 NODE *node;
496 CBDATUM *datum;
497 const char *kbuf, *vbuf;
498 int err, ksiz, vsiz;
499 assert(nmgr);
500 log_print(LL_INFO, "synchronizing the node manager");
501 err = FALSE;
502 cbmapiterinit(nmgr->nodes);
503 while((kbuf = cbmapiternext(nmgr->nodes, &ksiz)) != NULL){
504 vbuf = cbmapget(nmgr->nodes, kbuf, ksiz, NULL);
505 node = (NODE *)vbuf;
506 est_mtdb_add_meta(node->db, NMKNAME, node->name);
507 est_mtdb_add_meta(node->db, NMKLABEL, node->label);
508 datum = cbdatumopen("", 0);
509 cbmapiterinit(node->admins);
510 while((kbuf = cbmapiternext(node->admins, &ksiz)) != NULL){
511 cbdatumcat(datum, kbuf, ksiz);
512 cbdatumcat(datum, "\n", 1);
513 }
514 est_mtdb_add_meta(node->db, NMKADMINS, cbdatumptr(datum));
515 cbdatumclose(datum);
516 datum = cbdatumopen("", 0);
517 cbmapiterinit(node->users);
518 while((kbuf = cbmapiternext(node->users, &ksiz)) != NULL){
519 cbdatumcat(datum, kbuf, ksiz);
520 cbdatumcat(datum, "\n", 1);
521 }
522 est_mtdb_add_meta(node->db, NMKUSERS, cbdatumptr(datum));
523 cbdatumclose(datum);
524 datum = cbdatumopen("", 0);
525 cbmapiterinit(node->links);
526 while((kbuf = cbmapiternext(node->links, &ksiz)) != NULL){
527 vbuf = cbmapget(node->links, kbuf, ksiz, &vsiz);
528 cbdatumcat(datum, kbuf, ksiz);
529 cbdatumcat(datum, "\t", 1);
530 cbdatumcat(datum, vbuf, vsiz);
531 cbdatumcat(datum, "\n", 1);
532 }
533 est_mtdb_add_meta(node->db, NMKLINKS, cbdatumptr(datum));
534 cbdatumclose(datum);
535 if(phis && !est_mtdb_sync(node->db)){
536 log_print(LL_ERROR, "DB-ERROR: %s", est_err_msg(est_mtdb_error(node->db)));
537 err = TRUE;
538 }
539 }
540 return err ? FALSE : TRUE;
541 }
542
543
544 /* Add a node to a node manager object. */
545 int nmgr_put(NMGR *nmgr, const char *name, int wmode){
546 NODE node;
547 ESTMTDB *db;
548 CBLIST *list;
549 const char *cbuf, *pv;
550 char pbuf[URIBUFSIZ], *vbuf;
551 int i, ecode, csiz;
552 assert(nmgr && name);
553 log_print(LL_DEBUG, "nmgr_put: %s", name);
554 if(name[0] == '\0' || cbmapget(nmgr->nodes, name, -1, NULL)){
555 log_print(LL_WARN, "duplicated or empty node name: %s", name);
556 return FALSE;
557 }
558 if(strlen(name) >= NODENAMEMAX || !check_alnum_name(name)){
559 log_print(LL_WARN, "invalid node name: %s", name);
560 return FALSE;
561 }
562 log_print(LL_INFO, "opening the node (%s): %s", wmode ? "WRITER" : "READER", name);
563 sprintf(pbuf, "%s%c%s%c%s", nmgr->rootdir, ESTPATHCHR, NODEDIR, ESTPATHCHR, name);
564 if(!(db = est_mtdb_open(pbuf, wmode ? ESTDBWRITER | ESTDBCREAT : ESTDBREADER, &ecode))){
565 log_print(LL_ERROR, "DB-ERROR: %s", est_err_msg(ecode));
566 return FALSE;
567 }
568 est_mtdb_set_informer(db, db_inform);
569 node.db = db;
570 est_mtdb_add_meta(db, NMKNAME, name);
571 node.name = cbmemdup(name, -1);
572 vbuf = est_mtdb_meta(db, NMKLABEL);
573 node.label = vbuf ? vbuf : cbmemdup(name, -1);
574 if((vbuf = est_mtdb_meta(db, NMKADMINS)) != NULL){
575 list = cbsplit(vbuf, -1, "\n");
576 node.admins = cbmapopenex(cblistnum(list) + MINIBNUM);
577 for(i = 0; i < cblistnum(list); i++){
578 cbuf = cblistval(list, i, &csiz);
579 if(csiz < 1) continue;
580 cbmapput(node.admins, cbuf, csiz, "", 0, FALSE);
581 }
582 cblistclose(list);
583 free(vbuf);
584 } else {
585 node.admins = cbmapopenex(MINIBNUM);
586 }
587 if((vbuf = est_mtdb_meta(db, NMKUSERS)) != NULL){
588 list = cbsplit(vbuf, -1, "\n");
589 node.users = cbmapopenex(cblistnum(list) + MINIBNUM);
590 for(i = 0; i < cblistnum(list); i++){
591 cbuf = cblistval(list, i, &csiz);
592 if(csiz < 1) continue;
593 cbmapput(node.users, cbuf, csiz, "", 0, FALSE);
594 }
595 cblistclose(list);
596 free(vbuf);
597 } else {
598 node.users = cbmapopenex(MINIBNUM);
599 }
600 if((vbuf = est_mtdb_meta(db, NMKLINKS)) != NULL){
601 list = cbsplit(vbuf, -1, "\n");
602 node.links = cbmapopenex(cblistnum(list) + MINIBNUM);
603 for(i = 0; i < cblistnum(list); i++){
604 cbuf = cblistval(list, i, NULL);
605 if(!(pv = strchr(cbuf, '\t'))) continue;
606 cbmapput(node.links, cbuf, pv - cbuf, pv + 1, -1, FALSE);
607 }
608 cblistclose(list);
609 free(vbuf);
610 } else {
611 node.links = cbmapopenex(MINIBNUM);
612 }
613 pthread_mutex_init(&(node.mutex), NULL);
614 cbmapput(nmgr->nodes, name, -1, (char *)&node, sizeof(NODE), FALSE);
615 return TRUE;
616 }
617
618
619 /* Remove a node from a node manager object. */
620 int nmgr_out(NMGR *nmgr, const char *name){
621 NODE *node;
622 const char *vbuf;
623 char pbuf[URIBUFSIZ];
624 int err, ecode;
625 assert(nmgr && name);
626 log_print(LL_DEBUG, "nmgr_out: %s", name);
627 if(!(vbuf = cbmapget(nmgr->nodes, name, -1, NULL))) return FALSE;
628 err = FALSE;
629 node = (NODE *)vbuf;
630 pthread_mutex_destroy(&(node->mutex));
631 cbmapclose(node->links);
632 cbmapclose(node->users);
633 cbmapclose(node->admins);
634 free(node->label);
635 free(node->name);
636 if(!(est_mtdb_close(node->db, &ecode))){
637 log_print(LL_ERROR, "DB-ERROR: %s", est_err_msg(ecode));
638 err = TRUE;
639 }
640 sprintf(pbuf, "%s%c%s%c%s", nmgr->rootdir, ESTPATHCHR, NODEDIR, ESTPATHCHR, name);
641 if(!est_rmdir_rec(pbuf)){
642 log_print(LL_ERROR, "could not remove a directory");
643 err = TRUE;
644 }
645 cbmapout(nmgr->nodes, name, -1);
646 return TRUE;
647 }
648
649
650 /* Get a list of names of nodes in a noder manager object. */
651 CBLIST *nmgr_names(NMGR *nmgr){
652 CBLIST *names;
653 assert(nmgr);
654 names = cbmapkeys(nmgr->nodes);
655 cblistsort(names);
656 return names;
657 }
658
659
660 /* Get a node object in a node manager object. */
661 NODE *nmgr_get(NMGR *nmgr, const char *name){
662 const char *vbuf;
663 assert(nmgr && name);
664 if(!(vbuf = cbmapget(nmgr->nodes, name, -1, NULL))) return NULL;
665 return (NODE *)vbuf;
666 }
667
668
669 /* Set a link object of a node. */
670 void node_set_link(NODE *node, const char *url, const char *label, int credit){
671 char *vbuf;
672 assert(node && url);
673 if(!label || credit < 0){
674 cbmapout(node->links, url, -1);
675 return;
676 }
677 vbuf = cbsprintf("%s\t%d", label, credit);
678 cbmapput(node->links, url, -1, vbuf, -1, TRUE);
679 free(vbuf);
680 }
681
682
683 /* Create a read-write lock object. */
684 RWLOCK *rwlock_new(void){
685 RWLOCK *rwlock;
686 rwlock = cbmalloc(sizeof(RWLOCK));
687 rwlock->readers = 0;
688 rwlock->writers = 0;
689 pthread_mutex_init(&(rwlock->mutex), NULL);
690 pthread_cond_init(&(rwlock->cond), NULL);
691 return rwlock;
692 }
693
694
695 /* Destroy a read-write lock object. */
696 void rwlock_delete(RWLOCK *rwlock){
697 assert(rwlock);
698 pthread_cond_destroy(&(rwlock->cond));
699 pthread_mutex_destroy(&(rwlock->mutex));
700 free(rwlock);
701 }
702
703
704 /* Lock a read-write lock object. */
705 int rwlock_lock(RWLOCK *rwlock, int wmode){
706 assert(rwlock);
707 if(pthread_mutex_lock(&(rwlock->mutex)) != 0) return FALSE;
708 if(wmode){
709 while(rwlock->writers > 0 || rwlock->readers > 0){
710 pthread_cond_wait(&(rwlock->cond), &(rwlock->mutex));
711 }
712 rwlock->writers++;
713 } else {
714 while(rwlock->writers > 0){
715 pthread_cond_wait(&(rwlock->cond), &(rwlock->mutex));
716 }
717 rwlock->readers++;
718 }
719 pthread_mutex_unlock(&(rwlock->mutex));
720 return TRUE;
721 }
722
723
724 /* Unlock a read-write lock object. */
725 int rwlock_unlock(RWLOCK *rwlock){
726 assert(rwlock);
727 if(pthread_mutex_lock(&(rwlock->mutex)) != 0) return FALSE;
728 if(rwlock->writers > 0){
729 rwlock->writers--;
730 pthread_cond_broadcast(&(rwlock->cond));
731 pthread_mutex_unlock(&(rwlock->mutex));
732 } else {
733 rwlock->readers--;
734 if(rwlock->readers < 1) pthread_cond_signal(&(rwlock->cond));
735 pthread_mutex_unlock(&(rwlock->mutex));
736 }
737 return TRUE;
738 }
739
740
741 /* Get the number of readers locking a read-write lock object. */
742 int rwlock_rnum(RWLOCK *rwlock){
743 assert(rwlock);
744 return rwlock->readers;
745 }
746
747
748 /* Create a result map object. */
749 RESMAP *resmap_new(void){
750 RESMAP *resmap;
751 resmap = cbmalloc(sizeof(RESMAP));
752 resmap->uris = cbmapopen();
753 pthread_mutex_init(&(resmap->mutex), NULL);
754 return resmap;
755 }
756
757
758 /* Destroy a result map object. */
759 void resmap_delete(RESMAP *resmap){
760 RESDOC *resdoc;
761 const char *kbuf, *vbuf;
762 int ksiz;
763 assert(resmap);
764 cbmapiterinit(resmap->uris);
765 while((kbuf = cbmapiternext(resmap->uris, &ksiz)) != NULL){
766 vbuf = cbmapget(resmap->uris, kbuf, ksiz, NULL);
767 resdoc = (RESDOC *)vbuf;
768 if(resdoc->doc) est_doc_delete(resdoc->doc);
769 if(resdoc->attrs) cbmapclose(resdoc->attrs);
770 if(resdoc->body) free(resdoc->body);
771 }
772 pthread_mutex_destroy(&(resmap->mutex));
773 cbmapclose(resmap->uris);
774 free(resmap);
775 }
776
777
778 /* Add a result document data to a result map object. */
779 void resmap_put(RESMAP *resmap, int score, ESTDOC *doc, CBMAP *attrs, char *body){
780 RESDOC resdoc;
781 const char *uri, *vbuf;
782 assert(resmap);
783 uri = NULL;
784 if(doc) uri = est_doc_attr(doc, ESTDATTRURI);
785 if(attrs) uri = cbmapget(attrs, ESTDATTRURI, -1, NULL);
786 if(!uri || pthread_mutex_lock(&(resmap->mutex)) != 0){
787 if(doc) est_doc_delete(doc);
788 if(attrs) cbmapclose(attrs);
789 if(body) free(body);
790 return;
791 }
792 if((vbuf = cbmapget(resmap->uris, uri, -1, NULL)) != NULL){
793 if(((RESDOC *)vbuf)->score >= score){
794 if(doc) est_doc_delete(doc);
795 if(attrs) cbmapclose(attrs);
796 if(body) free(body);
797 } else {
798 if(((RESDOC *)vbuf)->doc) est_doc_delete(((RESDOC *)vbuf)->doc);
799 if(((RESDOC *)vbuf)->attrs) cbmapclose(((RESDOC *)vbuf)->attrs);
800 if(((RESDOC *)vbuf)->body) free(((RESDOC *)vbuf)->body);
801 resdoc.score = score;
802 resdoc.doc = doc;
803 resdoc.attrs = attrs;
804 resdoc.body = body;
805 cbmapput(resmap->uris, uri, -1, (char *)&resdoc, sizeof(RESDOC), TRUE);
806 }
807 } else {
808 resdoc.score = score;
809 resdoc.doc = doc;
810 resdoc.attrs = attrs;
811 resdoc.body = body;
812 cbmapput(resmap->uris, uri, -1, (char *)&resdoc, sizeof(RESDOC), FALSE);
813 }
814 pthread_mutex_unlock(&(resmap->mutex));
815 }
816
817
818 /* Get a list object of result objects in a result map objects. */
819 RESDOC **resmap_list(RESMAP *resmap, int *nump){
820 RESDOC **resdocs;
821 const char *kbuf, *vbuf;
822 int i, ksiz;
823 assert(resmap && nump);
824 if(pthread_mutex_lock(&(resmap->mutex)) != 0){
825 *nump = 0;
826 return cbmalloc(1);
827 }
828 *nump = cbmaprnum(resmap->uris);
829 resdocs = cbmalloc(*nump * sizeof(RESDOC) + 1);
830 cbmapiterinit(resmap->uris);
831 for(i = 0; i < *nump; i++){
832 kbuf = cbmapiternext(resmap->uris, &ksiz);
833 vbuf = cbmapget(resmap->uris, kbuf, ksiz, NULL);
834 resdocs[i] = (RESDOC *)vbuf;
835 }
836 qsort(resdocs, *nump, sizeof(RESDOC *), resdoc_compare);
837 pthread_mutex_unlock(&(resmap->mutex));
838 return resdocs;
839 }
840
841
842 /* Be a daemon process. */
843 int be_daemon(const char *curdir){
844 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
845 PROCESS_INFORMATION pi;
846 STARTUPINFO si;
847 assert(curdir);
848 FreeConsole();
849 if(getenv("ESTDAEMON")){
850 Sleep(1000);
851 if(chdir(curdir) == -1) return FALSE;
852 } else {
853 putenv("ESTDAEMON=1");
854 memset(&si, 0, sizeof(STARTUPINFO));
855 si.cb = sizeof(si);
856 if(!CreateProcess(NULL, GetCommandLine(), NULL, NULL, FALSE,
857 BELOW_NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP |
858 CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL, &si, &pi))
859 return FALSE;
860 CloseHandle(pi.hProcess);
861 exit(0);
862 }
863 return TRUE;
864 #else
865 int fd;
866 assert(curdir);
867 switch(fork()){
868 case -1:
869 return FALSE;
870 case 0:
871 break;
872 default:
873 exit(1);
874 }
875 if(setsid() == -1) return FALSE;
876 switch(fork()){
877 case -1:
878 return FALSE;
879 case 0:
880 break;
881 default:
882 exit(1);
883 }
884 umask(0);
885 if(chdir(curdir) == -1) return FALSE;
886 close(0);
887 close(1);
888 close(2);
889 if((fd = open(NULLDEV, O_RDWR, 0)) != -1){
890 dup2(fd, 0);
891 dup2(fd, 1);
892 dup2(fd, 2);
893 if(fd > 2) close(fd);
894 }
895 nice(5);
896 return TRUE;
897 #endif
898 }
899
900
901
902 /*************************************************************************************************
903 * private objects
904 *************************************************************************************************/
905
906
907 /* Close the log file. */
908 static void log_close(void){
909 if(log_fp) fclose(log_fp);
910 }
911
912
913 /* Output the log message of a DB event.
914 `msg' specifies the log message of a DB event. */
915 static void db_inform(const char *msg){
916 assert(msg);
917 log_print(LL_INFO, "DB-EVENT: %s", msg);
918 }
919
920
921 /* Compare two result document objects by score.
922 `ap' specifies the pointer to one object.
923 `ap' specifies the pointer to the other object.
924 The return value is negative if one is small, positive if one is big, 0 if both are equal. */
925 static int resdoc_compare(const void *ap, const void *bp){
926 assert(ap && bp);
927 return (*(RESDOC **)bp)->score - (*(RESDOC **)ap)->score;
928 }
929
930
931
932 /* END OF FILE */

  ViewVC Help
Powered by ViewVC 1.1.26