/[hyperestraier]/upstream/0.5.2/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.2/mastermod.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show annotations)
Wed Aug 3 15:21:15 2005 UTC (18 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 28475 byte(s)
import upstream version 0.5.2

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\n");
143 fprintf(ofp, "trustednode:\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, "# maximum size of the index cache (in mega bytes)\n");
149 fprintf(ofp, "cachesize: 64\n");
150 fprintf(ofp, "\n");
151 fprintf(ofp, "# name of the attribute of the special cache\n");
152 fprintf(ofp, "specialcache:\n");
153 fprintf(ofp, "\n");
154 fprintf(ofp, "# whole width of the snippet of each shown document\n");
155 fprintf(ofp, "snipwwidth: 480\n");
156 fprintf(ofp, "\n");
157 fprintf(ofp, "# width of strings picked up from the beginning of the text\n");
158 fprintf(ofp, "sniphwidth: 96\n");
159 fprintf(ofp, "\n");
160 fprintf(ofp, "# width of strings picked up around each highlighted word\n");
161 fprintf(ofp, "snipawidth: 96\n");
162 fprintf(ofp, "\n");
163 fprintf(ofp, "# prefix of the local URI of each document\n");
164 fprintf(ofp, "uilprefix: file:///home/mikio/public_html/\n");
165 fprintf(ofp, "\n");
166 fprintf(ofp, "# prefix of the global URI of each document\n");
167 fprintf(ofp, "uigprefix: http://localhost/\n");
168 fprintf(ofp, "\n");
169 fprintf(ofp, "# suffix added to the global URI of each document\n");
170 fprintf(ofp, "uigsuffix:\n");
171 fprintf(ofp, "\n");
172 fprintf(ofp, "# name of the directory index file\n");
173 fprintf(ofp, "uidirindex: index.html\n");
174 fprintf(ofp, "\n");
175 fprintf(ofp, "# expressions to replace the URI of each document\n");
176 fprintf(ofp, "uireplace: //localhost/{{!}}//127.0.0.1/\n");
177 fprintf(ofp, "uireplace: //127.0.0.1:80/{{!}}//127.0.0.1/\n");
178 fprintf(ofp, "\n");
179 fprintf(ofp, "# extra attributes to be shown\n");
180 fprintf(ofp, "uiextattr: @author|Author\n");
181 fprintf(ofp, "uiextattr: @mdate|Modification Date\n");
182 fprintf(ofp, "\n");
183 fprintf(ofp, "# whether to use simplefied search phrase (0:no, 1:yes)\n");
184 fprintf(ofp, "uismplphrase: 1\n");
185 fprintf(ofp, "\n");
186 if(fclose(ofp) == EOF) err = TRUE;
187 } else {
188 err = TRUE;
189 }
190 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, PIDFILE);
191 unlink(path);
192 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, STOPFILE);
193 unlink(path);
194 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, USERFILE);
195 if((ofp = fopen(path, "wb")) != NULL){
196 if(fclose(ofp) == EOF) err = TRUE;
197 } else {
198 err = TRUE;
199 }
200 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, LOGFILE);
201 if((ofp = fopen(path, "wb")) != NULL){
202 if(fclose(ofp) == EOF) err = TRUE;
203 } else {
204 err = TRUE;
205 }
206 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, NODEDIR);
207 est_rmdir_rec(path);
208 if(est_mkdir(path) == -1) err = TRUE;
209 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, SESSDIR);
210 est_rmdir_rec(path);
211 if(est_mkdir(path) == -1) err = TRUE;
212 return err ? FALSE : TRUE;
213 }
214
215
216 /* Get the PID of the process locking the root directory. */
217 int lockerpid(const char *rootdir){
218 char path[URIBUFSIZ], *vbuf;
219 int pid;
220 pid = -1;
221 sprintf(path, "%s%c%s", rootdir, ESTPATHCHR, PIDFILE);
222 if((vbuf = cbreadfile(path, NULL)) != NULL){
223 pid = atoi(vbuf);
224 free(vbuf);
225 }
226 return pid;
227 }
228
229
230 /* Check whether a name includes alpha numeric characters only. */
231 int check_alnum_name(const char *name){
232 while(*name != '\0'){
233 if(!(*name >= 'a' && *name <= 'z') && !(*name >= '0' && *name <= '9') &&
234 *name != '-' && *name != '_'){
235 return FALSE;
236 }
237 name++;
238 }
239 return TRUE;
240 }
241
242
243 /* Create a user manager object. */
244 UMGR *umgr_new(const char *rootdir){
245 UMGR *umgr;
246 assert(rootdir);
247 log_print(LL_INFO, "starting the user manager");
248 umgr = cbmalloc(sizeof(UMGR));
249 umgr->rootdir = cbmemdup(rootdir, -1);
250 umgr->users = cbmapopen();
251 return umgr;
252 }
253
254
255 /* Destroy a user manager object. */
256 int umgr_delete(UMGR *umgr){
257 USER *user;
258 const char *kbuf, *vbuf;
259 int err, ksiz;
260 assert(umgr);
261 log_print(LL_INFO, "finishing the user manager");
262 err = FALSE;
263 if(!umgr_sync(umgr)) err = TRUE;
264 cbmapiterinit(umgr->users);
265 while((kbuf = cbmapiternext(umgr->users, &ksiz)) != NULL){
266 vbuf = cbmapget(umgr->users, kbuf, ksiz, NULL);
267 user = (USER *)vbuf;
268 pthread_mutex_destroy(&(user->mutex));
269 if(user->sess) cbmapclose(user->sess);
270 free(user->misc);
271 free(user->fname);
272 free(user->flags);
273 free(user->passwd);
274 free(user->name);
275 }
276 cbmapclose(umgr->users);
277 free(umgr->rootdir);
278 free(umgr);
279 return err ? FALSE : TRUE;
280 }
281
282
283 /* Load all users from the user file. */
284 int umgr_load(UMGR *umgr){
285 CBLIST *lines, *elems;
286 const char *line;
287 char path[URIBUFSIZ];
288 int i, size;
289 assert(umgr);
290 log_print(LL_INFO, "loading the user list");
291 sprintf(path, "%s%c%s", umgr->rootdir, ESTPATHCHR, USERFILE);
292 if(!(lines = cbreadlines(path))){
293 log_print(LL_ERROR, "loading the user list failed");
294 return FALSE;
295 }
296 for(i = 0; i < cblistnum(lines); i++){
297 line = cblistval(lines, i, &size);
298 if(size < 1) continue;
299 elems = cbsplit(line, size, "\t");
300 if(cblistnum(elems) >= 5){
301 umgr_put(umgr, cblistval(elems, 0, NULL), cblistval(elems, 1, NULL),
302 cblistval(elems, 2, NULL), cblistval(elems, 3, NULL), cblistval(elems, 4, NULL));
303 } else {
304 log_print(LL_WARN, "invalid line: %d", i + 1);
305 }
306 cblistclose(elems);
307 }
308 cblistclose(lines);
309 return TRUE;
310 }
311
312
313 /* Synchronize all users into the user file. */
314 int umgr_sync(UMGR *umgr){
315 FILE *ofp;
316 USER *user;
317 const char *kbuf, *vbuf;
318 char path[URIBUFSIZ];
319 int err, ksiz;
320 assert(umgr);
321 log_print(LL_INFO, "saving the user list");
322 sprintf(path, "%s%c%s", umgr->rootdir, ESTPATHCHR, USERFILE);
323 if(!(ofp = fopen(path, "wb"))){
324 log_print(LL_ERROR, "synchronizing the user list failed");
325 return FALSE;
326 }
327 err = FALSE;
328 cbmapiterinit(umgr->users);
329 while((kbuf = cbmapiternext(umgr->users, &ksiz)) != NULL){
330 vbuf = cbmapget(umgr->users, kbuf, ksiz, NULL);
331 user = (USER *)vbuf;
332 fprintf(ofp, "%s\t%s\t%s\t%s\t%s\n",
333 user->name, user->passwd, user->flags, user->fname, user->misc);
334 }
335 if(fclose(ofp) == EOF){
336 log_print(LL_ERROR, "saving the user list failed");
337 err = TRUE;
338 }
339 return err ? FALSE : TRUE;
340 }
341
342
343 /* Add a user to a user manager object. */
344 int umgr_put(UMGR *umgr, const char *name, const char *passwd, const char *flags,
345 const char *fname, const char *misc){
346 USER user;
347 assert(umgr && name && passwd && flags && fname && misc);
348 log_print(LL_DEBUG, "umgr_put: %s:%s:%s:%s:%s", name, passwd, flags, fname, misc);
349 if(name[0] == '\0' || cbmapget(umgr->users, name, -1, NULL)){
350 log_print(LL_WARN, "duplicated or empty user name: %s", name);
351 return FALSE;
352 }
353 if(!check_alnum_name(name)){
354 log_print(LL_WARN, "invalid user name: %s", name);
355 return FALSE;
356 }
357 user.name = cbmemdup(name, -1);
358 user.passwd = cbmemdup(passwd, -1);
359 user.flags = cbmemdup(flags, -1);
360 user.fname = cbmemdup(fname, -1);
361 user.misc = cbmemdup(misc, -1);
362 user.atime = 0;
363 user.sess = NULL;
364 pthread_mutex_init(&(user.mutex), NULL);
365 cbmapput(umgr->users, name, -1, (char *)&user, sizeof(USER), FALSE);
366 return TRUE;
367 }
368
369
370 /* Remove a user from a user manager object. */
371 int umgr_out(UMGR *umgr, const char *name){
372 USER *user;
373 const char *vbuf;
374 assert(umgr && name);
375 log_print(LL_DEBUG, "umgr_out: %s", name);
376 if(!(vbuf = cbmapget(umgr->users, name, -1, NULL))) return FALSE;
377 user = (USER *)vbuf;
378 pthread_mutex_destroy(&(user->mutex));
379 if(user->sess) cbmapclose(user->sess);
380 free(user->misc);
381 free(user->fname);
382 free(user->flags);
383 free(user->passwd);
384 free(user->name);
385 cbmapout(umgr->users, name, -1);
386 return TRUE;
387 }
388
389
390 /* Get a list of names of users in a user manager object. */
391 CBLIST *umgr_names(UMGR *umgr){
392 CBLIST *names;
393 assert(umgr);
394 names = cbmapkeys(umgr->users);
395 cblistsort(names);
396 return names;
397 }
398
399
400 /* Get a user object in a user manager object. */
401 USER *umgr_get(UMGR *umgr, const char *name){
402 const char *vbuf;
403 assert(umgr && name);
404 if(!(vbuf = cbmapget(umgr->users, name, -1, NULL))) return NULL;
405 return (USER *)vbuf;
406 }
407
408
409 /* Make the session of a user object. */
410 void user_make_sess(USER *user){
411 assert(user);
412 if(pthread_mutex_lock(&(user->mutex)) != 0) return;
413 if(user->sess) cbmapclose(user->sess);
414 user->sess = cbmapopenex(MINIBNUM);
415 pthread_mutex_unlock(&(user->mutex));
416 }
417
418
419 /* Clear the session of a user object. */
420 void user_clear_sess(USER *user){
421 assert(user);
422 if(pthread_mutex_lock(&(user->mutex)) != 0) return;
423 if(user->sess) cbmapclose(user->sess);
424 user->sess = NULL;
425 pthread_mutex_unlock(&(user->mutex));
426 }
427
428
429 /* Set a session variable of a user object. */
430 void user_set_sess_val(USER *user, const char *name, const char *value){
431 assert(user && name);
432 if(pthread_mutex_lock(&(user->mutex)) != 0) return;
433 if(user->sess){
434 if(value){
435 cbmapput(user->sess, name, -1, value, -1, TRUE);
436 } else {
437 cbmapout(user->sess, name, -1);
438 }
439 }
440 pthread_mutex_unlock(&(user->mutex));
441 }
442
443
444 /* Get the value of a session variable of a user object. */
445 char *user_sess_val(USER *user, const char *name){
446 const char *value;
447 char *rv;
448 assert(user && name);
449 if(pthread_mutex_lock(&(user->mutex)) != 0) return NULL;
450 value = user->sess ? cbmapget(user->sess, name, -1, NULL) : NULL;
451 rv = value ? cbmemdup(value, -1) : NULL;
452 pthread_mutex_unlock(&(user->mutex));
453 return rv;
454 }
455
456
457 /* Create a node manager object. */
458 NMGR *nmgr_new(const char *rootdir){
459 NMGR *nmgr;
460 assert(rootdir);
461 log_print(LL_INFO, "starting the node manager");
462 nmgr = cbmalloc(sizeof(NMGR));
463 nmgr->rootdir = cbmemdup(rootdir, -1);
464 nmgr->nodes = cbmapopen();
465 return nmgr;
466 }
467
468
469 /* Destroy a user manager object. */
470 int nmgr_delete(NMGR *nmgr){
471 NODE *node;
472 const char *kbuf, *vbuf;
473 int err, ksiz, ecode;
474 assert(nmgr);
475 log_print(LL_INFO, "finishing the node manager");
476 err = FALSE;
477 if(!nmgr_sync(nmgr, FALSE)) err = TRUE;
478 cbmapiterinit(nmgr->nodes);
479 while((kbuf = cbmapiternext(nmgr->nodes, &ksiz)) != NULL){
480 vbuf = cbmapget(nmgr->nodes, kbuf, ksiz, NULL);
481 node = (NODE *)vbuf;
482 pthread_mutex_destroy(&(node->mutex));
483 cbmapclose(node->links);
484 cbmapclose(node->users);
485 cbmapclose(node->admins);
486 free(node->label);
487 free(node->name);
488 est_mtdb_close(node->db, &ecode);
489 }
490 cbmapclose(nmgr->nodes);
491 free(nmgr->rootdir);
492 free(nmgr);
493 return err ? FALSE : TRUE;
494 }
495
496
497 /* Load all nodes from the node directory. */
498 int nmgr_load(NMGR *nmgr, int wmode){
499 CBLIST *list;
500 const char *file;
501 char path[URIBUFSIZ];
502 int i, err;
503 assert(nmgr);
504 sprintf(path, "%s%c%s", nmgr->rootdir, ESTPATHCHR, NODEDIR);
505 if(!(list = cbdirlist(path))){
506 log_print(LL_ERROR, "loading the node directory failed");
507 return FALSE;
508 }
509 err = FALSE;
510 for(i = 0; i < cblistnum(list); i++){
511 file = cblistval(list, i, NULL);
512 if(!strcmp(file, ESTCDIRSTR) || !strcmp(file, ESTPDIRSTR)) continue;
513 if(!nmgr_put(nmgr, file, wmode)) err = TRUE;
514 }
515 cblistclose(list);
516 return err ? FALSE : TRUE;
517 }
518
519
520 /* Synchronize all nodes into the node directory. */
521 int nmgr_sync(NMGR *nmgr, int phis){
522 NODE *node;
523 CBDATUM *datum;
524 const char *kbuf, *vbuf;
525 int err, ksiz, vsiz;
526 assert(nmgr);
527 log_print(LL_INFO, "synchronizing the node manager");
528 err = FALSE;
529 cbmapiterinit(nmgr->nodes);
530 while((kbuf = cbmapiternext(nmgr->nodes, &ksiz)) != NULL){
531 vbuf = cbmapget(nmgr->nodes, kbuf, ksiz, NULL);
532 node = (NODE *)vbuf;
533 est_mtdb_add_meta(node->db, NMKNAME, node->name);
534 est_mtdb_add_meta(node->db, NMKLABEL, node->label);
535 datum = cbdatumopen("", 0);
536 cbmapiterinit(node->admins);
537 while((kbuf = cbmapiternext(node->admins, &ksiz)) != NULL){
538 cbdatumcat(datum, kbuf, ksiz);
539 cbdatumcat(datum, "\n", 1);
540 }
541 est_mtdb_add_meta(node->db, NMKADMINS, cbdatumptr(datum));
542 cbdatumclose(datum);
543 datum = cbdatumopen("", 0);
544 cbmapiterinit(node->users);
545 while((kbuf = cbmapiternext(node->users, &ksiz)) != NULL){
546 cbdatumcat(datum, kbuf, ksiz);
547 cbdatumcat(datum, "\n", 1);
548 }
549 est_mtdb_add_meta(node->db, NMKUSERS, cbdatumptr(datum));
550 cbdatumclose(datum);
551 datum = cbdatumopen("", 0);
552 cbmapiterinit(node->links);
553 while((kbuf = cbmapiternext(node->links, &ksiz)) != NULL){
554 vbuf = cbmapget(node->links, kbuf, ksiz, &vsiz);
555 cbdatumcat(datum, kbuf, ksiz);
556 cbdatumcat(datum, "\t", 1);
557 cbdatumcat(datum, vbuf, vsiz);
558 cbdatumcat(datum, "\n", 1);
559 }
560 est_mtdb_add_meta(node->db, NMKLINKS, cbdatumptr(datum));
561 cbdatumclose(datum);
562 if(phis && !est_mtdb_sync(node->db)){
563 log_print(LL_ERROR, "DB-ERROR: %s", est_err_msg(est_mtdb_error(node->db)));
564 err = TRUE;
565 }
566 }
567 return err ? FALSE : TRUE;
568 }
569
570
571 /* Add a node to a node manager object. */
572 int nmgr_put(NMGR *nmgr, const char *name, int wmode){
573 NODE node;
574 ESTMTDB *db;
575 CBLIST *list;
576 const char *cbuf, *pv;
577 char pbuf[URIBUFSIZ], *vbuf;
578 int i, ecode, csiz;
579 assert(nmgr && name);
580 log_print(LL_DEBUG, "nmgr_put: %s", name);
581 if(name[0] == '\0' || cbmapget(nmgr->nodes, name, -1, NULL)){
582 log_print(LL_WARN, "duplicated or empty node name: %s", name);
583 return FALSE;
584 }
585 if(strlen(name) >= NODENAMEMAX || !check_alnum_name(name)){
586 log_print(LL_WARN, "invalid node name: %s", name);
587 return FALSE;
588 }
589 log_print(LL_INFO, "opening the node (%s): %s", wmode ? "WRITER" : "READER", name);
590 sprintf(pbuf, "%s%c%s%c%s", nmgr->rootdir, ESTPATHCHR, NODEDIR, ESTPATHCHR, name);
591 if(!(db = est_mtdb_open(pbuf, wmode ? ESTDBWRITER | ESTDBCREAT : ESTDBREADER, &ecode))){
592 log_print(LL_ERROR, "DB-ERROR: %s", est_err_msg(ecode));
593 return FALSE;
594 }
595 est_mtdb_set_informer(db, db_inform);
596 node.db = db;
597 est_mtdb_add_meta(db, NMKNAME, name);
598 node.name = cbmemdup(name, -1);
599 vbuf = est_mtdb_meta(db, NMKLABEL);
600 node.label = vbuf ? vbuf : cbmemdup(name, -1);
601 if((vbuf = est_mtdb_meta(db, NMKADMINS)) != NULL){
602 list = cbsplit(vbuf, -1, "\n");
603 node.admins = cbmapopenex(cblistnum(list) + MINIBNUM);
604 for(i = 0; i < cblistnum(list); i++){
605 cbuf = cblistval(list, i, &csiz);
606 if(csiz < 1) continue;
607 cbmapput(node.admins, cbuf, csiz, "", 0, FALSE);
608 }
609 cblistclose(list);
610 free(vbuf);
611 } else {
612 node.admins = cbmapopenex(MINIBNUM);
613 }
614 if((vbuf = est_mtdb_meta(db, NMKUSERS)) != NULL){
615 list = cbsplit(vbuf, -1, "\n");
616 node.users = cbmapopenex(cblistnum(list) + MINIBNUM);
617 for(i = 0; i < cblistnum(list); i++){
618 cbuf = cblistval(list, i, &csiz);
619 if(csiz < 1) continue;
620 cbmapput(node.users, cbuf, csiz, "", 0, FALSE);
621 }
622 cblistclose(list);
623 free(vbuf);
624 } else {
625 node.users = cbmapopenex(MINIBNUM);
626 }
627 if((vbuf = est_mtdb_meta(db, NMKLINKS)) != NULL){
628 list = cbsplit(vbuf, -1, "\n");
629 node.links = cbmapopenex(cblistnum(list) + MINIBNUM);
630 for(i = 0; i < cblistnum(list); i++){
631 cbuf = cblistval(list, i, NULL);
632 if(!(pv = strchr(cbuf, '\t'))) continue;
633 cbmapput(node.links, cbuf, pv - cbuf, pv + 1, -1, FALSE);
634 }
635 cblistclose(list);
636 free(vbuf);
637 } else {
638 node.links = cbmapopenex(MINIBNUM);
639 }
640 pthread_mutex_init(&(node.mutex), NULL);
641 cbmapput(nmgr->nodes, name, -1, (char *)&node, sizeof(NODE), FALSE);
642 return TRUE;
643 }
644
645
646 /* Remove a node from a node manager object. */
647 int nmgr_out(NMGR *nmgr, const char *name){
648 NODE *node;
649 const char *vbuf;
650 char pbuf[URIBUFSIZ];
651 int err, ecode;
652 assert(nmgr && name);
653 log_print(LL_DEBUG, "nmgr_out: %s", name);
654 if(!(vbuf = cbmapget(nmgr->nodes, name, -1, NULL))) return FALSE;
655 err = FALSE;
656 node = (NODE *)vbuf;
657 pthread_mutex_destroy(&(node->mutex));
658 cbmapclose(node->links);
659 cbmapclose(node->users);
660 cbmapclose(node->admins);
661 free(node->label);
662 free(node->name);
663 if(!(est_mtdb_close(node->db, &ecode))){
664 log_print(LL_ERROR, "DB-ERROR: %s", est_err_msg(ecode));
665 err = TRUE;
666 }
667 sprintf(pbuf, "%s%c%s%c%s", nmgr->rootdir, ESTPATHCHR, NODEDIR, ESTPATHCHR, name);
668 if(!est_rmdir_rec(pbuf)){
669 log_print(LL_ERROR, "could not remove a directory");
670 err = TRUE;
671 }
672 cbmapout(nmgr->nodes, name, -1);
673 return TRUE;
674 }
675
676
677 /* Get a list of names of nodes in a noder manager object. */
678 CBLIST *nmgr_names(NMGR *nmgr){
679 CBLIST *names;
680 assert(nmgr);
681 names = cbmapkeys(nmgr->nodes);
682 cblistsort(names);
683 return names;
684 }
685
686
687 /* Get a node object in a node manager object. */
688 NODE *nmgr_get(NMGR *nmgr, const char *name){
689 const char *vbuf;
690 assert(nmgr && name);
691 if(!(vbuf = cbmapget(nmgr->nodes, name, -1, NULL))) return NULL;
692 return (NODE *)vbuf;
693 }
694
695
696 /* Set a link object of a node. */
697 void node_set_link(NODE *node, const char *url, const char *label, int credit){
698 char *vbuf;
699 assert(node && url);
700 if(!label || credit < 0){
701 cbmapout(node->links, url, -1);
702 return;
703 }
704 vbuf = cbsprintf("%s\t%d", label, credit);
705 cbmapput(node->links, url, -1, vbuf, -1, TRUE);
706 free(vbuf);
707 }
708
709
710 /* Create a read-write lock object. */
711 RWLOCK *rwlock_new(void){
712 RWLOCK *rwlock;
713 rwlock = cbmalloc(sizeof(RWLOCK));
714 rwlock->readers = 0;
715 rwlock->writers = 0;
716 pthread_mutex_init(&(rwlock->mutex), NULL);
717 pthread_cond_init(&(rwlock->cond), NULL);
718 return rwlock;
719 }
720
721
722 /* Destroy a read-write lock object. */
723 void rwlock_delete(RWLOCK *rwlock){
724 assert(rwlock);
725 pthread_cond_destroy(&(rwlock->cond));
726 pthread_mutex_destroy(&(rwlock->mutex));
727 free(rwlock);
728 }
729
730
731 /* Lock a read-write lock object. */
732 int rwlock_lock(RWLOCK *rwlock, int wmode){
733 assert(rwlock);
734 if(pthread_mutex_lock(&(rwlock->mutex)) != 0) return FALSE;
735 if(wmode){
736 while(rwlock->writers > 0 || rwlock->readers > 0){
737 pthread_cond_wait(&(rwlock->cond), &(rwlock->mutex));
738 }
739 rwlock->writers++;
740 } else {
741 while(rwlock->writers > 0){
742 pthread_cond_wait(&(rwlock->cond), &(rwlock->mutex));
743 }
744 rwlock->readers++;
745 }
746 pthread_mutex_unlock(&(rwlock->mutex));
747 return TRUE;
748 }
749
750
751 /* Unlock a read-write lock object. */
752 int rwlock_unlock(RWLOCK *rwlock){
753 assert(rwlock);
754 if(pthread_mutex_lock(&(rwlock->mutex)) != 0) return FALSE;
755 if(rwlock->writers > 0){
756 rwlock->writers--;
757 pthread_cond_broadcast(&(rwlock->cond));
758 pthread_mutex_unlock(&(rwlock->mutex));
759 } else {
760 rwlock->readers--;
761 if(rwlock->readers < 1) pthread_cond_signal(&(rwlock->cond));
762 pthread_mutex_unlock(&(rwlock->mutex));
763 }
764 return TRUE;
765 }
766
767
768 /* Get the number of readers locking a read-write lock object. */
769 int rwlock_rnum(RWLOCK *rwlock){
770 assert(rwlock);
771 return rwlock->readers;
772 }
773
774
775 /* Create a result map object. */
776 RESMAP *resmap_new(void){
777 RESMAP *resmap;
778 resmap = cbmalloc(sizeof(RESMAP));
779 resmap->uris = cbmapopen();
780 pthread_mutex_init(&(resmap->mutex), NULL);
781 return resmap;
782 }
783
784
785 /* Destroy a result map object. */
786 void resmap_delete(RESMAP *resmap){
787 RESDOC *resdoc;
788 const char *kbuf, *vbuf;
789 int ksiz;
790 assert(resmap);
791 cbmapiterinit(resmap->uris);
792 while((kbuf = cbmapiternext(resmap->uris, &ksiz)) != NULL){
793 vbuf = cbmapget(resmap->uris, kbuf, ksiz, NULL);
794 resdoc = (RESDOC *)vbuf;
795 if(resdoc->doc) est_doc_delete(resdoc->doc);
796 if(resdoc->attrs) cbmapclose(resdoc->attrs);
797 if(resdoc->body) free(resdoc->body);
798 }
799 pthread_mutex_destroy(&(resmap->mutex));
800 cbmapclose(resmap->uris);
801 free(resmap);
802 }
803
804
805 /* Add a result document data to a result map object. */
806 void resmap_put(RESMAP *resmap, int score, ESTDOC *doc, CBMAP *attrs, char *body){
807 RESDOC resdoc;
808 const char *uri, *vbuf;
809 assert(resmap);
810 uri = NULL;
811 if(doc) uri = est_doc_attr(doc, ESTDATTRURI);
812 if(attrs) uri = cbmapget(attrs, ESTDATTRURI, -1, NULL);
813 if(!uri || pthread_mutex_lock(&(resmap->mutex)) != 0){
814 if(doc) est_doc_delete(doc);
815 if(attrs) cbmapclose(attrs);
816 if(body) free(body);
817 return;
818 }
819 if((vbuf = cbmapget(resmap->uris, uri, -1, NULL)) != NULL){
820 if(((RESDOC *)vbuf)->score >= score){
821 if(doc) est_doc_delete(doc);
822 if(attrs) cbmapclose(attrs);
823 if(body) free(body);
824 } else {
825 if(((RESDOC *)vbuf)->doc) est_doc_delete(((RESDOC *)vbuf)->doc);
826 if(((RESDOC *)vbuf)->attrs) cbmapclose(((RESDOC *)vbuf)->attrs);
827 if(((RESDOC *)vbuf)->body) free(((RESDOC *)vbuf)->body);
828 resdoc.score = score;
829 resdoc.doc = doc;
830 resdoc.attrs = attrs;
831 resdoc.body = body;
832 cbmapput(resmap->uris, uri, -1, (char *)&resdoc, sizeof(RESDOC), TRUE);
833 }
834 } else {
835 resdoc.score = score;
836 resdoc.doc = doc;
837 resdoc.attrs = attrs;
838 resdoc.body = body;
839 cbmapput(resmap->uris, uri, -1, (char *)&resdoc, sizeof(RESDOC), FALSE);
840 }
841 pthread_mutex_unlock(&(resmap->mutex));
842 }
843
844
845 /* Get a list object of result objects in a result map objects. */
846 RESDOC **resmap_list(RESMAP *resmap, int *nump){
847 RESDOC **resdocs;
848 const char *kbuf, *vbuf;
849 int i, ksiz;
850 assert(resmap && nump);
851 if(pthread_mutex_lock(&(resmap->mutex)) != 0){
852 *nump = 0;
853 return cbmalloc(1);
854 }
855 *nump = cbmaprnum(resmap->uris);
856 resdocs = cbmalloc(*nump * sizeof(RESDOC) + 1);
857 cbmapiterinit(resmap->uris);
858 for(i = 0; i < *nump; i++){
859 kbuf = cbmapiternext(resmap->uris, &ksiz);
860 vbuf = cbmapget(resmap->uris, kbuf, ksiz, NULL);
861 resdocs[i] = (RESDOC *)vbuf;
862 }
863 qsort(resdocs, *nump, sizeof(RESDOC *), resdoc_compare);
864 pthread_mutex_unlock(&(resmap->mutex));
865 return resdocs;
866 }
867
868
869 /* Be a daemon process. */
870 int be_daemon(const char *curdir){
871 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
872 PROCESS_INFORMATION pi;
873 STARTUPINFO si;
874 assert(curdir);
875 FreeConsole();
876 if(getenv("ESTDAEMON")){
877 Sleep(1000);
878 if(chdir(curdir) == -1) return FALSE;
879 } else {
880 putenv("ESTDAEMON=1");
881 memset(&si, 0, sizeof(STARTUPINFO));
882 si.cb = sizeof(si);
883 if(!CreateProcess(NULL, GetCommandLine(), NULL, NULL, FALSE,
884 BELOW_NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP |
885 CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL, &si, &pi))
886 return FALSE;
887 CloseHandle(pi.hProcess);
888 exit(0);
889 }
890 return TRUE;
891 #else
892 int fd;
893 assert(curdir);
894 switch(fork()){
895 case -1:
896 return FALSE;
897 case 0:
898 break;
899 default:
900 exit(0);
901 }
902 if(setsid() == -1) return FALSE;
903 switch(fork()){
904 case -1:
905 return FALSE;
906 case 0:
907 break;
908 default:
909 exit(0);
910 }
911 umask(0);
912 if(chdir(curdir) == -1) return FALSE;
913 close(0);
914 close(1);
915 close(2);
916 if((fd = open(NULLDEV, O_RDWR, 0)) != -1){
917 dup2(fd, 0);
918 dup2(fd, 1);
919 dup2(fd, 2);
920 if(fd > 2) close(fd);
921 }
922 nice(5);
923 return TRUE;
924 #endif
925 }
926
927
928
929 /*************************************************************************************************
930 * private objects
931 *************************************************************************************************/
932
933
934 /* Close the log file. */
935 static void log_close(void){
936 if(log_fp) fclose(log_fp);
937 }
938
939
940 /* Output the log message of a DB event.
941 `msg' specifies the log message of a DB event. */
942 static void db_inform(const char *msg){
943 assert(msg);
944 log_print(LL_INFO, "DB-EVENT: %s", msg);
945 }
946
947
948 /* Compare two result document objects by score.
949 `ap' specifies the pointer to one object.
950 `ap' specifies the pointer to the other object.
951 The return value is negative if one is small, positive if one is big, 0 if both are equal. */
952 static int resdoc_compare(const void *ap, const void *bp){
953 assert(ap && bp);
954 return (*(RESDOC **)bp)->score - (*(RESDOC **)ap)->score;
955 }
956
957
958
959 /* END OF FILE */

  ViewVC Help
Powered by ViewVC 1.1.26