00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "dazuko_platform.h"
00036
00037 #include "dazuko_xp.h"
00038 #include "dazukoio.h"
00039
00040 #include "dazuko_call.h"
00041
00042 #define NUM_SLOT_LISTS 5
00043 #define NUM_SLOTS 25
00044
00045 #define SCAN_ON_OPEN (access_mask & DAZUKO_ON_OPEN)
00046 #define SCAN_ON_CLOSE (access_mask & DAZUKO_ON_CLOSE)
00047 #define SCAN_ON_EXEC (access_mask & DAZUKO_ON_EXEC)
00048 #define SCAN_ON_CLOSE_MODIFIED (access_mask & DAZUKO_ON_CLOSE_MODIFIED)
00049
00050 struct path
00051 {
00052
00053
00054
00055 struct path *next;
00056 int len;
00057 char path[1];
00058 };
00059
00060 struct hash
00061 {
00062
00063
00064
00065
00066 struct hash *next;
00067 struct xp_file file;
00068 int dirty;
00069 int namelen;
00070 char name[1];
00071 };
00072
00073 struct daemon_id
00074 {
00075 int unique;
00076 struct xp_daemon_id *xp_id;
00077 };
00078
00079 struct slot
00080 {
00081
00082
00083
00084
00085
00086 int id;
00087 struct daemon_id did;
00088 int write_mode;
00089 int state;
00090 int response;
00091 int event;
00092 int filenamelength;
00093 char *filename;
00094 struct event_properties event_p;
00095 struct file_properties file_p;
00096 struct xp_mutex mutex;
00097 };
00098
00099 struct slot_list
00100 {
00101 struct xp_atomic use_count;
00102 struct slot slots[NUM_SLOTS];
00103 char reg_name[1];
00104 };
00105
00106 struct slot_list_container
00107 {
00108 struct slot_list *slot_list;
00109 struct xp_mutex mutex;
00110 };
00111
00112 struct one_slot_state_not_condition_param
00113 {
00114 struct slot *slot;
00115 int state;
00116 };
00117
00118 struct two_slot_state_not_condition_param
00119 {
00120 struct slot *slot1;
00121 int state1;
00122 struct slot *slot2;
00123 int state2;
00124 };
00125
00126 struct get_ready_slot_condition_param
00127 {
00128 struct slot *slot;
00129 struct slot_list *slotlist;
00130 };
00131
00132 static int unique_count = 1;
00133 static char access_mask = 7;
00134 static struct slot_list_container slot_lists[NUM_SLOT_LISTS];
00135 static struct path *incl_paths = NULL;
00136 static struct path *excl_paths = NULL;
00137 static struct hash *hash = NULL;
00138 static struct xp_rwlock lock_hash;
00139 static struct xp_rwlock lock_lists;
00140 static struct xp_atomic active;
00141 static struct xp_mutex mutex_unique_count;
00142
00143 static struct xp_queue wait_kernel_waiting_for_free_slot;
00144 static struct xp_queue wait_daemon_waiting_for_work;
00145 static struct xp_queue wait_kernel_waiting_while_daemon_works;
00146 static struct xp_queue wait_daemon_waiting_for_free;
00147
00148
00149 int dazuko_vsnprintf(char *str, size_t size, const char *format, va_list ap)
00150 {
00151 char *target;
00152 const char *end;
00153 int overflow = 0;
00154 char number_buffer[32];
00155 const char *s;
00156
00157 if (str == NULL || size < 1 || format == NULL)
00158 return -1;
00159
00160 target = str;
00161 end = (target + size) - 1;
00162
00163 #define DAZUKO_VSNPRINTF_PRINTSTRING \
00164 for ( ; *s ; s++) \
00165 { \
00166 if (target == end) \
00167 { \
00168 overflow = 1; \
00169 goto dazuko_vsnprintf_out; \
00170 } \
00171 *target = *s; \
00172 target++; \
00173 }
00174
00175 for ( ; *format ; format++)
00176 {
00177 if (target == end)
00178 {
00179 overflow = 1;
00180 goto dazuko_vsnprintf_out;
00181 }
00182
00183 if (*format == '%')
00184 {
00185 format++;
00186
00187 switch (*format)
00188 {
00189 case 's':
00190 s = va_arg(ap, char *);
00191 if (s == NULL)
00192 s = "(null)";
00193 DAZUKO_VSNPRINTF_PRINTSTRING
00194 break;
00195
00196 case 'd':
00197 sprintf(number_buffer, "%d", va_arg(ap, int));
00198 s = number_buffer;
00199 DAZUKO_VSNPRINTF_PRINTSTRING
00200 break;
00201
00202 case 'c':
00203 *target = va_arg(ap, int);
00204 target++;
00205 break;
00206
00207 case 'l':
00208 format++;
00209 if (*format != 'u')
00210 {
00211
00212 goto dazuko_vsnprintf_out;
00213 }
00214 sprintf(number_buffer, "%lu", va_arg(ap, unsigned long));
00215 s = number_buffer;
00216 DAZUKO_VSNPRINTF_PRINTSTRING
00217 break;
00218
00219 case '0':
00220 format++;
00221 if (*format != '2')
00222 {
00223
00224 goto dazuko_vsnprintf_out;
00225 }
00226 format++;
00227 if (*format != 'x')
00228 {
00229
00230 goto dazuko_vsnprintf_out;
00231 }
00232 sprintf(number_buffer, "%02x", va_arg(ap, int));
00233 s = number_buffer;
00234 DAZUKO_VSNPRINTF_PRINTSTRING
00235 break;
00236
00237 default:
00238
00239 goto dazuko_vsnprintf_out;
00240 }
00241 }
00242 else
00243 {
00244 *target = *format;
00245 target++;
00246 }
00247 }
00248
00249 dazuko_vsnprintf_out:
00250
00251 *target = 0;
00252
00253
00254
00255
00256
00257
00258 return ((target - str) + overflow);
00259 }
00260
00261 int dazuko_snprintf(char *str, size_t size, const char *format, ...)
00262 {
00263 va_list ap;
00264 int ret;
00265
00266 va_start(ap, format);
00267 ret = dazuko_vsnprintf(str, size, format, ap);
00268 va_end(ap);
00269
00270 return ret;
00271 }
00272
00273 inline void dazuko_bzero(void *p, int len)
00274 {
00275
00276
00277 char *ptr = (char *)p;
00278
00279 while (len--)
00280 *ptr++ = 0;
00281 }
00282
00283 static inline int dazuko_get_new_unique(void)
00284 {
00285 int unique;
00286
00287
00288 call_xp_down(&mutex_unique_count);
00289
00290 unique = unique_count;
00291 unique_count++;
00292
00293 call_xp_up(&mutex_unique_count);
00294
00295
00296 return unique;
00297 }
00298
00299 static inline int dazuko_slot_state(struct slot *s)
00300 {
00301 int state;
00302
00303
00304 if (call_xp_down(&(s->mutex)) != 0)
00305 return XP_ERROR_INTERRUPT;
00306
00307 state = s->state;
00308
00309 call_xp_up(&(s->mutex));
00310
00311
00312 return state;
00313 }
00314
00315 static int one_slot_state_not_condition(void *param)
00316 {
00317 return (dazuko_slot_state(((struct one_slot_state_not_condition_param *)param)->slot)
00318 != ((struct one_slot_state_not_condition_param *)param)->state);
00319 }
00320
00321 static int two_slot_state_not_condition(void *param)
00322 {
00323 return (dazuko_slot_state(((struct two_slot_state_not_condition_param *)param)->slot1)
00324 != ((struct two_slot_state_not_condition_param *)param)->state1
00325 && dazuko_slot_state(((struct two_slot_state_not_condition_param *)param)->slot2)
00326 != ((struct two_slot_state_not_condition_param *)param)->state2);
00327 }
00328
00329 static inline int __dazuko_change_slot_state(struct slot *s, int from_state, int to_state)
00330 {
00331
00332
00333
00334
00335 if (to_state != from_state)
00336 {
00337
00338
00339 if (s->state != from_state || s->did.unique == 0)
00340 return 0;
00341 }
00342
00343 s->state = to_state;
00344
00345
00346
00347
00348 if (to_state == DAZUKO_READY)
00349 {
00350 call_xp_notify(&wait_kernel_waiting_for_free_slot);
00351 }
00352 else if (to_state == DAZUKO_FREE)
00353 {
00354 call_xp_notify(&wait_kernel_waiting_while_daemon_works);
00355 call_xp_notify(&wait_daemon_waiting_for_free);
00356 }
00357
00358 return 1;
00359 }
00360
00361 static int dazuko_change_slot_state(struct slot *s, int from_state, int to_state, int release)
00362 {
00363
00364
00365
00366
00367
00368
00369
00370 int success;
00371
00372
00373
00374 if (call_xp_down(&(s->mutex)) != 0)
00375 return 0;
00376
00377 success = __dazuko_change_slot_state(s, from_state, to_state);
00378
00379
00380
00381 if (!success || release)
00382 call_xp_up(&(s->mutex));
00383
00384 return success;
00385 }
00386
00387 static struct slot * _dazuko_find_slot(struct daemon_id *did, int release, struct slot_list *sl)
00388 {
00389
00390
00391
00392
00393
00394
00395 int i;
00396 struct slot *s = NULL;
00397
00398 if (sl == NULL)
00399 {
00400 call_xp_print("dazuko: invalid slot_list given (bug!)\n");
00401 return NULL;
00402 }
00403
00404 for (i=0 ; i<NUM_SLOTS ; i++)
00405 {
00406 s = &(sl->slots[i]);
00407
00408
00409
00410 if (call_xp_down(&(s->mutex)) != 0)
00411 return NULL;
00412
00413 if (did == NULL)
00414 {
00415
00416 if (s->did.unique == 0 && s->did.xp_id == NULL)
00417 {
00418
00419
00420 if (release)
00421 call_xp_up(&(s->mutex));
00422
00423 return s;
00424 }
00425 }
00426 else if (s->did.unique == 0 && s->did.xp_id == NULL)
00427 {
00428
00429
00430
00431 }
00432
00433 else if (call_xp_id_compare(s->did.xp_id, did->xp_id) == 0)
00434 {
00435
00436
00437 if (did->unique < 0 || (s->did.unique == did->unique))
00438 {
00439
00440
00441 if (release)
00442 call_xp_up(&(s->mutex));
00443
00444 return s;
00445 }
00446 }
00447
00448 call_xp_up(&(s->mutex));
00449
00450 }
00451
00452 return NULL;
00453 }
00454
00455 static struct slot * dazuko_find_slot_and_slotlist(struct daemon_id *did, int release, struct slot_list *slist, struct slot_list **sl_result)
00456 {
00457 struct slot *s;
00458 int i;
00459 struct slot_list *sl;
00460
00461 if (slist == NULL)
00462 {
00463 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
00464 {
00465
00466
00467
00468 if (call_xp_down(&(slot_lists[i].mutex)) != 0)
00469 return NULL;
00470
00471 sl = slot_lists[i].slot_list;
00472
00473 call_xp_up(&(slot_lists[i].mutex));
00474
00475
00476 if (sl != NULL)
00477 {
00478 s = _dazuko_find_slot(did, release, sl);
00479 if (s != NULL)
00480 {
00481
00482 if (sl_result != NULL)
00483 *sl_result = sl;
00484
00485 return s;
00486 }
00487 }
00488 }
00489 }
00490 else
00491 {
00492 return _dazuko_find_slot(did, release, slist);
00493 }
00494
00495 return NULL;
00496 }
00497
00498 static inline struct slot * dazuko_find_slot(struct daemon_id *did, int release, struct slot_list *slist)
00499 {
00500 return dazuko_find_slot_and_slotlist(did, release, slist, NULL);
00501 }
00502
00503 static int dazuko_insert_path_fs(struct path **list, char *fs_path, int fs_len)
00504 {
00505
00506
00507
00508
00509
00510
00511 struct path *newitem;
00512 struct path *tmp;
00513
00514 if (fs_path == NULL || fs_len < 1)
00515 return XP_ERROR_INVALID;
00516
00517
00518 if (!call_xp_is_absolute_path(fs_path))
00519 return XP_ERROR_INVALID;
00520
00521
00522 newitem = (struct path *)call_xp_malloc(sizeof(struct path) + fs_len);
00523 if (newitem == NULL)
00524 return XP_ERROR_FAULT;
00525
00526
00527 memcpy(newitem->path, fs_path, fs_len);
00528
00529 newitem->path[fs_len] = 0;
00530
00531 while (newitem->path[fs_len-1] == 0)
00532 {
00533 fs_len--;
00534 if (fs_len == 0)
00535 break;
00536 }
00537
00538 if (fs_len < 1)
00539 {
00540 call_xp_free(newitem);
00541 return XP_ERROR_INVALID;
00542 }
00543
00544 newitem->len = fs_len;
00545
00546
00547 for (tmp=*list ; tmp ; tmp=tmp->next)
00548 {
00549 if (newitem->len == tmp->len)
00550 {
00551 if (memcmp(newitem->path, tmp->path, tmp->len) == 0)
00552 {
00553
00554
00555 call_xp_free(newitem);
00556
00557 return 0;
00558 }
00559 }
00560 }
00561
00562 DPRINT(("dazuko: adding %s %s\n", (list == &incl_paths) ? "incl" : "excl", newitem->path));
00563
00564
00565
00566 call_xp_write_lock(&lock_lists);
00567 newitem->next = *list;
00568 *list = newitem;
00569 call_xp_write_unlock(&lock_lists);
00570
00571
00572 return 0;
00573 }
00574
00575 static void dazuko_remove_all_hash(void)
00576 {
00577
00578
00579 struct hash *tmp;
00580
00581
00582 call_xp_write_lock(&lock_hash);
00583 while (hash)
00584 {
00585 tmp = hash;
00586 hash = hash->next;
00587
00588 DPRINT(("dazuko: removing hash %s\n", tmp->name));
00589
00590 call_xp_free(tmp);
00591 }
00592 call_xp_write_unlock(&lock_hash);
00593
00594 }
00595
00596 static void dazuko_remove_all_paths(void)
00597 {
00598
00599
00600
00601 struct path *tmp;
00602
00603
00604 call_xp_write_lock(&lock_lists);
00605
00606
00607 while (incl_paths)
00608 {
00609 tmp = incl_paths;
00610 incl_paths = incl_paths->next;
00611
00612 DPRINT(("dazuko: removing incl %s\n", tmp->path));
00613
00614 call_xp_free(tmp);
00615 }
00616
00617
00618 while (excl_paths)
00619 {
00620 tmp = excl_paths;
00621 excl_paths = excl_paths->next;
00622
00623 DPRINT(("dazuko: removing excl %s\n", tmp->path));
00624
00625 call_xp_free(tmp);
00626 }
00627
00628 call_xp_write_unlock(&lock_lists);
00629
00630 }
00631
00632 static int _dazuko_unregister_daemon(struct daemon_id *did)
00633 {
00634
00635
00636
00637
00638 struct slot *s;
00639 struct slot_list *sl;
00640
00641 DPRINT(("dazuko: dazuko_unregister_daemon() [%d]\n", did->unique));
00642
00643
00644
00645
00646 s = dazuko_find_slot_and_slotlist(did, 0, NULL, &sl);
00647
00648 if (s == NULL)
00649 {
00650
00651 return 0;
00652 }
00653
00654
00655
00656
00657 s->did.unique = 0;
00658 call_xp_id_free(s->did.xp_id);
00659 s->did.xp_id = NULL;
00660
00661
00662 __dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE);
00663
00664 call_xp_atomic_dec(&(sl->use_count));
00665
00666 call_xp_up(&(s->mutex));
00667
00668
00669
00670
00671 if (call_xp_atomic_read(&active) > 0)
00672 {
00673
00674
00675
00676
00677 call_xp_atomic_dec(&active);
00678 }
00679 else
00680 {
00681 call_xp_print("dazuko: active count error (possible bug)\n");
00682 }
00683
00684
00685
00686
00687
00688
00689 if (call_xp_atomic_read(&active) == 0)
00690 {
00691
00692
00693 dazuko_remove_all_paths();
00694
00695
00696 dazuko_remove_all_hash();
00697 }
00698
00699 call_xp_notify(&wait_kernel_waiting_for_free_slot);
00700 call_xp_notify(&wait_kernel_waiting_while_daemon_works);
00701
00702 return 0;
00703 }
00704
00705 int dazuko_unregister_daemon(struct xp_daemon_id *xp_id)
00706 {
00707 struct daemon_id did;
00708 int ret;
00709
00710 if (xp_id == NULL)
00711 return 0;
00712
00713 did.unique = -1;
00714 did.xp_id = call_xp_id_copy(xp_id);
00715
00716 ret = _dazuko_unregister_daemon(&did);
00717
00718 call_xp_id_free(did.xp_id);
00719
00720 return ret;
00721 }
00722
00723 static inline int dazuko_state_error(struct slot *s, int current_state)
00724 {
00725 if (dazuko_change_slot_state(s, current_state, DAZUKO_BROKEN, 1))
00726 {
00727 call_xp_notify(&wait_kernel_waiting_for_free_slot);
00728 call_xp_notify(&wait_kernel_waiting_while_daemon_works);
00729 }
00730
00731 return 0;
00732 }
00733
00734 static int dazuko_register_daemon(struct daemon_id *did, const char *reg_name, int string_length, int write_mode)
00735 {
00736 const char *p1;
00737 char *p2;
00738 struct slot *s;
00739 struct slot_list *sl;
00740 int i;
00741
00742 DPRINT(("dazuko: dazuko_register_daemon() [%d]\n", did->unique));
00743
00744 if (did == NULL || reg_name == NULL)
00745 return XP_ERROR_PERMISSION;
00746
00747 s = dazuko_find_slot(did, 1, NULL);
00748
00749 if (s != NULL)
00750 {
00751
00752
00753 call_xp_print("dazuko: daemon %d already assigned to slot[%d]\n", did->unique, s->id);
00754
00755 return XP_ERROR_PERMISSION;
00756 }
00757
00758
00759
00760 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
00761 {
00762
00763
00764
00765 if (call_xp_down(&(slot_lists[i].mutex)) != 0)
00766 return XP_ERROR_INTERRUPT;
00767
00768 sl = slot_lists[i].slot_list;
00769
00770 call_xp_up(&(slot_lists[i].mutex));
00771
00772
00773 if (sl != NULL)
00774 {
00775 p1 = reg_name;
00776 p2 = sl->reg_name;
00777
00778 while (*p1 == *p2)
00779 {
00780 if (*p1 == 0)
00781 break;
00782
00783 p1++;
00784 p2++;
00785 }
00786
00787 if (*p1 == *p2)
00788 break;
00789 }
00790 }
00791
00792 if (i == NUM_SLOT_LISTS)
00793 {
00794
00795
00796
00797 sl = (struct slot_list *)call_xp_malloc(sizeof(struct slot_list) + string_length);
00798 if (sl == NULL)
00799 return XP_ERROR_FAULT;
00800
00801 dazuko_bzero(sl, sizeof(struct slot_list) + string_length);
00802 call_xp_atomic_set(&(sl->use_count), 0);
00803
00804 p1 = reg_name;
00805 p2 = sl->reg_name;
00806
00807 while (*p1)
00808 {
00809 *p2 = *p1;
00810
00811 p1++;
00812 p2++;
00813 }
00814 *p2 = 0;
00815
00816
00817 for (i=0 ; i<NUM_SLOTS ; i++)
00818 {
00819 sl->slots[i].id = i;
00820 call_xp_init_mutex(&(sl->slots[i].mutex));
00821 }
00822
00823
00824 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
00825 {
00826
00827
00828
00829 if (call_xp_down(&(slot_lists[i].mutex)) != 0)
00830 {
00831 call_xp_free(sl);
00832 return XP_ERROR_INTERRUPT;
00833 }
00834
00835 if (slot_lists[i].slot_list == NULL)
00836 {
00837 slot_lists[i].slot_list = sl;
00838
00839 call_xp_up(&(slot_lists[i].mutex));
00840
00841 break;
00842 }
00843
00844 call_xp_up(&(slot_lists[i].mutex));
00845
00846 }
00847
00848 if (i == NUM_SLOT_LISTS)
00849 {
00850
00851 call_xp_free(sl);
00852 return XP_ERROR_BUSY;
00853 }
00854 }
00855
00856
00857
00858
00859 s = dazuko_find_slot(NULL, 0, sl);
00860
00861 if (s == NULL)
00862 return XP_ERROR_BUSY;
00863
00864
00865
00866
00867
00868
00869
00870
00871 call_xp_atomic_inc(&active);
00872
00873
00874 did->unique = dazuko_get_new_unique();
00875
00876 s->did.unique = did->unique;
00877 s->did.xp_id = call_xp_id_copy(did->xp_id);
00878 s->write_mode = write_mode;
00879
00880 call_xp_atomic_inc(&(sl->use_count));
00881
00882
00883
00884 __dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE);
00885
00886 DPRINT(("dazuko: slot[%d] assigned to daemon %d\n", s->id, s->did.unique));
00887
00888 call_xp_up(&(s->mutex));
00889
00890
00891 return 0;
00892 }
00893
00894 static struct slot* dazuko_get_an_access(struct daemon_id *did)
00895 {
00896
00897
00898
00899
00900
00901
00902
00903
00904 int i;
00905 struct slot *s;
00906 struct one_slot_state_not_condition_param cond_p;
00907
00908 tryagain:
00909
00910 s = dazuko_find_slot(did, 1, NULL);
00911
00912 if (s == NULL)
00913 {
00914 i = dazuko_register_daemon(did, "_COMPAT", 7, 1);
00915 if (i != 0)
00916 {
00917 call_xp_print("dazuko: unregistered daemon %d attempted to get access\n", did->unique);
00918 return NULL;
00919 }
00920
00921 s = dazuko_find_slot(did, 1, NULL);
00922 if (s == NULL)
00923 {
00924 call_xp_print("dazuko: unregistered daemon %d attempted to get access\n", did->unique);
00925 return NULL;
00926 }
00927
00928 call_xp_print("dazuko: warning: daemon %d is using a deprecated protocol\n", did->unique);
00929 }
00930
00931
00932 dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_READY, 1);
00933
00934 cond_p.slot = s;
00935 cond_p.state = DAZUKO_READY;
00936 if (call_xp_wait_until_condition(&wait_daemon_waiting_for_work, one_slot_state_not_condition, &cond_p, 1) != 0)
00937 {
00938
00939
00940
00941
00942 DPRINT(("dazuko: daemon %d killed while waiting for work\n", did->unique));
00943
00944 if (dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_BROKEN, 1) || dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_BROKEN, 1))
00945 {
00946 call_xp_notify(&wait_kernel_waiting_for_free_slot);
00947 call_xp_notify(&wait_kernel_waiting_while_daemon_works);
00948 }
00949
00950 return NULL;
00951 }
00952
00953
00954
00955
00956
00957
00958
00959 if (!dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_WORKING, 0))
00960 {
00961
00962
00963 goto tryagain;
00964 }
00965
00966
00967
00968
00969
00970
00971
00972
00973 return s;
00974 }
00975
00976 static int dazuko_return_access(struct daemon_id *did, int response, struct slot *s)
00977 {
00978
00979
00980
00981
00982 struct one_slot_state_not_condition_param cond_p;
00983
00984
00985 if (s == NULL)
00986 {
00987
00988 s = dazuko_find_slot(did, 1, NULL);
00989
00990 if (s == NULL)
00991 {
00992
00993
00994
00995 DPRINT(("dazuko: daemon %d unexpectedly lost slot\n", did->unique));
00996
00997 return XP_ERROR_PERMISSION;
00998 }
00999 }
01000
01001
01002
01003
01004
01005 if (!dazuko_change_slot_state(s, DAZUKO_WORKING, DAZUKO_DONE, 0))
01006 {
01007
01008
01009
01010
01011 DPRINT(("dazuko: response from daemon %d on slot[%d] not needed\n", did->unique, s->id));
01012
01013 return 0;
01014 }
01015
01016
01017
01018 s->response = response;
01019
01020 call_xp_up(&(s->mutex));
01021
01022
01023
01024
01025 call_xp_notify(&wait_kernel_waiting_while_daemon_works);
01026
01027 cond_p.slot = s;
01028 cond_p.state = DAZUKO_DONE;
01029 if (call_xp_wait_until_condition(&wait_daemon_waiting_for_free, one_slot_state_not_condition, &cond_p, 1) != 0)
01030 {
01031
01032
01033
01034
01035 DPRINT(("dazuko: daemon %d killed while waiting for response acknowledgement\n", did->unique));
01036
01037 return XP_ERROR_INTERRUPT;
01038 }
01039
01040 return 0;
01041 }
01042
01043 static inline int dazuko_isdigit(const char c)
01044 {
01045 return (c >= '0' && c <= '9');
01046 }
01047
01048 static inline long dazuko_strtol(const char *string)
01049 {
01050 long num = 1;
01051 const char *p = string;
01052
01053 if (string == NULL)
01054 return 0;
01055
01056 switch (*p)
01057 {
01058 case '-':
01059 num = -1;
01060 p++;
01061 break;
01062
01063 case '+':
01064 p++;
01065 break;
01066 }
01067
01068 if (dazuko_isdigit(*p))
01069 {
01070 num *= *p - '0';
01071 p++;
01072 }
01073 else
01074 {
01075 return 0;
01076 }
01077
01078 while (dazuko_isdigit(*p))
01079 {
01080 num *= 10;
01081 num += *p - '0';
01082 p++;
01083 }
01084
01085 return num;
01086 }
01087
01088 static inline int dazuko_strlen(const char *string)
01089 {
01090 const char *p;
01091
01092 if (string == NULL)
01093 return -1;
01094
01095 for (p=string ; *p ; p++)
01096 continue;
01097
01098 return (p - string);
01099 }
01100
01101 static inline const char* dazuko_strchr(const char *haystack, char needle)
01102 {
01103 const char *p;
01104
01105 if (haystack == NULL)
01106 return NULL;
01107
01108 for (p=haystack ; *p ; p++)
01109 {
01110 if (*p == needle)
01111 return p;
01112 }
01113
01114 return NULL;
01115 }
01116
01117 static inline const char* dazuko_strstr(const char *haystack, const char *needle)
01118 {
01119 const char *p1;
01120 const char *p2;
01121 const char *p3;
01122
01123 if (haystack == NULL || needle == NULL)
01124 return NULL;
01125
01126 for (p1=haystack ; *p1 ; p1++)
01127 {
01128 for (p2=needle,p3=p1 ; *p2&&*p3 ; p2++,p3++)
01129 {
01130 if (*p2 != *p3)
01131 break;
01132 }
01133
01134 if (*p2 == 0)
01135 return p1;
01136 }
01137
01138 return NULL;
01139 }
01140
01141 int dazuko_get_value(const char *key, const char *string, char **value)
01142 {
01143 const char *p1;
01144 const char *p2;
01145 int size;
01146
01147 if (value == NULL)
01148 return -1;
01149
01150 *value = NULL;
01151
01152 if (key == NULL || string == NULL)
01153 return -1;
01154
01155 p1 = dazuko_strstr(string, key);
01156 if (p1 == NULL)
01157 return -1;
01158
01159 p1 += dazuko_strlen(key);
01160
01161 for (p2=p1 ; *p2 && *p2!='\n' ; p2++)
01162 continue;
01163
01164 size = (p2 - p1) + 1;
01165 *value = call_xp_malloc(size);
01166 if (*value == NULL)
01167 return -1;
01168
01169 memcpy(*value, p1, size - 1);
01170 (*value)[size - 1] = 0;
01171
01172 return 0;
01173 }
01174
01175 static inline void dazuko_clear_replybuffer(struct dazuko_request *request)
01176 {
01177 dazuko_bzero(request->reply_buffer, request->reply_buffer_size);
01178 request->reply_buffer_size_used = 0;
01179 }
01180
01181 static inline void dazuko_close_replybuffer(struct dazuko_request *request)
01182 {
01183 request->reply_buffer[request->reply_buffer_size_used] = 0;
01184 request->reply_buffer_size_used++;
01185 }
01186
01187 static inline void dazuko_add_keyvalue_to_replybuffer(struct dazuko_request *request, const char *key, void *value, char vtype)
01188 {
01189
01190 #define DAZUKO_VSNPRINT(type, name) dazuko_snprintf(request->reply_buffer + request->reply_buffer_size_used, (request->reply_buffer_size - request->reply_buffer_size_used) - 1, "%s%" #type , key, *((name *)value))
01191
01192 switch (vtype)
01193 {
01194 case 'd':
01195 DAZUKO_VSNPRINT(d, const int);
01196 break;
01197
01198 case 's':
01199 DAZUKO_VSNPRINT(s, const char *);
01200 break;
01201
01202 case 'l':
01203 DAZUKO_VSNPRINT(lu, const unsigned long);
01204 break;
01205
01206 default:
01207
01208 DAZUKO_VSNPRINT(c, const char);
01209 break;
01210 }
01211
01212
01213 request->reply_buffer_size_used += strlen(request->reply_buffer + request->reply_buffer_size_used);
01214 }
01215
01216 static inline int dazuko_printable(char c)
01217 {
01218
01219
01220 return ((c >= ' ') && (c <= '~') && (c != '\\'));
01221 }
01222
01223 static inline void dazuko_add_esc_to_replybuffer(struct dazuko_request *request, const char *key, char **filename)
01224 {
01225 int found = 0;
01226 char *p_rq;
01227 const char *limit;
01228 const char *p_fn;
01229 unsigned char c;
01230
01231
01232 for (p_fn=*filename ; *p_fn ; p_fn++)
01233 {
01234 if (!dazuko_printable(*p_fn))
01235 {
01236 found = 1;
01237 break;
01238 }
01239 }
01240
01241 if (found)
01242 {
01243
01244
01245 p_rq = request->reply_buffer + request->reply_buffer_size_used;
01246 limit = request->reply_buffer + request->reply_buffer_size - 1;
01247
01248 dazuko_snprintf(p_rq, limit - p_rq, "%s", key);
01249 p_rq += strlen(p_rq);
01250
01251 for (p_fn=*filename ; *p_fn && (p_rq<limit) ; p_fn++)
01252 {
01253 if (dazuko_printable(*p_fn))
01254 {
01255 *p_rq = *p_fn;
01256 p_rq++;
01257 }
01258 else
01259 {
01260 c = *p_fn & 0xFF;
01261 dazuko_snprintf(p_rq, limit - p_rq, "\\x%02x", c);
01262 p_rq += strlen(p_rq);
01263 }
01264 }
01265
01266 request->reply_buffer_size_used += strlen(request->reply_buffer + request->reply_buffer_size_used);
01267 }
01268 else
01269 {
01270
01271
01272 dazuko_add_keyvalue_to_replybuffer(request, key, filename, 's');
01273 }
01274 }
01275
01276 static int dazuko_set_option(struct daemon_id *did, int opt, void *param, int len)
01277 {
01278
01279
01280
01281 struct slot *s;
01282 int error;
01283
01284
01285 if (len < 0 || len > 8192)
01286 return XP_ERROR_PERMISSION;
01287
01288
01289
01290
01291
01292 s = dazuko_find_slot(did, 1, NULL);
01293
01294 switch (opt)
01295 {
01296 case REGISTER:
01297 call_xp_print("dazuko: dazuko_set_option does not support REGISTER (bug!)\n");
01298 return XP_ERROR_PERMISSION;
01299
01300 case UNREGISTER:
01301 if (s == NULL)
01302 {
01303
01304
01305 return 0;
01306 }
01307 break;
01308
01309 default:
01310 if (s == NULL)
01311 {
01312 error = dazuko_register_daemon(did, "_COMPAT", 7, 1);
01313 if (error)
01314 {
01315 call_xp_print("dazuko: unregistered daemon %d attempted access\n", did->unique);
01316 return XP_ERROR_PERMISSION;
01317 }
01318
01319 s = dazuko_find_slot(did, 1, NULL);
01320 if (s == NULL)
01321 {
01322 call_xp_print("dazuko: unregistered daemon %d attempted access\n", did->unique);
01323 return XP_ERROR_PERMISSION;
01324 }
01325
01326 call_xp_print("dazuko: warning: daemon %d is using a deprecated protocol\n", did->unique);
01327 }
01328 break;
01329 }
01330
01331
01332 switch (opt)
01333 {
01334 case UNREGISTER:
01335 error = _dazuko_unregister_daemon(did);
01336 if (error)
01337 return error;
01338 break;
01339
01340 case SET_ACCESS_MASK:
01341 memcpy(&access_mask, (char *)param, sizeof(char));
01342 break;
01343
01344 case ADD_INCLUDE_PATH:
01345 error = dazuko_insert_path_fs(&incl_paths, (char *)param, len);
01346 if (error)
01347 return error;
01348 break;
01349
01350 case ADD_EXCLUDE_PATH:
01351 error = dazuko_insert_path_fs(&excl_paths, (char *)param, len);
01352 if (error)
01353 return error;
01354 break;
01355
01356 case REMOVE_ALL_PATHS:
01357 dazuko_remove_all_paths();
01358 break;
01359
01360 default:
01361 call_xp_print("dazuko: daemon %d requested unknown set %d (possible bug)\n", did->unique, opt);
01362 break;
01363 }
01364
01365 return 0;
01366 }
01367
01368 static int dazuko_handle_request(struct dazuko_request *request, struct xp_daemon_id *xp_id)
01369 {
01370 char *value1;
01371 char *value2;
01372 int error = 0;
01373 int type;
01374 struct slot *s;
01375 struct daemon_id did;
01376
01377 if (request == NULL || xp_id == NULL)
01378 return -1;
01379
01380 type = request->type[0] + (256 * request->type[1]);
01381
01382 switch (type)
01383 {
01384 case REGISTER:
01385
01386
01387
01388 if (request->buffer_size <= 0)
01389 return -1;
01390
01391 if (request->reply_buffer_size <= 0)
01392 return -1;
01393
01394 if (dazuko_get_value("\nGN=", request->buffer, &value1) != 0)
01395 return -1;
01396
01397 if (dazuko_get_value("\nRM=", request->buffer, &value2) != 0)
01398 {
01399 call_xp_free(value1);
01400 return -1;
01401 }
01402
01403 did.xp_id = call_xp_id_copy(xp_id);
01404 did.unique = 0;
01405
01406 error = dazuko_register_daemon(&did, value1, dazuko_strlen(value1), dazuko_strchr(value2, 'W') != NULL);
01407
01408 dazuko_clear_replybuffer(request);
01409 dazuko_add_keyvalue_to_replybuffer(request, "\nID=", &(did.unique), 'd');
01410 dazuko_close_replybuffer(request);
01411
01412 call_xp_free(value1);
01413 call_xp_free(value2);
01414 call_xp_id_free(did.xp_id);
01415
01416 break;
01417
01418 case UNREGISTER:
01419
01420
01421 if (request->buffer_size <= 0)
01422 return -1;
01423
01424 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
01425 return -1;
01426
01427 did.xp_id = call_xp_id_copy(xp_id);
01428 did.unique = dazuko_strtol(value1);
01429
01430 error = dazuko_set_option(&did, UNREGISTER, NULL, 0);
01431
01432 call_xp_free(value1);
01433 call_xp_id_free(did.xp_id);
01434
01435 break;
01436
01437 case SET_ACCESS_MASK:
01438
01439
01440 if (request->buffer_size <= 0)
01441 return -1;
01442
01443 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
01444 return -1;
01445
01446 if (dazuko_get_value("\nAM=", request->buffer, &value2) != 0)
01447 {
01448 call_xp_free(value1);
01449 return -1;
01450 }
01451
01452 access_mask = (char)dazuko_strtol(value2);
01453
01454 call_xp_free(value1);
01455 call_xp_free(value2);
01456
01457 break;
01458
01459 case ADD_INCLUDE_PATH:
01460
01461
01462 if (request->buffer_size <= 0)
01463 return -1;
01464
01465 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
01466 return -1;
01467
01468 if (dazuko_get_value("\nPT=", request->buffer, &value2) != 0)
01469 {
01470 call_xp_free(value1);
01471 return -1;
01472 }
01473
01474 did.xp_id = call_xp_id_copy(xp_id);
01475 did.unique = dazuko_strtol(value1);
01476
01477 error = dazuko_set_option(&did, ADD_INCLUDE_PATH, value2, dazuko_strlen(value2));
01478
01479 call_xp_free(value1);
01480 call_xp_free(value2);
01481 call_xp_id_free(did.xp_id);
01482
01483 break;
01484
01485 case ADD_EXCLUDE_PATH:
01486
01487
01488 if (request->buffer_size <= 0)
01489 return -1;
01490
01491 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
01492 return -1;
01493
01494 if (dazuko_get_value("\nPT=", request->buffer, &value2) != 0)
01495 {
01496 call_xp_free(value1);
01497 return -1;
01498 }
01499
01500 did.xp_id = call_xp_id_copy(xp_id);
01501 did.unique = dazuko_strtol(value1);
01502
01503 error = dazuko_set_option(&did, ADD_EXCLUDE_PATH, value2, dazuko_strlen(value2));
01504
01505 call_xp_free(value1);
01506 call_xp_free(value2);
01507 call_xp_id_free(did.xp_id);
01508
01509 break;
01510
01511 case REMOVE_ALL_PATHS:
01512
01513
01514 if (request->buffer_size <= 0)
01515 return -1;
01516
01517 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
01518 return -1;
01519
01520 did.xp_id = call_xp_id_copy(xp_id);
01521 did.unique = dazuko_strtol(value1);
01522
01523 error = dazuko_set_option(&did, REMOVE_ALL_PATHS, NULL, 0);
01524
01525 call_xp_free(value1);
01526 call_xp_id_free(did.xp_id);
01527
01528 break;
01529
01530 case GET_AN_ACCESS:
01531
01532
01533
01534 if (request->buffer_size <= 0)
01535 return -1;
01536
01537 if (request->reply_buffer_size <= 0)
01538 return -1;
01539
01540 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
01541 return -1;
01542
01543 did.xp_id = call_xp_id_copy(xp_id);
01544 did.unique = dazuko_strtol(value1);
01545
01546 call_xp_free(value1);
01547
01548
01549 s = dazuko_get_an_access(&did);
01550
01551 if (s == NULL)
01552 {
01553 call_xp_id_free(did.xp_id);
01554 return XP_ERROR_INTERRUPT;
01555 }
01556
01557
01558
01559
01560
01561 dazuko_clear_replybuffer(request);
01562 dazuko_add_keyvalue_to_replybuffer(request, "\nEV=", &(s->event), 'd');
01563 dazuko_add_esc_to_replybuffer(request, "\nFN=", &(s->filename));
01564
01565 if (s->event_p.set_uid)
01566 dazuko_add_keyvalue_to_replybuffer(request, "\nUI=", &(s->event_p.uid), 'd');
01567
01568 if (s->event_p.set_pid)
01569 dazuko_add_keyvalue_to_replybuffer(request, "\nPI=", &(s->event_p.pid), 'd');
01570
01571 if (s->event_p.set_flags)
01572 dazuko_add_keyvalue_to_replybuffer(request, "\nFL=", &(s->event_p.flags), 'd');
01573
01574 if (s->event_p.set_mode)
01575 dazuko_add_keyvalue_to_replybuffer(request, "\nMD=", &(s->event_p.mode), 'd');
01576
01577 if (s->file_p.set_size)
01578 dazuko_add_keyvalue_to_replybuffer(request, "\nFS=", &(s->file_p.size), 'l');
01579
01580 if (s->file_p.set_uid)
01581 dazuko_add_keyvalue_to_replybuffer(request, "\nFU=", &(s->file_p.uid), 'd');
01582
01583 if (s->file_p.set_gid)
01584 dazuko_add_keyvalue_to_replybuffer(request, "\nFG=", &(s->file_p.gid), 'd');
01585
01586 if (s->file_p.set_mode)
01587 dazuko_add_keyvalue_to_replybuffer(request, "\nFM=", &(s->file_p.mode), 'd');
01588
01589 if (s->file_p.set_device_type)
01590 dazuko_add_keyvalue_to_replybuffer(request, "\nDT=", &(s->file_p.device_type), 'd');
01591
01592 dazuko_close_replybuffer(request);
01593
01594
01595
01596
01597
01598 if (!(s->write_mode))
01599 {
01600
01601
01602
01603 call_xp_up(&(s->mutex));
01604
01605
01606 dazuko_return_access(&did, 0, s);
01607 }
01608 else
01609 {
01610 call_xp_up(&(s->mutex));
01611
01612 }
01613
01614 call_xp_id_free(did.xp_id);
01615
01616 break;
01617
01618 case RETURN_AN_ACCESS:
01619
01620
01621 if (request->buffer_size <= 0)
01622 return -1;
01623
01624 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
01625 return -1;
01626
01627 if (dazuko_get_value("\nDN=", request->buffer, &value2) != 0)
01628 {
01629 call_xp_free(value1);
01630 return -1;
01631 }
01632
01633 did.xp_id = call_xp_id_copy(xp_id);
01634 did.unique = dazuko_strtol(value1);
01635
01636 error = dazuko_return_access(&did, dazuko_strtol(value2), NULL);
01637
01638 call_xp_free(value1);
01639 call_xp_free(value2);
01640 call_xp_id_free(did.xp_id);
01641
01642 break;
01643
01644 default:
01645 call_xp_print("dazuko: daemon made unknown request %d (possible bug)\n", type);
01646
01647 break;
01648 }
01649
01650 return error;
01651 }
01652
01653 int dazuko_handle_user_request(struct dazuko_request *user_request, struct xp_daemon_id *xp_id)
01654 {
01655 int error = 0;
01656 struct dazuko_request *request;
01657 struct dazuko_request *temp_request;
01658
01659 if (user_request == NULL || xp_id == NULL)
01660 return XP_ERROR_FAULT;
01661
01662
01663 request = (struct dazuko_request *)call_xp_malloc(sizeof(struct dazuko_request));
01664 if (request == NULL)
01665 return XP_ERROR_FAULT;
01666
01667
01668
01669
01670 temp_request = (struct dazuko_request *)call_xp_malloc(sizeof(struct dazuko_request));
01671 if (temp_request == NULL)
01672 {
01673 error = XP_ERROR_FAULT;
01674 goto dazuko_handle_user_request_out0;
01675 }
01676
01677
01678
01679
01680 if (call_xp_copyin(user_request, temp_request, sizeof(struct dazuko_request)) != 0)
01681 {
01682 error = XP_ERROR_FAULT;
01683 goto dazuko_handle_user_request_out1;
01684 }
01685
01686 memcpy(request->type, temp_request->type, sizeof(char[2]));
01687 request->buffer_size = temp_request->buffer_size;
01688
01689
01690 if (request->buffer_size < 0 || request->buffer_size > 8192)
01691 {
01692 error = XP_ERROR_FAULT;
01693 goto dazuko_handle_user_request_out1;
01694 }
01695
01696 request->reply_buffer_size = temp_request->reply_buffer_size;
01697
01698
01699 if (request->reply_buffer_size < 0 || request->reply_buffer_size > 8192)
01700 {
01701 error = XP_ERROR_PERMISSION;
01702 goto dazuko_handle_user_request_out1;
01703 }
01704
01705
01706 request->buffer = (char *)call_xp_malloc(request->buffer_size + 1);
01707 if (request->buffer == NULL)
01708 {
01709 error = XP_ERROR_FAULT;
01710 goto dazuko_handle_user_request_out1;
01711 }
01712
01713
01714
01715 if (request->reply_buffer_size > 0)
01716 {
01717
01718 request->reply_buffer = (char *)call_xp_malloc(request->reply_buffer_size + 1);
01719 if (request->reply_buffer == NULL)
01720 {
01721 error = XP_ERROR_FAULT;
01722 goto dazuko_handle_user_request_out2;
01723 }
01724
01725
01726
01727 request->reply_buffer_size_used = 0;
01728 }
01729
01730
01731 if (call_xp_copyin(temp_request->buffer, request->buffer, request->buffer_size) != 0)
01732 {
01733 error = XP_ERROR_FAULT;
01734 goto dazuko_handle_user_request_out3;
01735 }
01736
01737 request->buffer[request->buffer_size] = 0;
01738
01739 error = dazuko_handle_request(request, xp_id);
01740
01741 if (error == 0 && request->reply_buffer_size > 0)
01742 {
01743 request->reply_buffer[request->reply_buffer_size] = 0;
01744
01745 temp_request->reply_buffer_size_used = request->reply_buffer_size_used;
01746
01747 if (call_xp_copyout(temp_request, user_request, sizeof(struct dazuko_request)) != 0)
01748 {
01749 error = XP_ERROR_FAULT;
01750 goto dazuko_handle_user_request_out3;
01751 }
01752
01753 if (request->reply_buffer_size_used > 0)
01754 {
01755 if (call_xp_copyout(request->reply_buffer, temp_request->reply_buffer, request->reply_buffer_size_used) != 0)
01756 {
01757 error = XP_ERROR_FAULT;
01758 goto dazuko_handle_user_request_out3;
01759 }
01760 }
01761 }
01762
01763 dazuko_handle_user_request_out3:
01764 if (request->reply_buffer_size > 0)
01765 call_xp_free(request->reply_buffer);
01766 dazuko_handle_user_request_out2:
01767 call_xp_free(request->buffer);
01768 dazuko_handle_user_request_out1:
01769 call_xp_free(temp_request);
01770 dazuko_handle_user_request_out0:
01771 call_xp_free(request);
01772
01773 return error;
01774 }
01775
01776 int dazuko_handle_user_request_compat12(void *ptr, int cmd, struct xp_daemon_id *xp_id)
01777 {
01778 struct access_compat12 *user_request12;
01779 struct access_compat12 *temp_request12;
01780 int error = 0;
01781 struct slot *s;
01782 char *k_param;
01783 struct daemon_id did;
01784 int temp_length;
01785 int temp_int;
01786
01787 if (ptr == NULL || xp_id == NULL)
01788 return XP_ERROR_FAULT;
01789
01790 did.xp_id = call_xp_id_copy(xp_id);
01791 did.unique = -1;
01792
01793 switch (cmd)
01794 {
01795 case IOCTL_GET_AN_ACCESS:
01796
01797
01798
01799
01800
01801
01802 user_request12 = (struct access_compat12 *)ptr;
01803
01804 error = call_xp_verify_user_writable(user_request12, sizeof(struct access_compat12));
01805 if (error)
01806 {
01807 error = XP_ERROR_FAULT;
01808 break;
01809 }
01810
01811
01812 s = dazuko_get_an_access(&did);
01813
01814 if (s == NULL)
01815 {
01816 error = XP_ERROR_INTERRUPT;
01817 break;
01818 }
01819
01820
01821
01822
01823
01824
01825 if (s->filenamelength >= DAZUKO_FILENAME_MAX_LENGTH_COMPAT12)
01826 {
01827
01828
01829 s->filename[DAZUKO_FILENAME_MAX_LENGTH_COMPAT12 - 1] = 0;
01830 temp_length = DAZUKO_FILENAME_MAX_LENGTH_COMPAT12;
01831 }
01832 else
01833 {
01834 temp_length = s->filenamelength + 1;
01835 }
01836
01837 temp_request12 = (struct access_compat12 *)call_xp_malloc(sizeof(struct access_compat12));
01838 if (temp_request12 == NULL)
01839 {
01840 error = XP_ERROR_FAULT;
01841 }
01842 else if (call_xp_copyin(user_request12, temp_request12, sizeof(struct access_compat12)) != 0)
01843 {
01844 error = XP_ERROR_FAULT;
01845 }
01846
01847 if (error == 0)
01848 {
01849 temp_request12->event = s->event;
01850 temp_request12->o_flags = s->event_p.flags;
01851 temp_request12->o_mode = s->event_p.mode;
01852 temp_request12->uid = s->event_p.uid;
01853 temp_request12->pid = s->event_p.pid;
01854 memcpy(temp_request12->filename, s->filename, temp_length);
01855
01856 if (call_xp_copyout(temp_request12, user_request12, sizeof(struct access_compat12)) != 0)
01857 {
01858 error = XP_ERROR_FAULT;
01859 }
01860 }
01861
01862 call_xp_up(&(s->mutex));
01863
01864
01865 if (error)
01866 {
01867 dazuko_state_error(s, DAZUKO_WORKING);
01868 }
01869
01870 if (temp_request12 != NULL)
01871 {
01872 call_xp_free(temp_request12);
01873 }
01874
01875 break;
01876
01877 case IOCTL_RETURN_ACCESS:
01878
01879
01880
01881
01882 user_request12 = (struct access_compat12 *)ptr;
01883
01884 error = call_xp_verify_user_readable(user_request12, sizeof(struct access_compat12));
01885 if (error)
01886 {
01887 error = XP_ERROR_FAULT;
01888 break;
01889 }
01890
01891 temp_request12 = (struct access_compat12 *)call_xp_malloc(sizeof(struct access_compat12));
01892 if (temp_request12 == NULL)
01893 {
01894 error = XP_ERROR_FAULT;
01895 break;
01896 }
01897
01898 if (call_xp_copyin(user_request12, temp_request12, sizeof(struct access_compat12)) != 0)
01899 {
01900 error = XP_ERROR_FAULT;
01901 }
01902
01903 temp_int = temp_request12->deny;
01904
01905 call_xp_free(temp_request12);
01906
01907 error = dazuko_return_access(&did, temp_int, NULL);
01908 break;
01909
01910 case IOCTL_SET_OPTION:
01911
01912
01913
01914 error = call_xp_verify_user_readable(ptr, 2*sizeof(int));
01915 if (error)
01916 {
01917 error = XP_ERROR_FAULT;
01918 break;
01919 }
01920
01921
01922 if (call_xp_copyin(ptr, &temp_int, sizeof(int)) != 0)
01923 {
01924 error = XP_ERROR_FAULT;
01925 break;
01926 }
01927
01928 ptr = ((char *)ptr + sizeof(int));
01929
01930
01931 if (call_xp_copyin(ptr, &temp_length, sizeof(int)) != 0)
01932 {
01933 error = XP_ERROR_FAULT;
01934 break;
01935 }
01936
01937
01938 if (temp_length < 0 || temp_length > 4096)
01939 {
01940 error = XP_ERROR_INVALID;
01941 break;
01942 }
01943
01944 ptr = ((char *)ptr + sizeof(int));
01945
01946 error = call_xp_verify_user_readable(ptr, temp_length);
01947 if (error)
01948 {
01949 error = XP_ERROR_FAULT;
01950 break;
01951 }
01952
01953 k_param = (char *)call_xp_malloc(temp_length + 1);
01954 if (k_param == NULL)
01955 {
01956 error = XP_ERROR_FAULT;
01957 break;
01958 }
01959
01960
01961
01962 if (call_xp_copyin(ptr, k_param, temp_length) != 0)
01963 {
01964 call_xp_free(k_param);
01965 error = XP_ERROR_FAULT;
01966 break;
01967 }
01968
01969 k_param[temp_length] = 0;
01970
01971 if (temp_int == REGISTER)
01972 error = dazuko_register_daemon(&did, k_param, temp_length, 1);
01973 else
01974 error = dazuko_set_option(&did, temp_int, k_param, temp_length);
01975
01976 call_xp_free(k_param);
01977
01978 break;
01979
01980 default:
01981 call_xp_print("dazuko: daemon requested unknown device_ioctl %d (possible bug)\n", cmd);
01982
01983 break;
01984 }
01985
01986 call_xp_id_free(did.xp_id);
01987
01988 return error;
01989 }
01990
01991 static struct slot * dazuko_get_and_hold_ready_slot(struct slot_list *sl)
01992 {
01993
01994
01995
01996
01997
01998
01999
02000
02001 int i;
02002 struct slot *s;
02003
02004 for (i=0 ; i<NUM_SLOTS ; i++)
02005 {
02006 s = &(sl->slots[i]);
02007
02008 if (dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_WAITING, 0))
02009 {
02010
02011 return s;
02012 }
02013 }
02014
02015
02016
02017 return NULL;
02018 }
02019
02020 static int get_ready_slot_condition(void *param)
02021 {
02022 return ((((struct get_ready_slot_condition_param *)param)->slot = dazuko_get_and_hold_ready_slot(((struct get_ready_slot_condition_param *)param)->slotlist)) != NULL
02023 || call_xp_atomic_read(&active) == 0
02024 || call_xp_atomic_read(&(((struct get_ready_slot_condition_param *)param)->slotlist->use_count)) == 0);
02025 }
02026
02027 static int dazuko_run_daemon_on_slotlist(int event, char *filename, int filenamelength, struct event_properties *event_p, struct file_properties *file_p, int prev_response, struct slot_list *sl)
02028 {
02029
02030
02031
02032 int rc;
02033 int unique;
02034 struct slot *s;
02035 struct get_ready_slot_condition_param cond_p1;
02036 struct two_slot_state_not_condition_param cond_p2;
02037
02038 begin:
02039
02040
02041
02042
02043 s = NULL;
02044
02045
02046 cond_p1.slotlist = sl;
02047 cond_p1.slot = s;
02048 if (call_xp_wait_until_condition(&wait_kernel_waiting_for_free_slot, get_ready_slot_condition, &cond_p1, 0) != 0)
02049 {
02050
02051
02052
02053
02054 DPRINT(("dazuko: kernel process %d killed while waiting for free slot\n", event_p->pid));
02055
02056 return -1;
02057 }
02058
02059
02060
02061
02062
02063 s = cond_p1.slot;
02064
02065 if (s == NULL)
02066 {
02067
02068
02069
02070
02071 return 0;
02072 }
02073
02074
02075
02076
02077
02078
02079 unique = s->did.unique;
02080
02081
02082
02083
02084
02085
02086 s->filename = filename;
02087 s->event = event;
02088 s->response = prev_response;
02089 s->filenamelength = filenamelength;
02090
02091 if (event_p == NULL)
02092 dazuko_bzero(&(s->event_p), sizeof(struct event_properties));
02093 else
02094 memcpy(&(s->event_p), event_p, sizeof(struct event_properties));
02095
02096 if (file_p == NULL)
02097 dazuko_bzero(&(s->file_p), sizeof(struct file_properties));
02098 else
02099 memcpy(&(s->file_p), file_p, sizeof(struct file_properties));
02100
02101
02102 call_xp_up(&(s->mutex));
02103
02104
02105
02106 call_xp_notify(&wait_daemon_waiting_for_work);
02107
02108
02109 cond_p2.slot1 = s;
02110 cond_p2.state1 = DAZUKO_WAITING;
02111 cond_p2.slot2 = s;
02112 cond_p2.state2 = DAZUKO_WORKING;
02113 if (call_xp_wait_until_condition(&wait_kernel_waiting_while_daemon_works, two_slot_state_not_condition, &cond_p2, 0) != 0)
02114 {
02115
02116
02117
02118
02119 DPRINT(("dazuko: kernel process %d killed while waiting for daemon response\n", event_p->pid));
02120
02121
02122
02123
02124 dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE, 1);
02125
02126 return -1;
02127 }
02128
02129
02130
02131
02132 if (call_xp_down(&(s->mutex)) != 0)
02133 {
02134 return -1;
02135 }
02136
02137
02138 if (s->did.unique != unique)
02139 {
02140
02141
02142
02143 call_xp_up(&(s->mutex));
02144
02145 goto begin;
02146 }
02147
02148
02149 if (!__dazuko_change_slot_state(s, DAZUKO_DONE, DAZUKO_FREE))
02150 {
02151
02152
02153
02154 call_xp_up(&(s->mutex));
02155
02156 goto begin;
02157 }
02158
02159
02160 rc = s->response;
02161
02162 call_xp_up(&(s->mutex));
02163
02164
02165
02166
02167 return rc;
02168 }
02169
02170 static int dazuko_run_daemon(int event, char *filename, int filenamelength, struct event_properties *event_p, struct file_properties *file_p)
02171 {
02172 struct slot_list *sl;
02173 int i;
02174 int rc = 0;
02175 int error;
02176
02177 if (event_p != NULL)
02178 {
02179
02180 if (event_p->thrown)
02181 return 0;
02182 event_p->thrown = 1;
02183 }
02184
02185 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
02186 {
02187
02188
02189 if (call_xp_down(&(slot_lists[i].mutex)) != 0)
02190 return XP_ERROR_INTERRUPT;
02191
02192 sl = slot_lists[i].slot_list;
02193
02194 call_xp_up(&(slot_lists[i].mutex));
02195
02196
02197 if (sl != NULL)
02198 {
02199 error = dazuko_run_daemon_on_slotlist(event, filename, filenamelength, event_p, file_p, rc, sl);
02200
02201 if (error < 0)
02202 {
02203
02204 rc = error;
02205 break;
02206 }
02207 else if (error > 0)
02208 {
02209
02210 rc = 1;
02211 }
02212 }
02213 }
02214
02215 return rc;
02216 }
02217
02218 inline int dazuko_is_our_daemon(struct xp_daemon_id *xp_id)
02219 {
02220
02221
02222
02223 struct daemon_id did;
02224 int ret;
02225
02226 did.xp_id = call_xp_id_copy(xp_id);
02227 did.unique = -1;
02228
02229 ret = (dazuko_find_slot(&did, 1, NULL) != NULL);
02230
02231 call_xp_id_free(did.xp_id);
02232
02233 return ret;
02234 }
02235
02236 static int dazuko_is_selected(struct dazuko_file_struct *kfs)
02237 {
02238
02239
02240
02241
02242 struct dazuko_file_listnode *cur;
02243 struct path *path;
02244 int selected = 0;
02245 int use_aliases = 1;
02246
02247 if (kfs == NULL)
02248 return 0;
02249
02250
02251
02252
02253
02254 call_xp_read_lock(&lock_lists);
02255
02256 if (kfs->aliases == NULL && kfs->filename != NULL)
02257 {
02258
02259
02260 use_aliases = 0;
02261
02262 kfs->aliases = (struct dazuko_file_listnode *)xp_malloc(sizeof(struct dazuko_file_listnode));
02263 if (kfs->aliases == NULL)
02264 {
02265 call_xp_print("dazuko: warning: access not controlled (%s)\n", kfs->filename);
02266 return 0;
02267 }
02268
02269 dazuko_bzero(kfs->aliases, sizeof(struct dazuko_file_listnode));
02270
02271 kfs->aliases->filename = kfs->filename;
02272 kfs->aliases->filename_length = kfs->filename_length;
02273 }
02274
02275 for (cur=kfs->aliases ; cur ; cur=cur->next)
02276 {
02277 if (cur->filename != NULL && cur->filename_length > 0)
02278 {
02279
02280 for (path=incl_paths ; path ; path=path->next)
02281 {
02282
02283 if (path->len <= cur->filename_length)
02284 {
02285
02286 if (memcmp(path->path, cur->filename, path->len) == 0)
02287 {
02288 kfs->filename = cur->filename;
02289 kfs->filename_length = cur->filename_length;
02290
02291 selected = 1;
02292 break;
02293 }
02294 }
02295 }
02296
02297
02298
02299
02300 if (!selected)
02301 {
02302 continue;
02303 }
02304
02305
02306 for (path=excl_paths ; path ; path=path->next)
02307 {
02308
02309 if (path->len <= cur->filename_length)
02310 {
02311
02312 if (memcmp(path->path, cur->filename, path->len) == 0)
02313 {
02314 kfs->filename = NULL;
02315 kfs->filename_length = 0;
02316
02317 selected = 0;
02318 break;
02319 }
02320 }
02321 }
02322
02323
02324 if (selected)
02325 break;
02326 }
02327 }
02328
02329 call_xp_read_unlock(&lock_lists);
02330
02331
02332 if (!use_aliases)
02333 {
02334 xp_free(kfs->aliases);
02335 kfs->aliases = NULL;
02336 }
02337
02338 return selected;
02339 }
02340
02341 static int dazuko_add_hash(struct xp_file *file, char *filename, int len)
02342 {
02343
02344
02345
02346 struct hash *h;
02347
02348
02349 h = (struct hash *)call_xp_malloc(sizeof(struct hash) + len);
02350 if (h == NULL)
02351 return XP_ERROR_FAULT;
02352
02353
02354
02355 call_xp_copy_file(&(h->file), file);
02356 h->dirty = 0;
02357 h->namelen = len;
02358 memcpy(h->name, filename, len);
02359 h->name[len] = 0;
02360
02361
02362
02363
02364
02365 call_xp_write_lock(&lock_hash);
02366 h->next = hash;
02367 hash = h;
02368 call_xp_write_unlock(&lock_hash);
02369
02370 return 0;
02371 }
02372
02373
02374 static void dazuko_mark_hash_dirty(struct xp_file *file)
02375 {
02376 struct hash *h = NULL;
02377 struct hash *entry = NULL;
02378 struct hash *prev = NULL;
02379 struct hash *prev_entry = NULL;
02380
02381
02382 call_xp_write_lock(&lock_hash);
02383
02384 for (h=hash ; h ; h=h->next)
02385 {
02386
02387 if (h->dirty)
02388 {
02389 entry = NULL;
02390 break;
02391 }
02392
02393 if (call_xp_compare_file(&(h->file), file) == 0)
02394 {
02395
02396
02397 prev_entry = prev;
02398 entry = h;
02399 break;
02400 }
02401
02402 prev = h;
02403 }
02404
02405 if (entry)
02406 {
02407 if (!entry->dirty)
02408 {
02409
02410 entry->dirty = 1;
02411
02412
02413
02414
02415 if (entry->next)
02416 {
02417 if (!entry->next->dirty)
02418 {
02419 for (h=entry->next ; h ; h=h->next)
02420 {
02421 if (h->dirty)
02422 break;
02423
02424 prev = h;
02425 }
02426
02427
02428 if (prev_entry)
02429 prev_entry->next = entry->next;
02430 else
02431 hash = entry->next;
02432
02433 if (prev == NULL)
02434 {
02435
02436 entry->next = hash;
02437 hash = entry;
02438 }
02439 else if (h)
02440 {
02441
02442 entry->next = prev->next;
02443 prev->next = entry;
02444 }
02445 else
02446 {
02447
02448 entry->next = NULL;
02449 prev->next = entry;
02450 }
02451 }
02452 }
02453 }
02454 }
02455
02456 call_xp_write_unlock(&lock_hash);
02457
02458
02459 }
02460
02461 static struct hash *dazuko_get_hash(struct xp_file *file)
02462 {
02463
02464
02465
02466
02467 struct hash *prev;
02468 struct hash *cur;
02469
02470
02471 call_xp_write_lock(&lock_hash);
02472
02473 prev = NULL;
02474 cur = hash;
02475 while (cur)
02476 {
02477 if (call_xp_compare_file(&(cur->file), file) == 0)
02478 {
02479
02480
02481
02482 if (!prev)
02483 hash = cur->next;
02484 else
02485 prev->next = cur->next;
02486 break;
02487 }
02488
02489 prev = cur;
02490 cur = cur->next;
02491 }
02492
02493 call_xp_write_unlock(&lock_hash);
02494
02495
02496 return cur;
02497 }
02498
02499 inline int dazuko_get_filename_length(char *filename)
02500 {
02501 int len;
02502
02503 for (len=0 ; filename[len] ; len++);
02504
02505 return len;
02506 }
02507
02508 static int dazuko_should_scan(struct dazuko_file_struct *kfs)
02509 {
02510
02511
02512
02513
02514
02515 int result = 0;
02516
02517
02518 switch (kfs->should_scan)
02519 {
02520
02521
02522
02523
02524
02525 case 1:
02526
02527 return 1;
02528
02529 case 2:
02530
02531 return 0;
02532 }
02533
02534
02535 if (call_xp_fill_file_struct(kfs) == 0)
02536 {
02537 if (dazuko_is_selected(kfs))
02538 {
02539
02540
02541
02542
02543
02544
02545 kfs->should_scan = 1;
02546
02547 result = 1;
02548 }
02549 else
02550 {
02551
02552
02553
02554
02555
02556 kfs->should_scan = 2;
02557 }
02558 }
02559
02560 return result;
02561 }
02562
02563 inline int dazuko_sys_check(unsigned long event, int daemon_is_allowed, struct xp_daemon_id *xp_id)
02564 {
02565
02566 switch (event)
02567 {
02568 case DAZUKO_ON_OPEN:
02569
02570
02571
02572 if ((SCAN_ON_OPEN || SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED) == 0)
02573 return -1;
02574 break;
02575
02576 case DAZUKO_ON_CLOSE:
02577
02578
02579 if ((SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED) == 0)
02580 return -1;
02581 break;
02582
02583 default:
02584 if ((access_mask & event) == 0)
02585 return -1;
02586 break;
02587 }
02588
02589
02590 if (call_xp_atomic_read(&active) <= 0)
02591 return -1;
02592
02593
02594 if (daemon_is_allowed)
02595 {
02596 if (dazuko_is_our_daemon(xp_id))
02597 {
02598
02599
02600
02601 return -1;
02602 }
02603 }
02604
02605 return 0;
02606 }
02607
02608 inline int dazuko_sys_pre(unsigned long event, struct dazuko_file_struct *kfs, struct xp_file *file, struct event_properties *event_p)
02609 {
02610
02611
02612
02613
02614
02615
02616 int error = 0;
02617 struct hash *h = NULL;
02618
02619 switch (event)
02620 {
02621 case DAZUKO_ON_OPEN:
02622
02623
02624
02625 if (!SCAN_ON_OPEN)
02626 return 0;
02627 break;
02628
02629 case DAZUKO_ON_CLOSE:
02630
02631
02632 return 0;
02633
02634 case DAZUKO_ON_CLOSE_MODIFIED:
02635
02636
02637 return 0;
02638
02639 default:
02640 break;
02641 }
02642
02643 if (kfs == NULL)
02644 {
02645
02646
02647 call_xp_print("dazuko: kfs=NULL (possible bug)\n");
02648
02649 return XP_ERROR_PERMISSION;
02650 }
02651
02652 if (file != NULL)
02653 {
02654
02655
02656
02657 call_xp_read_lock(&lock_hash);
02658
02659 for (h=hash ; h ; h=h->next)
02660 {
02661 if (call_xp_compare_file(&(h->file), file) == 0)
02662 {
02663
02664
02665 kfs->filename = (char*)call_xp_malloc(h->namelen + 1);
02666 if (kfs->filename != NULL)
02667 {
02668 memcpy(kfs->filename, h->name, h->namelen);
02669 kfs->filename[h->namelen] = 0;
02670 kfs->filename_length = h->namelen;
02671 kfs->should_scan = 1;
02672 }
02673 else
02674 {
02675
02676 h = NULL;
02677 }
02678 break;
02679 }
02680 }
02681
02682 call_xp_read_unlock(&lock_hash);
02683
02684
02685 if (h == NULL && kfs->extra_data == NULL)
02686 {
02687
02688
02689
02690
02691
02692 kfs->should_scan = 2;
02693
02694 return 0;
02695 }
02696 }
02697
02698
02699 if (dazuko_should_scan(kfs))
02700 {
02701 error = dazuko_run_daemon(event, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p));
02702 }
02703
02704 if (error > 0)
02705 {
02706
02707
02708
02709
02710 return XP_ERROR_PERMISSION;
02711 }
02712 else if (error < 0)
02713 {
02714
02715
02716
02717
02718 return XP_ERROR_INTERRUPT;
02719 }
02720
02721
02722
02723 return 0;
02724 }
02725
02726 inline int dazuko_sys_post(unsigned long event, struct dazuko_file_struct *kfs, struct xp_file *file, struct event_properties *event_p)
02727 {
02728 struct hash *h = NULL;
02729
02730 switch (event)
02731 {
02732 case DAZUKO_ON_OPEN:
02733
02734
02735
02736 if ((call_xp_atomic_read(&active) > 0) && file != NULL && kfs != NULL)
02737 {
02738 if (SCAN_ON_OPEN || SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED)
02739 {
02740
02741 if (dazuko_should_scan(kfs))
02742 {
02743
02744 if (file != NULL)
02745 dazuko_add_hash(file, kfs->filename, kfs->filename_length);
02746
02747
02748 dazuko_run_daemon(event, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p));
02749 }
02750 }
02751 }
02752 break;
02753
02754 case DAZUKO_ON_CLOSE:
02755 if (file != NULL)
02756 {
02757
02758 h = dazuko_get_hash(file);
02759
02760
02761
02762 if (h != NULL)
02763 {
02764
02765
02766
02767
02768 if (SCAN_ON_CLOSE_MODIFIED && h->dirty)
02769 dazuko_run_daemon(DAZUKO_ON_CLOSE_MODIFIED, h->name, h->namelen, event_p, NULL);
02770 else if (SCAN_ON_CLOSE)
02771 dazuko_run_daemon(DAZUKO_ON_CLOSE, h->name, h->namelen, event_p, NULL);
02772
02773
02774 call_xp_free(h);
02775 }
02776 }
02777 else
02778 {
02779 if (SCAN_ON_CLOSE)
02780 {
02781 if (dazuko_should_scan(kfs))
02782 {
02783 dazuko_run_daemon(DAZUKO_ON_CLOSE, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p));
02784 }
02785 }
02786 }
02787 break;
02788
02789 case DAZUKO_ON_CLOSE_MODIFIED:
02790 if (file != NULL)
02791 {
02792
02793
02794
02795
02796 dazuko_mark_hash_dirty(file);
02797 }
02798 break;
02799
02800 default:
02801 break;
02802 }
02803
02804 return 0;
02805 }
02806
02807 inline int dazuko_init(void)
02808 {
02809 int i;
02810 int error;
02811
02812 call_xp_init_mutex(&mutex_unique_count);
02813
02814 call_xp_init_rwlock(&lock_hash);
02815 call_xp_init_rwlock(&lock_lists);
02816
02817 call_xp_init_queue(&wait_kernel_waiting_for_free_slot);
02818 call_xp_init_queue(&wait_daemon_waiting_for_work);
02819 call_xp_init_queue(&wait_kernel_waiting_while_daemon_works);
02820 call_xp_init_queue(&wait_daemon_waiting_for_free);
02821
02822 dazuko_bzero(&slot_lists, sizeof(slot_lists));
02823
02824 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
02825 call_xp_init_mutex(&(slot_lists[i].mutex));
02826
02827 call_xp_atomic_set(&active, 0);
02828
02829 error = call_xp_sys_hook();
02830
02831 if (error == 0)
02832 call_xp_print("dazuko: loaded, version=%s\n", VERSION);
02833
02834 return error;
02835 }
02836
02837 inline int dazuko_exit(void)
02838 {
02839 int error;
02840 int i;
02841 int j;
02842
02843 i = call_xp_atomic_read(&active);
02844
02845 if (i != 0)
02846 {
02847 call_xp_print("dazuko: warning: trying to remove Dazuko with %d process%s still registered\n", i, i==1 ? "" : "es");
02848 return -1;
02849 }
02850
02851 dazuko_remove_all_paths();
02852 dazuko_remove_all_hash();
02853
02854 error = call_xp_sys_unhook();
02855
02856 if (error == 0)
02857 {
02858 call_xp_destroy_mutex(&mutex_unique_count);
02859
02860 call_xp_destroy_rwlock(&lock_hash);
02861 call_xp_destroy_rwlock(&lock_lists);
02862
02863 call_xp_destroy_queue(&wait_kernel_waiting_for_free_slot);
02864 call_xp_destroy_queue(&wait_daemon_waiting_for_work);
02865 call_xp_destroy_queue(&wait_kernel_waiting_while_daemon_works);
02866 call_xp_destroy_queue(&wait_daemon_waiting_for_free);
02867
02868 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
02869 {
02870 if (slot_lists[i].slot_list != NULL)
02871 {
02872 if (call_xp_atomic_read(&(slot_lists[i].slot_list->use_count)) != 0)
02873 call_xp_print("dazuko: slot_list count was not 0 (possible bug)\n");
02874
02875 for (j=0 ; j<NUM_SLOTS ; j++)
02876 {
02877 call_xp_destroy_mutex(&(slot_lists[i].slot_list->slots[j].mutex));
02878 }
02879
02880 call_xp_free(slot_lists[i].slot_list);
02881 slot_lists[i].slot_list = NULL;
02882 }
02883
02884 call_xp_destroy_mutex(&(slot_lists[i].mutex));
02885 }
02886
02887 call_xp_print("dazuko: unloaded, version=%s\n", VERSION);
02888 }
02889
02890 return error;
02891 }