/* * $Id: update.c,v 1.6 2002/10/17 20:02:32 ljb Exp $ * originally Id: update.c,v 1.46 1998/07/29 21:15:18 gerald Exp */ #include #include #include "mrt.h" #include "trace.h" #include #include #include "config_file.h" #include #include "irrd.h" #include "irrd_prototypes.h" extern trace_t *default_trace; static int build_secondary_keys (irr_database_t *db, irr_object_t *object); void mark_deleted_irr_object (irr_database_t *database, u_long offset) { char *xx = "*xx"; if (fseek (database->db_fp, offset, SEEK_SET) < 0) { perror ("seek error"); trace (NORM, default_trace, "** Error ** fseek failed in mark_deleted"); } if (fwrite (xx, 1, 3, database->db_fp) == 0) perror ("frwite failed"); fflush (database->db_fp); } void add_spec_keys (irr_database_t *db, irr_object_t *object) { char *maint, *as_set, new_key[BUFSIZE]; if (object->ll_mbr_of == NULL) return; /* this key is for (maint|as-set) hash lookups from set objects */ if (object->ll_mnt_by != NULL) { LL_ContIterate (object->ll_mnt_by, maint) { LL_ContIterate (object->ll_mbr_of, as_set) { make_spec_key (new_key, maint, as_set); if (object->mode == IRR_DELETE) memory_hash_spec_remove (db, new_key, SET_MBRSX, object->name); else memory_hash_spec_store (db, new_key, SET_MBRSX, object); } } } /* add this key for fast ANY lookups */ LL_ContIterate (object->ll_mbr_of, as_set) { make_spec_key (new_key, NULL, as_set); if (object->mode == IRR_DELETE) memory_hash_spec_remove (db, new_key, SET_MBRSX, object->name); else memory_hash_spec_store (db, new_key, SET_MBRSX, object); } } /* load_irr_object * We need to find an object before we can delete it * Basically, we need to fill in the object structure (with all of the old keys) */ irr_object_t *load_irr_object (irr_database_t *database, irr_object_t *irr_object) { irr_object_t *old_irr_object = NULL; int ret; u_long offset, len; /* route objects are special because we need both the key AND the autnum */ if (irr_object->type == ROUTE) ret = seek_route_object (database, irr_object->name, irr_object->origin, &offset, &len, 1); else /* fill in object->offset and object->len */ ret = find_object_offset_len (database, irr_object->name, irr_object->type, &offset, &len); /* object doesn't really exist -- nothing to delete */ if (ret < 1) return (NULL); /* JW: I'm wondering about locking? Should we lock? */ if (fseek(database->db_fp, offset, SEEK_SET) < 0) trace (NORM, default_trace, "** Error ** fseek failed in load_irr_obj"); old_irr_object = (irr_object_t *) scan_irr_file_main (database->db_fp, database, 0, SCAN_OBJECT); if (old_irr_object) old_irr_object->offset = offset; return (old_irr_object); } /* irr_special_indexing_store * store "special" keys, or keys that we cannot just dump into the * the generic hash table. These include route and inetnum objects (which * need special radix magic). * * return 1 is we still need to store this object in the hash */ int irr_special_indexing_store (irr_database_t *database, irr_object_t *irr_object) { char *key, key_buf[BUFSIZE], str_origin[16]; int store_hash = 1; /* first add/delete object from hash associated with maintainers */ if (irr_object->ll_mnt_by != NULL) { LL_ContIterate (irr_object->ll_mnt_by, key) { make_mntobj_key (key_buf, key); if (irr_object->mode == IRR_DELETE) memory_hash_spec_remove (database, key_buf, MNTOBJS, &irr_object->offset); else memory_hash_spec_store (database, key_buf, MNTOBJS, irr_object); } } switch (irr_object->type) { case ROUTE: add_spec_keys (database, irr_object); sprintf (str_origin, "%d", irr_object->origin); make_gas_key (key_buf, str_origin); if (irr_object->mode == IRR_DELETE) { memory_hash_spec_remove (database, key_buf, GASX, irr_object->name); delete_irr_route (database, irr_object->name, irr_object); } else { if (!irr_object->withdrawn) memory_hash_spec_store (database, key_buf, GASX, irr_object); add_irr_route (database, irr_object->name, irr_object); } store_hash = 0; break; case AUT_NUM: add_spec_keys (database, irr_object); break; case IPV6_SITE: LL_Iterate (irr_object->ll_prefix, key) { if (irr_object->mode == IRR_DELETE) delete_irr_route (database, key, irr_object); else add_irr_route (database, key, irr_object); } store_hash = 0; break; case AS_SET: case RS_SET: make_setobj_key (key_buf, irr_object->name); if (irr_object->mode == IRR_DELETE) memory_hash_spec_remove (database, key_buf, SET_OBJX, NULL); else memory_hash_spec_store (database, key_buf, SET_OBJX, irr_object); break; default: store_hash = 1; break; } return (store_hash); } void back_out_secondaries (irr_database_t *db, irr_object_t *object, char *buf) { char *p, *q; for (q = buf; (p = strchr (q, ' ')) != NULL; q = p) { *p++ = '\0'; irr_database_remove (db, q, SECONDARY, object->type, object->offset, object->len); } } /* JW It looks like the irr_database_store () routine allows * duplicate PRIMARY keys. Need to fix so it returns * an error */ /* Given a PERSON object, make its secondary keys and it's complete * 'person: nic-hdl:' key (which is a primary key). So this routine * inappropriately named. * * Return: * void */ int build_secondary_keys (irr_database_t *db, irr_object_t *object) { char buf[256], buf1[256], *cp, *last, *p; int n = 0, ret_code = 1; int (*func)(irr_database_t *, char *, u_short, enum IRR_OBJECTS, u_long, u_long); switch (object->type) { case PERSON: if (object->mode == IRR_DELETE) func = &irr_database_remove; else func = &irr_database_store; p = buf; strcpy (buf1, object->name); cp = buf1; strtok_r (cp, " ", &last); while (cp != NULL) { whitespace_remove (cp); if ((ret_code = (*func) (db, cp, SECONDARY, object->type, object->offset, object->len)) < 0) { /* an error occured, remove any secondary key's we have added */ if (object->mode != IRR_DELETE) { if (p != buf) { *p++ = ' '; *p = '\0'; back_out_secondaries (db, object, buf); } break; } } n = strlen (cp); if (p != buf) *p++ = ' '; memcpy (p, cp, n); p += n; cp = strtok_r (NULL, " ", &last); } if (object->nic_hdl) { n = strlen (object->nic_hdl); *p++ = ' '; memcpy (p, object->nic_hdl, n); *(p + n) = '\0'; if ((ret_code = (*func) (db, buf, PRIMARY, object->type, object->offset, object->len)) < 0) { if (object->mode != IRR_DELETE) { *p = '\0'; back_out_secondaries (db, object, buf); } } else if ((*func) (db, object->nic_hdl, SECONDARY, object->type, object->offset, object->len) < 0 && object->mode != IRR_DELETE) { ret_code = -1; irr_database_remove (db, buf, PRIMARY, object->type, object->offset, object->len); } } break; default: break; } return ret_code; } /* scan_process_object * We have scanned an entire object from the db, update, journal, whatever file * Now process the darn thing */ int add_irr_object (irr_database_t *database, irr_object_t *irr_object) { long svoffset = 0, offset; int ret_code = 1, store_hash = 0; /* if update (e.g. mirror or user update), save to end of main database */ /* append the new object to the end of the db file */ if (irr_object->mode == IRR_UPDATE) { offset = copy_irr_object (irr_object->fp, (long) irr_object->offset, database, irr_object->len); if (offset < 0) { trace (ERROR, default_trace, "DB (%s) file error, could not add object (%s) to EOF\n", database->name, irr_object->name); return -1; } svoffset = irr_object->offset; irr_object->offset = (u_long) offset; } /* deal with primary key; JW later need to change to detect error */ store_hash = irr_special_indexing_store (database, irr_object); if (store_hash) { if ((ret_code = irr_database_store (database, irr_object->name, PRIMARY, irr_object->type, irr_object->offset, irr_object->len)) > 0) { /* Routine will build the PERSON secondary and 'person: hic-hdl:' primary key */ if (irr_object->type == PERSON && (ret_code = build_secondary_keys (database, irr_object)) < 0) irr_database_remove (database, irr_object->name, PRIMARY, irr_object->type, irr_object->offset, irr_object->len); } } if (irr_object->mode == IRR_UPDATE) { if (ret_code > 0) trace (NORM, default_trace, "Object %s added\n", irr_object->name); else trace (ERROR, default_trace, "ERROR: Disk or indexing error: key (%s)\n", irr_object->name); } /* statistics */ if (ret_code > 0) { database->num_objects[irr_object->type]++; database->bytes += irr_object->len; } if (irr_object->mode == IRR_UPDATE) irr_object->offset = svoffset; return ret_code; } /* delete_irr_object * First, load the current version of the object. We need to check a) that it * exists, and b) we need to get the current offset/len and the secondary keys * Once we have all of this, delete the indicies, mark the database file on disk */ int delete_irr_object (irr_database_t *database, irr_object_t *irr_object, u_long *db_offset) { int ret_code = 1, store_hash = 0; irr_object_t *stored_irr_object; if ((stored_irr_object = load_irr_object (database, irr_object)) == NULL) { if (irr_object->mode == IRR_DELETE) trace (NORM, default_trace, "Object %s not found -- delete failed\n", irr_object->name); return -1; } /* remove the special indexes for this object */ stored_irr_object->mode = IRR_DELETE; store_hash = irr_special_indexing_store (database, stored_irr_object); if (store_hash) { if ((ret_code = irr_database_remove (database, irr_object->name, PRIMARY, stored_irr_object->type, stored_irr_object->offset, stored_irr_object->len)) > 0) if (stored_irr_object->type == PERSON && (ret_code = build_secondary_keys (database, stored_irr_object)) < 0) irr_database_store (database, irr_object->name, PRIMARY, stored_irr_object->type, stored_irr_object->offset, stored_irr_object->len); } /* statistics */ if (ret_code > 0) { database->num_objects[irr_object->type]--; *db_offset = stored_irr_object->offset; trace (NORM, default_trace, "Object %s deleted!\n", irr_object->name); } /* release memory */ Delete_IRR_Object (stored_irr_object); return ret_code; }