/[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

Annotation of /trunk/mastermod.c

Parent Directory Parent Directory | Revision Log Revision Log


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

1 dpavlin 2 /*************************************************************************************************
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