/[hyperestraier]/trunk/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 /trunk/mastermod.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Fri Jul 29 21:57:20 2005 UTC (18 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 28896 byte(s)
make working copy from version 0.5.1

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

  ViewVC Help
Powered by ViewVC 1.1.26