diff --git a/src/bee-dep.c b/src/bee-dep.c index 54d77cf..27b981f 100644 --- a/src/bee-dep.c +++ b/src/bee-dep.c @@ -24,466 +24,830 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#define _GNU_SOURCE - #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <string.h> #include <limits.h> #include <dirent.h> -#include <sys/file.h> #include <libgen.h> #include <unistd.h> #include <getopt.h> -#include <errno.h> -#include <assert.h> +#include <fcntl.h> #include "graph.h" #define CACHENAME "index.db" +#define TMPNAME "index.tmp" +#define LOCKNAME "index.lock" + +#define REBUILD 1 +#define UPDATE 2 +#define REMOVE 3 +#define LIST 4 +#define CONFLICTS 5 -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) +static char *bee_version(void) +{ + static char *bee_v = NULL; -#define BEE_METADIR env_bee_metadir() -#define BEE_CACHEDIR env_bee_cachedir() + if (!bee_v) + bee_v = getenv("BEE_VERSION"); + + return bee_v; +} -static char *env_bee_metadir(void) +static char *bee_metadir(void) { - static char *value = NULL; + static char *bee_md = NULL; - if(value) - return value; + if (!bee_md) + bee_md = getenv("BEE_METADIR"); - value = getenv("BEE_METADIR"); + return bee_md; +} + +static char *bee_cachedir(void) +{ + static char *bee_cd = NULL; - if(!value) - value = ""; + if (!bee_cd) + bee_cd = getenv("BEE_CACHEDIR"); - return value; + return bee_cd; } -static char *env_bee_cachedir(void) +static void get_bee_variables(void) { - static char *value = NULL; + if (!bee_version()) { + fprintf(stderr, "BEE-ERROR: please call bee-dep from bee\n"); + exit(1); + } + + if (!bee_metadir()) { + fprintf(stderr, "BEE-ERROR: BEE_METADIR not set\n"); + exit(1); + } + + if (!bee_cachedir()) { + fprintf(stderr, "BEE_ERROR: BEE_CACHEDIR not set\n"); + exit(1); + } +} + +static char *cache_filename(void) +{ + static char cache[PATH_MAX + 1] = {0}; + + if (!cache[0]) + sprintf(cache, "%s/%s", bee_cachedir(), CACHENAME); + + return cache; +} - if(value) - return value; +static char *lock_filename(void) +{ + static char lock[PATH_MAX + 1] = {0}; - value = getenv("BEE_CACHEDIR"); + if (!lock[0]) + sprintf(lock, "%s/%s", bee_cachedir(), LOCKNAME); - if(!value) - value = ""; + return lock; +} - return value; +static void usage_header(void) +{ + printf("bee-dep v%s 2011\n" + " by Matthias Ruester and Lucas Schwass\n" + " Max Planck Institute for Molecular Genetics Berlin Dahlem\n\n", + getenv("BEE_VERSION")); } static void usage(void) { - printf("bee-dep v%s 2011\n" - " by Matthias Ruester and Lucas Schwass\n" - " Max Planck Institute for Molecular Genetics Berlin Dahlem\n\n" - - "Usage: bee dep <OPTION> [PKGNAME]\n\n" - - "Options:\n" - " --rebuild rebuild the cache\n" - " --update <PKGNAME> update the cache\n" - " --print-removable <PKGNAME> print removable files " - "from package\n" - " --remove <PKGNAME> remove package from cache\n", - getenv("BEE_VERSION")); + usage_header(); + printf("Usage: bee dep <command> [<args>]\n\n" + + "Commands:\n" + " rebuild rebuild the cache\n" + " update update the cache for a specific package\n" + " remove remove a package from the cache\n" + " list list information\n" + " conflicts show conflicting packages\n"); } -int pkg_to_graph(struct hash *graph, char *pkgname) +static void usage_rebuild(void) { - int ret = 1; - char *fname; + usage_header(); + printf("Usage: bee dep rebuild\n"); +} - if(asprintf(&fname, "%s/%s/DEPENDENCIES", BEE_METADIR, pkgname) == -1) { - perror("bee-dep: pkg_to_graph: asprintf"); - return -1; - } +static void usage_update(void) +{ + usage_header(); + printf("Usage: bee dep update [pkgname]\n"); +} + +static void usage_remove(void) +{ + usage_header(); + printf("Usage: bee dep remove [options] <pkgname>\n\n" + + "Options:\n" + " --print print which files can be deleted from the hard drive\n"); +} + +static void usage_list(void) +{ + usage_header(); + printf("Usage: bee dep list [options]\n\n" + + "Options:\n" + " --packages\n" + " --files <pkg>\n" + " --depending-on <pkg|file>\n" + " --required-by <pkg|file>\n" + " --removable <pkg>\n" + " --provider-of <file>\n" + " --count\n"); +} + +static void usage_conflicts(void) +{ + usage_header(); + printf("Usage: bee dep conflicts [pkgname]\n"); +} + +void ensure_directories(void) +{ + char *c; + int i; + char dir[PATH_MAX + 1] = {0}; + struct stat st; + + c = bee_cachedir(); + i = 0; + + while (*c) { + dir[i] = *c; + c++; - ret = graph_insert_nodes(graph, fname); + if (*c == '/' || !(*c)) { + if (stat(dir, &st) == -1 && mkdir(dir, 0755) == -1) { + perror("mkdir"); + exit(1); + } + } - free(fname); - return ret; + i++; + } } -int init_cache(struct hash *graph, char *filename) +static struct hash *init_cache(void) { struct dirent **package; int i, pkg_cnt; + char path[PATH_MAX + 1]; + struct stat st; + struct hash *graph; - /* TODO: need to handle all kinds of race conditions here 8) */ - - if ((pkg_cnt = scandir(BEE_METADIR, &package, 0, alphasort)) < 0) { - perror("bee-dep: create_cache: scandir"); - return 0; + if ((pkg_cnt = scandir(bee_metadir(), &package, 0, alphasort)) < 0) { + perror("bee-dep: init_cache: scandir"); + return NULL; } + graph = hash_new(); + /* skip . and .. */ free(package[0]); free(package[1]); for (i = 2; i < pkg_cnt; i++) { - pkg_to_graph(graph, package[i]->d_name); + sprintf(path, "%s/%s", bee_metadir(), package[i]->d_name); + + if (stat(path, &st) == -1) { + perror("bee-dep: init_cache: stat"); + hash_free(graph); + return NULL; + } + + if (S_ISDIR(st.st_mode)) { + strcat(path, "/DEPENDENCIES"); + + if (stat(path, &st) == -1) { + fprintf(stderr, + "bee-dep: init_cache: missing " + "DEPENDENCIES file for package \"%s\"\n", + package[i]->d_name); + hash_free(graph); + return NULL; + } + + if (graph_insert_nodes(graph, path)) { + hash_free(graph); + return NULL; + } + } + free(package[i]); } free(package); - return save_cache(graph, filename); + if (save_cache(graph, cache_filename())) { + hash_free(graph); + return NULL; + } + + return graph; } -void unlock(FILE *cache) +static int update_cache(struct hash *graph) { - if (flock(fileno(cache), LOCK_UN) == -1) { - perror("bee-dep: unlock: flock"); - exit(EXIT_FAILURE); - } + struct dirent **package; + int i, pkg_cnt; + char path[PATH_MAX + 1]; + struct stat st; + struct tree_node *t; - if (fclose(cache) == EOF) { - perror("bee-dep: unlock: fclose"); - exit(EXIT_FAILURE); + if ((pkg_cnt = scandir(bee_metadir(), &package, 0, alphasort)) < 0) { + perror("bee-dep: update_cache: scandir"); + return 1; } -} -void cleanup_and_exit(struct hash *h, FILE *f, int r) -{ - if (h) - hash_free(h); + /* skip . and .. */ + free(package[0]); + free(package[1]); - if (f) - unlock(f); + /* add new (not known) packages */ + for (i = 2; i < pkg_cnt; i++) { + if (hash_search(graph, package[i]->d_name)) + continue; - exit(r); -} + printf("adding %s\n", package[i]->d_name); -static FILE *open_and_lock(char *filename, char *mode) -{ - FILE *f; + if (sprintf(path, "%s/%s", bee_metadir(), package[i]->d_name) < 0) { + perror("bee-dep: update_cache: sprintf"); + return 1; + } + + if (stat(path, &st) == -1) { + perror("bee-dep: update_cache: stat"); + return 1; + } + + if (S_ISDIR(st.st_mode)) { + strcat(path, "/DEPENDENCIES"); - if ((f = fopen(filename, mode)) == NULL) { - perror("bee-dep: fopen"); - exit(EXIT_FAILURE); + if (stat(path, &st) == -1) { + fprintf(stderr, + "bee-dep: update_cache: missing " + "DEPENDENCIES file for package \"%s\"\n", + package[i]->d_name); + return 1; + } + + if (graph_insert_nodes(graph, path)) + return 1; + } + + free(package[i]); } - if (flock(fileno(f), LOCK_EX) == -1) { - perror("bee-dep: flock"); - exit(EXIT_FAILURE); + free(package); + + /* remove packages which not exist anymore */ + for (i = 0; i < TBLSIZE; i++) { + t = tree_first(graph->tbl[i]->root); + + while (t) { + if (IS_PKG(t->n)) { + if (sprintf(path, "%s/%s", bee_metadir(), t->n->name) < 0) { + perror("bee-dep: update_cache: sprintf"); + return 1; + } + + if (stat(path, &st) == -1) { + printf("removing %s\n", t->n->name); + + if (remove_package(graph, t->n->name)) + return 1; + } + } + + t = tree_next(t); + } } - return f; + return 0; } -/* create all directories in path with mode mode */ -int mkdirp(char *path, mode_t mode) +struct hash *get_cache(void) { - char *dir, *pdir, *end; - int ret; + struct hash *graph; + struct stat st; - assert(path); + if (stat(cache_filename(), &st) == -1) + graph = init_cache(); + else + graph = load_cache(cache_filename()); - dir = end = path; + if (!graph) + exit(1); - while(*dir) { - /* skip "/" */ - dir = end + strspn(end, "/"); + return graph; +} - /* skip non-"/" */ - end = dir + strcspn(dir, "/"); +static int bee_dep_rebuild(int argc, char *argv[]) +{ + int c, help; + struct hash *graph; + struct option long_options[] = { + {"help", 0, &help, 1}, + {0, 0, 0, 0} + }; - /* grab everything in path till current end */ - if(!(pdir = strndup(path, end - path))) - return -1; + help = 0; + + while ((c = getopt_long(argc, argv, "", long_options, NULL)) != -1) { + switch (c) { + case '?': + usage_update(); + return 1; + } + } - /* create the directory ; ignore err if it already exists */ - ret = mkdir(pdir, mode); + if (help) { + usage_rebuild(); + return 0; + } - free(pdir); + if (argc > 1) { + fprintf(stderr, "bee-dep: too many arguments\n"); + return 1; + } - if(ret == -1 && errno != EEXIST) - return -1; - } + graph = init_cache(); + hash_free(graph); - return 0; + return 0; } -/* - * checks if given filename is a regular file - * returns: - * - * 1 : file exists and is a regular file - * 0 : file is not a regular file or does not exist - * check errno for - * EEXIST : file exists but is not a regular file - * ENOENT : file does not exist - * -1 : error; check errno see(stat(2)) - */ -int regular_file_exists(char *fname) +static int bee_dep_update(int argc, char *argv[]) { + int c, help; + char *pkg; + char path[PATH_MAX + 1]; + struct hash *graph; struct stat st; - int ret; + struct option long_options[] = { + {"help", 0, &help, 1}, + {0, 0, 0, 0} + }; - ret = stat(fname, &st); + help = 0; - if(likely(ret == 0)) { - if(likely(S_ISREG(st.st_mode))) - return 1; + while ((c = getopt_long(argc, argv, "", long_options, NULL)) != -1) { + switch (c) { + case '?': + usage_update(); + return 1; + } + } - /* set errno for file exists but is not a regular file */ - errno = EEXIST; + if (help) { + usage_update(); return 0; } - if (likely(errno == ENOENT)) + if (argc == 1) { + graph = get_cache(); + + if (update_cache(graph) || save_cache(graph, cache_filename())) { + hash_free(graph); + return 1; + } + + hash_free(graph); return 0; + } - return -1; -} + if (argc < 2) { + fprintf(stderr, "bee-dep: pkgname needed\n"); + return 1; + } -char *get_cachefilename(void) -{ - char *cfname; + if (argc > 2) { + fprintf(stderr, "bee-dep: too many arguments\n"); + return 1; + } - if(asprintf(&cfname, "%s/%s", BEE_CACHEDIR, CACHENAME) == -1) { - perror("bee-dep: get_cachefilename"); - return NULL; + pkg = argv[1]; + + if (sprintf(path, "%s/%s/DEPENDENCIES", bee_metadir(), pkg) < 0) { + perror("bee-dep: sprintf"); + return 1; + } + + graph = get_cache(); + + if (stat(path, &st) != -1) { + if (hash_search(graph, pkg)) { + fprintf(stderr, + "bee-dep: package \"%s\" is already in the cache\n", + pkg); + hash_free(graph); + return 0; + } + + if (graph_insert_nodes(graph, path)) { + hash_free(graph); + return 1; + } + } else { + if (remove_package(graph, pkg)) { + hash_free(graph); + return 1; + } } - return cfname; + + if (save_cache(graph, cache_filename())) { + hash_free(graph); + return 1; + } + + hash_free(graph); + return 0; } -int do_rebuild_cachedb(void) +static int bee_dep_remove(int argc, char *argv[]) { - char *cfname; + int c, help, print; struct hash *graph; - int ret; + char *pkg; + struct option long_options[] = { + {"help", 0, &help, 1}, + {"print", 0, &print, 1}, + {0, 0, 0, 0} + }; + + help = print = 0; - cfname = get_cachefilename(); + while ((c = getopt_long(argc, argv, "", long_options, NULL)) != -1) { + switch (c) { + case '?': + usage_remove(); + return 1; + } + } - if (!cfname) + if (help) { + usage_remove(); return 0; + } - graph = hash_new(); + if (optind == argc) { + fprintf(stderr, "bee-dep: pkgname needed\n"); + return 1; + } - if (!graph) { - free(cfname); - return 0; + if (optind < argc - 1) { + fprintf(stderr, "bee-dep: too many arguments\n"); + return 1; } - ret = init_cache(graph, cfname); + pkg = argv[optind]; + graph = get_cache(); - free(cfname); - hash_free(graph); + if (print && print_removable(graph, pkg)) { + hash_free(graph); + return 1; + } - return ret; + if (remove_package(graph, pkg) + || save_cache(graph, cache_filename())) { + hash_free(graph); + return 1; + } + + hash_free(graph); + return 0; } -int main(int argc, char *argv[]) +static int bee_dep_list(int argc, char *argv[]) { - int c, help, rebuild, update, remove, print, options; - int ret; - char *cachefile = NULL; - char *depfile = NULL; - char found; - char *pkgname; + int c, i, opt_count, help, files, packages, count, + depending_on, required_by, removable, provider_of; struct hash *graph; - struct stat st; - FILE *cache = NULL; - struct node *hnode; - + char *name; struct option long_options[] = { - {"help", 0, &help, 1}, - {"rebuild", 0, &rebuild, 1}, - {"update", 0, &update, 1}, - {"remove", 0, &remove, 1}, - {"print-removable", 0, &print, 1}, + {"help", 0, &help, 1}, + {"files", 0, &files, 1}, + {"packages", 0, &packages, 1}, + {"count", 0, &count, 1}, + {"depending-on", 0, &depending_on, 1}, + {"required-by", 0, &required_by, 1}, + {"removable", 0, &removable, 1}, + {"provider-of", 0, &provider_of, 1}, {0, 0, 0, 0} }; - if (!getenv("BEE_VERSION")) { - fprintf(stderr, "BEE-ERROR: please call beedep from bee\n"); - exit(EXIT_FAILURE); - } - - if (argc == 1) { - usage(); - exit(EXIT_FAILURE); - } - - help = rebuild = update = remove = print = options = 0; - pkgname = NULL; + opt_count = help = files = packages = provider_of = + count = depending_on = required_by = removable = 0; while ((c = getopt_long(argc, argv, "", long_options, NULL)) != -1) { switch (c) { case '?': - usage(); - exit(EXIT_FAILURE); - break; + usage_list(); + return 1; default: - options++; + opt_count++; } } if (help) { - usage(); - exit(EXIT_SUCCESS); + usage_list(); + return 0; } - if (argc != optind + !rebuild) { - if (argc > optind + !rebuild) - fprintf(stderr, "bee-dep: too many arguments\n"); - else - fprintf(stderr, "bee-dep: pkgname needed\n"); + if (!opt_count && optind != argc) { + fprintf(stderr, "bee-dep: too many arguments\n"); + return 1; + } + + if (!opt_count) + packages = 1; - exit(EXIT_FAILURE); + if (opt_count > 1 && !count) { + fprintf(stderr, "bee-dep: too many options specified\n"); + return 1; } - if (!rebuild) - pkgname = argv[optind]; + if (packages) { + graph = get_cache(); - if (!options) { - fprintf(stderr, "bee-dep: no option specified\n"); - exit(EXIT_FAILURE); + if (count) + printf("%d\n", count_packages(graph)); + else + list_packages(graph); + + hash_free(graph); + return 0; } - if (options > 1 && (options != 2 || !(remove && print))) { - fprintf(stderr, "bee-dep: too many options specified\n"); - exit(EXIT_FAILURE); + if (optind == argc) { + fprintf(stderr, "bee-dep: arguments needed\n"); + return 1; + } + + if (count && (depending_on || required_by)) + fprintf(stderr, "bee-dep: ignoring option --count\n"); + + graph = get_cache(); + + for (i = optind; i < argc; i++) { + name = argv[i]; + + if (optind < argc - 1) + printf("%s:\n", name); + + if (files) { + if (count) { + c = count_files(graph, name); + + if (c < 0) { + hash_free(graph); + return 1; + } + + printf("%d\n", c); + } else if (list_files(graph, name)) { + hash_free(graph); + return 1; + } + } + + if (removable) { + if (count) { + c = count_removable(graph, name); + + if (c < 0) { + hash_free(graph); + return 1; + } + + printf("%d\n", c); + } else if (print_removable(graph, name)) { + hash_free(graph); + return 1; + } + } + + if (depending_on && print_neededby(graph, name)) { + hash_free(graph); + return 1; + } + + if (required_by && print_needs(graph, name)) { + hash_free(graph); + return 1; + } + + if (provider_of) { + if (count) { + c = count_providers(graph, name); + + if (c < 0) { + hash_free(graph); + return 1; + } + + printf("%d\n", c); + } else if (print_providers(graph, name)) { + hash_free(graph); + return 1; + } + } } - if (mkdirp(BEE_CACHEDIR, 0755) == -1) { - perror("bee-dep: mkdirp"); - exit(EXIT_FAILURE); + hash_free(graph); + return 0; +} + +static int bee_dep_conflicts(int argc, char *argv[]) +{ + int c, opt_count, help; + struct hash *graph; + struct option long_options[] = { + {"help", 0, &help, 1}, + {0, 0, 0, 0} + }; + + help = opt_count = 0; + + while ((c = getopt_long(argc, argv, "", long_options, NULL)) != -1) { + switch (c) { + case '?': + usage_conflicts(); + return 1; + + default: + opt_count++; + } } - if (rebuild) { - if(!do_rebuild_cachedb()) - return EXIT_FAILURE; - return EXIT_SUCCESS; + if (help) { + usage_conflicts(); + return 0; } - if(!(graph = hash_new())) { - perror("bee-dep: hash_new"); - exit(EXIT_FAILURE); + if (optind < argc) { + fprintf(stderr, "bee-dep: too many arguments\n"); + return 1; } - if(!(cachefile = get_cachefilename())) { + graph = get_cache(); + + if (print_conflicts(graph)) { hash_free(graph); - exit(EXIT_FAILURE); + return 1; } + hash_free(graph); + return 0; +} - ret = regular_file_exists(cachefile); +static int get_command(char *command) +{ + if (!strcmp("rebuild", command)) + return REBUILD; - if (ret == -1 || (ret == 0 && errno != ENOENT)) { - perror("bee-dep: regular_file_exists(cachefile)"); - free(cachefile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } else if (ret) { - cache = open_and_lock(cachefile, "r"); + if (!strcmp("update", command)) + return UPDATE; - if (!load_cache(graph, cache)) { - free(cachefile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } - } else { - if (!init_cache(graph, cachefile)) { - free(cachefile); - hash_free(graph); - return EXIT_FAILURE; + if (!strcmp("remove", command)) + return REMOVE; + + if (!strcmp("list", command)) + return LIST; + + if (!strcmp("conflicts", command)) + return CONFLICTS; + + return 0; +} + +static FILE *lockfile(void) +{ + static FILE *file = NULL; + + if (!file) { + ensure_directories(); + + if ((file = fopen(lock_filename(), "w")) == NULL) { + perror("bee-dep: lockfile"); + exit(1); } + + fprintf(file, "locked by pid %d\n", getpid()); + fflush(file); } - hnode = hash_search(graph, pkgname); - found = hnode && IS_PKG(hnode); + return file; +} - if (update) { - if (asprintf(&depfile, "%s/%s/DEPENDENCIES", - BEE_METADIR, pkgname) == -1) { - perror("bee-dep: asprintf"); - free(cachefile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } +void lock(void) +{ + FILE *f; + struct flock flo; - if (stat(depfile, &st) != -1) { - if (hnode) { - fprintf(stderr, "bee-dep: package '%s' is " - "already in the cache\n", pkgname); - free(cachefile); - free(depfile); - cleanup_and_exit(graph, cache, EXIT_SUCCESS); - } + f = lockfile(); - if (!graph_insert_nodes(graph, depfile)) { - free(cachefile); - free(depfile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } - } else { - if (!found) { - fprintf(stderr, - "bee-dep: unknown package '%s'\n", pkgname); - free(cachefile); - free(depfile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } + flo.l_start = flo.l_len = 0; + flo.l_whence = SEEK_SET; + flo.l_type = F_WRLCK; - if (!hnode || !IS_PKG(hnode)) { - fprintf(stderr, "bee-dep: unknown package '%s'\n", pkgname); - free(cachefile); - free(depfile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } + if (fcntl(fileno(f), F_SETLKW, &flo) == -1) { + perror("bee-dep: lock"); + exit(1); + } +} - if (remove_package(graph, pkgname) == EXIT_FAILURE) - free(cachefile); - free(depfile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } +void unlock(void) +{ + FILE *f; + struct flock flo; - if (!save_cache(graph, cachefile)) { - free(cachefile); - free(depfile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } + f = lockfile(); - free(cachefile); - free(depfile); - cleanup_and_exit(graph, cache, EXIT_SUCCESS); + if (!f) + return; + + flo.l_start = flo.l_len = 0; + flo.l_whence = SEEK_SET; + flo.l_type = F_UNLCK; + + rewind(f); + + if (ftruncate(fileno(f), 0) == -1) { + perror("bee-dep: unlock: ftruncate"); + exit(1); } - if (!hnode || !IS_PKG(hnode)) { - fprintf(stderr, "bee-dep: unknown package '%s'\n", pkgname); - free(cachefile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); + if (fcntl(fileno(f), F_SETLK, &flo) == -1) { + perror("bee-dep: unlock: fcntl"); + exit(1); } - if (print) { - if (print_removable(graph, pkgname) == EXIT_FAILURE) { - free(cachefile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } + if (fclose(f) == EOF) { + perror("bee-dep: unlock: fclose"); + exit(1); } +} - if (remove) { - if (remove_package(graph, pkgname) == EXIT_FAILURE) { - free(cachefile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } +int main(int argc, char *argv[]) +{ + int command; - if (!save_cache(graph, cachefile)) { - free(cachefile); - cleanup_and_exit(graph, cache, EXIT_FAILURE); - } + get_bee_variables(); + + if (argc < 2) { + usage(); + return 1; + } + + lock(); + if (atexit(unlock)) { + perror("bee-dep: atexit"); + return 1; } - free(cachefile); - cleanup_and_exit(graph, cache, EXIT_SUCCESS); + command = get_command(argv[1]); + + argv++; + argc--; + + switch (command) { + case REBUILD: + return bee_dep_rebuild(argc, argv); + + case UPDATE: + return bee_dep_update(argc, argv); + + case REMOVE: + return bee_dep_remove(argc, argv); + + case LIST: + return bee_dep_list(argc, argv); + + case CONFLICTS: + return bee_dep_conflicts(argc, argv); + + default: + usage(); + return 1; + } - return EXIT_FAILURE; + return 0; } diff --git a/src/bee-install.sh.in b/src/bee-install.sh.in index 5ab420e..1588382 100755 --- a/src/bee-install.sh.in +++ b/src/bee-install.sh.in @@ -286,7 +286,7 @@ do_install() { if [ "${OPT_NOOP}" != "yes" ]; then run_hooks post-install ${pkg} - ${BEE_LIBEXECDIR}/bee/bee.d/bee-dep --update ${pkg} + ${BEE_LIBEXECDIR}/bee/bee.d/bee-dep update ${pkg} fi if [ "${OPT_UPGRADE}" != "yes" ] ; then diff --git a/src/bee-remove.sh.in b/src/bee-remove.sh.in index d6d3d83..0ad19dd 100755 --- a/src/bee-remove.sh.in +++ b/src/bee-remove.sh.in @@ -60,7 +60,7 @@ pkg_remove() { do_remove() { pkg=${1} - FILES=$(${BEE_LIBEXECDIR}/bee/bee.d/bee-dep --remove --print ${pkg##*/}) + FILES=$(${BEE_LIBEXECDIR}/bee/bee.d/bee-dep remove --print ${pkg##*/}) if [ $? -ne 0 ] ; then echo "removal of ${pkg} failed" exit 1 diff --git a/src/graph.c b/src/graph.c index ca8472e..dc63850 100644 --- a/src/graph.c +++ b/src/graph.c @@ -24,17 +24,18 @@ ** along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#define _GNU_SOURCE - #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> #include <sys/stat.h> -#include <unistd.h> #include "graph.h" +#define IS_FILE(a) ((a)[0] == '/') +#define IS_DIR(a) (!strcmp((a)->type, DIR)) +#define IS_WHITESPACE(a) ((a) == ' ' || (a) == '\t' || (a) == '\n' || (a) == '\r') + static void add_provide(struct node *a, struct node *b) { tree_insert(a->provide, b); @@ -88,7 +89,7 @@ char is_virtual_file(char *s) int graph_insert_nodes(struct hash *hash, char *filename) { FILE *file; - char *s, *p, *a; + register char *s, *p, *a; char type_flag, u; char line[LINE_MAX], prop[LINE_MAX], @@ -96,11 +97,11 @@ int graph_insert_nodes(struct hash *hash, char *filename) pkgname[NODENAME_MAX] = {0}, nodename[NODENAME_MAX] = {0}; int l, line_cnt; - struct node *n, *h, *v; + struct node *n, *h, *v, *c; if ((file = fopen(filename, "r")) == NULL) { perror("bee-dep: graph_insert_nodes: fopen"); - return 0; + return 1; } line_cnt = type_flag = u = 0; @@ -137,7 +138,7 @@ int graph_insert_nodes(struct hash *hash, char *filename) fprintf(stderr, "bee-dep: %s: error at line %d: missing bracket\n", filename, line_cnt); - return 0; + return 1; } *p = '\0'; @@ -146,7 +147,7 @@ int graph_insert_nodes(struct hash *hash, char *filename) fprintf(stderr, "bee-dep: %s: error at line %d: empty node name\n", filename, line_cnt); - return 0; + return 1; } if (IS_FILE(s)) { @@ -155,7 +156,7 @@ int graph_insert_nodes(struct hash *hash, char *filename) "bee-dep: %s: error at line %d: " "dont know to which package" "\"%s\" belongs to\n", filename, line_cnt, s); - return 0; + return 1; } sprintf(nodename, "%s%s", pkgname, s); @@ -163,10 +164,10 @@ int graph_insert_nodes(struct hash *hash, char *filename) sprintf(nodename, "%s", s); } - if ((n = hash_search(hash, nodename)) == NULL) { - n = node_new(nodename, UNKNOWN); - hash_insert(hash, n); - } + c = node_new(nodename, UNKNOWN); + n = hash_safe_insert(hash, c); + if (c != n) + node_free(c); type_flag = 0; continue; @@ -192,7 +193,7 @@ int graph_insert_nodes(struct hash *hash, char *filename) fprintf(stderr, "bee-dep: %s: error at line %d: missing value " "for property \"%s\"\n", filename, line_cnt, prop); - return 0; + return 1; } memset(value, '\0', LINE_MAX); @@ -204,7 +205,7 @@ int graph_insert_nodes(struct hash *hash, char *filename) "bee-dep: %s: error at line %d: " "ambiguous type \"%s\"\n", filename, line_cnt, value); - return 0; + return 1; } node_set_type(n, value); @@ -218,18 +219,20 @@ int graph_insert_nodes(struct hash *hash, char *filename) type_flag = 1; } else if (strcasecmp(prop, PROVIDES) == 0) { - if ((h = hash_search(hash, value)) == NULL) { - h = node_new(value, UNKNOWN); - hash_insert(hash, h); - } + c = node_new(value, UNKNOWN); + h = hash_safe_insert(hash, c); + + if (c != h) + node_free(c); if (IS_FILE(value)) { sprintf(nodename, "%s%s", pkgname, value); - if ((v = hash_search(hash, nodename)) == NULL) { - v = node_new(nodename, UNKNOWN); - hash_insert(hash, v); - } + c = node_new(nodename, UNKNOWN); + v = hash_safe_insert(hash, c); + + if (v != c) + node_free(c); add_provide(n, v); add_provide(v, h); @@ -237,10 +240,11 @@ int graph_insert_nodes(struct hash *hash, char *filename) add_provide(n, h); } } else if (strcasecmp(prop, NEEDS) == 0) { - if ((h = hash_search(hash, value)) == NULL) { - h = node_new(value, UNKNOWN); - hash_insert(hash, h); - } + c = node_new(value, UNKNOWN); + h = hash_safe_insert(hash, c); + + if (c != h) + node_free(c); add_need(n, h); } @@ -248,18 +252,19 @@ int graph_insert_nodes(struct hash *hash, char *filename) if (fclose(file) == EOF) { perror("bee-dep: graph_insert_nodes: fclose"); - return 0; + return 1; } - if(line_cnt == 0) { - fprintf(stderr, "bee-dep: error: file '%s' is empty\n", filename); - return 0; + if (line_cnt == 0) { + fprintf(stderr, "bee-dep: error: file '%s' is empty\n", filename); + return 1; } - return 1; + return 0; } -void search_dependencies(struct hash *hash, struct node *n, struct tree *d) +static void search_dependencies(struct hash *hash, struct node *n, + struct tree *d) { struct tree_node *t; char *pkgname; @@ -267,10 +272,13 @@ void search_dependencies(struct hash *hash, struct node *n, struct tree *d) t = tree_first(n->neededby->root); while (t) { - pkgname = get_pkgname(t->n->name); - if (is_virtual_file(t->n->name)) - tree_insert(d, hash_search(hash, pkgname)); - free(pkgname); + if (is_virtual_file(t->n->name)) { + pkgname = get_pkgname(t->n->name); + if (!tree_search_node(d, pkgname)) + tree_insert(d, hash_search(hash, pkgname)); + free(pkgname); + } + t = tree_next(t); } @@ -282,43 +290,27 @@ void search_dependencies(struct hash *hash, struct node *n, struct tree *d) } } -void print_dependencies(struct hash *hash, char *depend) +static int print_dependencies(struct hash *hash, struct node *n) { - struct node *n; struct tree *t; struct tree_node *e; - if ((n = hash_search(hash, depend)) == NULL) { - fprintf(stderr, - "bee-dep: print_dependencies: cannot find \"%s\"\n", - depend); - return; - } - - if (strcmp(n->type, PACKAGE)) { - fprintf(stderr, - "bee-dep: print_dependencies: \"%s\": no such package\n", - depend); - return; - } - t = tree_new(); search_dependencies(hash, n, t); e = tree_first(t->root); - if (!e) - puts("none"); - while (e) { - if (strcmp(depend, e->n->name) != 0) + if (strcmp(n->name, e->n->name) != 0) puts(e->n->name); e = tree_next(e); } tree_free(t); + + return 0; } void add_all_neededby(struct hash *hash, struct node *n, struct tree *a) @@ -446,14 +438,14 @@ int print_removable(struct hash *hash, char *remove) fprintf(stderr, "bee-dep: print_removable: cannot find \"%s\"\n", remove); - return EXIT_FAILURE; + return 1; } if (!IS_PKG(n)) { fprintf(stderr, "bee-dep: print_removable: \"%s\": no such package\n", remove); - return EXIT_FAILURE; + return 1; } t = tree_new(); @@ -465,7 +457,7 @@ int print_removable(struct hash *hash, char *remove) if ((dirs = calloc(cnt, sizeof(*dirs))) == NULL || (files = calloc(cnt, sizeof(*files))) == NULL) { perror("bee-dep: print_removable: calloc"); - return EXIT_FAILURE; + return 1; } e = tree_first(t->root); @@ -492,27 +484,440 @@ int print_removable(struct hash *hash, char *remove) free(files); tree_free(t); - return EXIT_SUCCESS; + return 0; +} + +int count_removable(struct hash *hash, char *remove) +{ + struct node *n; + struct tree *t; + int c; + + if ((n = hash_search(hash, remove)) == NULL) { + fprintf(stderr, + "bee-dep: print_removable: cannot find \"%s\"\n", + remove); + return -1; + } + + if (!IS_PKG(n)) { + fprintf(stderr, + "bee-dep: print_removable: \"%s\": no such package\n", + remove); + return -1; + } + + t = tree_new(); + + search_removable(hash, n, t, remove); + + c = tree_count(t); + + tree_free(t); + + return c; +} + +static void list_all_files(struct node *n) +{ + struct tree_node *t; + + t = tree_first(n->provide->root); + + while (t) { + if (IS_FILE(t->n->name)) + puts(t->n->name); + + list_all_files(t->n); + + t = tree_next(t); + } +} + +static void count_all_files(struct node *n, int *count) +{ + struct tree_node *t; + + t = tree_first(n->provide->root); + + while (t) { + if (IS_FILE(t->n->name)) + (*count)++; + + list_all_files(t->n); + + t = tree_next(t); + } +} + +int list_files(struct hash *hash, char *pkgname) +{ + struct node *n; + + if ((n = hash_search(hash, pkgname)) == NULL) { + fprintf(stderr, + "bee-dep: list_files: cannot find \"%s\"\n", + pkgname); + return 1; + } + + if (!IS_PKG(n)) { + fprintf(stderr, + "bee-dep: list_files: \"%s\": no such package\n", + pkgname); + return 1; + } + + list_all_files(n); + + return 0; +} + +int count_files(struct hash *hash, char *pkgname) +{ + struct node *n; + int c; + + if ((n = hash_search(hash, pkgname)) == NULL) { + fprintf(stderr, + "bee-dep: count_files: cannot find \"%s\"\n", + pkgname); + return -1; + } + + if (!IS_PKG(n)) { + fprintf(stderr, + "bee-dep: count_files: \"%s\": no such package\n", + pkgname); + return -1; + } + + c = 0; + count_all_files(n, &c); + + return c; +} + +static void get_all_providers(struct node *n, struct tree *all) +{ + struct tree_node *t; + + t = tree_first(n->providedby->root); + + while (t) { + if (IS_PKG(t->n) && !tree_search_node(all, t->n->name)) + tree_insert(all, node_new(t->n->name, "")); + + get_all_providers(t->n, all); + + t = tree_next(t); + } } -static int save_cache_to_file(struct hash *hash, char *path) +int print_providers(struct hash *hash, char *name) +{ + struct node *n; + struct tree_node *t; + struct tree *all; + + if ((n = hash_search(hash, name)) == NULL) { + fprintf(stderr, + "bee-dep: print_providers: cannot find \"%s\"\n", + name); + return 1; + } + + if (IS_PKG(n)) { + fprintf(stderr, + "bee-dep: print_providers: \"%s\" is a package\n", + name); + return 1; + } + + all = tree_new(); + + get_all_providers(n, all); + + t = tree_first(all->root); + + while (t) { + puts(t->n->name); + t = tree_next(t); + } + + tree_free_all_nodes(all); + tree_free(all); + + return 0; +} + +int count_providers(struct hash *hash, char *name) +{ + int count; + struct node *n; + struct tree *all; + + count = 0; + + if ((n = hash_search(hash, name)) == NULL) { + fprintf(stderr, + "bee-dep: count_providers: cannot find \"%s\"\n", + name); + return -1; + } + + if (IS_PKG(n)) { + fprintf(stderr, + "bee-dep: count_providers: \"%s\" is a package\n", + name); + return -1; + } + + all = tree_new(); + get_all_providers(n, all); + + count = tree_count(all); + + tree_free_all_nodes(all); + tree_free(all); + + return count; +} + +int get_virtual_files(struct node *n, char *name, struct tree *all) +{ + struct tree_node *t; + + t = tree_first(n->providedby->root); + + while (t) { + if (!strcmp(name, get_filename(t->n->name)) + && !tree_search_node(all, t->n->name)) + tree_insert(all, t->n); + + t = tree_next(t); + } + + return tree_count(all); +} + +static void search_requirements(struct hash *hash, struct node *n, + struct tree *d) +{ + struct tree_node *t, *u; + struct tree *providers; + + t = tree_first(n->need->root); + + while (t) { + providers = tree_new(); + + get_all_providers(t->n, providers); + + u = tree_first(providers->root); + + while (u) { + if (!tree_search_node(d, u->n->name)) + tree_insert(d, hash_search(hash, u->n->name)); + + u = tree_next(u); + } + + tree_free_all_nodes(providers); + tree_free(providers); + + t = tree_next(t); + } + + t = tree_first(n->provide->root); + + while (t) { + search_requirements(hash, t->n, d); + t = tree_next(t); + } +} + +static int print_requirements(struct hash *hash, struct node *n) +{ + struct tree *t; + struct tree_node *e; + + t = tree_new(); + + search_requirements(hash, n, t); + + e = tree_first(t->root); + + while (e) { + if (strcmp(n->name, e->n->name) != 0) + puts(e->n->name); + + e = tree_next(e); + } + + tree_free(t); + + return 0; +} + +int print_needs(struct hash *hash, char *name) +{ + struct tree_node *t, *v; + struct node *n; + struct tree *all, *vf; + char *pkgname; + int count; + char p; + + if ((n = hash_search(hash, name)) == NULL) { + fprintf(stderr, + "bee-dep: print_needs: cannot find \"%s\"\n", + name); + return 1; + } + + if (IS_PKG(n)) + return print_requirements(hash, n); + + vf = tree_new(); + count = 1; + + if (is_virtual_file(n->name)) + tree_insert(vf, n); + else + count = get_virtual_files(n, name, vf); + + if (!count) { + fprintf(stderr, "bee-dep: could not get virtual file for \"%s\"\n", + name); + tree_free(vf); + return 1; + } + + v = tree_first(vf->root); + + while (v) { + all = tree_new(); + + t = tree_first(v->n->need->root); + + while (t) { + get_all_providers(t->n, all); + t = tree_next(t); + } + + t = tree_first(all->root); + p = (t && count > 1); + + if (p) { + pkgname = get_pkgname(v->n->name); + printf("%s:\n", pkgname); + free(pkgname); + } + + while (t) { + puts(t->n->name); + t = tree_next(t); + } + + tree_free_all_nodes(all); + tree_free(all); + + v = tree_next(v); + + if (v && p) + puts(""); + } + + tree_free(vf); + + return 0; +} + +int print_neededby(struct hash *hash, char *name) +{ + struct node *n; + struct tree_node *t; + struct tree *all; + + if ((n = hash_search(hash, name)) == NULL) { + fprintf(stderr, + "bee-dep: print_needs: cannot find \"%s\"\n", + name); + return 1; + } + + if (IS_PKG(n)) + return print_dependencies(hash, n); + + all = tree_new(); + + t = tree_first(n->neededby->root); + + while (t) { + get_all_providers(t->n, all); + t = tree_next(t); + } + + t = tree_first(all->root); + + while (t) { + puts(t->n->name); + t = tree_next(t); + } + + tree_free_all_nodes(all); + tree_free(all); + + return 0; +} + +void list_packages(struct hash *hash) { int i; - unsigned long index; - struct tree_node *s, *t; - FILE *file; + struct tree_node *t; - /* TODO: need to handle all kinds of race conditions here 8) */ + for (i = 0; i < TBLSIZE; i++) { + t = tree_first(hash->tbl[i]->root); - if ((file = fopen(path, "w")) == NULL) { - perror("bee-dep: save_cache: fopen"); - return 0; + while (t) { + if (IS_PKG(t->n)) + puts(t->n->name); + t = tree_next(t); + } } +} - index = 0; +int count_packages(struct hash *hash) +{ + int i, c; + struct tree_node *t; - if (hash->cnt == 0) + c = 0; + + for (i = 0; i < TBLSIZE; i++) { + t = tree_first(hash->tbl[i]->root); + + while (t) { + if (IS_PKG(t->n)) + c++; + t = tree_next(t); + } + } + + return c; +} + +int save_cache(struct hash *hash, char *path) +{ + int i; + struct tree_node *s, *t; + FILE *file; + + if ((file = fopen(path, "w")) == NULL) { + perror("bee-dep: save_cache: fopen"); return 1; + } for (i = 0; i < TBLSIZE; i++) { if (hash->tbl[i]->root) { @@ -557,42 +962,13 @@ static int save_cache_to_file(struct hash *hash, char *path) if (fclose(file) == EOF) { perror("bee-dep: save_cache: fclose"); - return 0; - } - - return 1; -} - -int save_cache(struct hash *hash, char *fname) -{ - char *tmpname; - int ret = 1; - - /* TODO: need to handle all kinds of race conditions here 8) */ - - if(asprintf(&tmpname, "%s.tmp", fname) == -1) { - perror("bee-dep: save_cache: asprintf"); - return 0; - } - - if(save_cache_to_file(hash, tmpname)) { - if(rename(tmpname, fname) == -1) { - perror("bee-dep: save_cache: rename"); - if(unlink(tmpname) == -1) { - perror("bee-dep: save_cache: unlink"); - } - ret = 0; - } - } else { - ret = 0; + return 1; } - free(tmpname); - - return ret; + return 0; } -int load_cache(struct hash *hash, FILE *file) +struct hash *load_cache(char *filename) { char line[LINE_MAX], a[NODENAME_MAX], @@ -600,8 +976,16 @@ int load_cache(struct hash *hash, FILE *file) char c; struct node *k, *l; int line_cnt; + FILE *file; + struct hash *hash; + + if ((file = fopen(filename, "r")) == NULL) { + perror("bee-dep: load_cache: fopen"); + return NULL; + } + + hash = hash_new(); - rewind(file); line_cnt = 0; while (fgets(line, LINE_MAX, file)) { @@ -613,7 +997,8 @@ int load_cache(struct hash *hash, FILE *file) if (sscanf(line, "%s %s", a, b) == EOF) { fprintf(stderr, "beedep: load_cache: " "cache file is broken (line %d)\n", line_cnt); - return 0; + hash_free(hash); + return NULL; } hash_insert(hash, node_new(a, b)); @@ -625,7 +1010,8 @@ int load_cache(struct hash *hash, FILE *file) if (sscanf(line, "%s %s %c", a, b, &c) == EOF) { fprintf(stderr, "beedep: load_cache: " "cache file is broken (line %d)\n", line_cnt); - return 0; + hash_free(hash); + return NULL; } k = hash_search(hash, a); @@ -634,7 +1020,8 @@ int load_cache(struct hash *hash, FILE *file) if (!k || !l) { fprintf(stderr, "beedep: load_cache: " "cache file is broken (line %d)\n", line_cnt); - return 0; + hash_free(hash); + return NULL; } if (c == 'n') { @@ -646,25 +1033,18 @@ int load_cache(struct hash *hash, FILE *file) } else { fprintf(stderr, "beedep: load_cache: " "cache file is broken (line %d)\n", line_cnt); - return 0; + hash_free(hash); + return NULL; } } - return 1; -} - -unsigned long count_providedby(struct hash *hash, char *count) -{ - struct node *n; - - if ((n = hash_search(hash, count)) == NULL) { - fprintf(stderr, - "bee-dep: count_providedby: cannot find \"%s\"\n", - count); - exit(EXIT_FAILURE); + if (fclose(file) == EOF) { + perror("bee-dep: load_cache: fclose"); + hash_free(hash); + return NULL; } - return tree_count(n->providedby); + return hash; } void remove_all(struct hash *hash, struct node *n) @@ -708,17 +1088,66 @@ int remove_package(struct hash *hash, char *pkgname) fprintf(stderr, "bee-dep: remove_package: cannot find \"%s\"\n", pkgname); - return EXIT_FAILURE; + return 1; } if (!IS_PKG(n)) { fprintf(stderr, "bee-dep: remove_package: \"%s\": no such package\n", pkgname); - return EXIT_FAILURE; + return 1; } remove_all(hash, n); - return EXIT_SUCCESS; + return 0; +} + +int print_conflicts(struct hash *hash) +{ + int i; + struct tree_node *t, *s; + char *pkgname; + + for (i = 0; i < TBLSIZE; i++) { + t = tree_first(hash->tbl[i]->root); + + while (t) { + if (!IS_FILE(t->n->name) || IS_DIR(t->n) + || tree_count(t->n->providedby) < 2) { + t = tree_next(t); + continue; + } + + printf("%s: ", t->n->name); + + s = tree_first(t->n->providedby->root); + + while (s) { + if (IS_PKG(s->n)) { + printf("%s", s->n->name); + } else if (is_virtual_file(s->n->name)) { + pkgname = get_pkgname(s->n->name); + printf("%s", pkgname); + free(pkgname); + } else { + fprintf(stderr, "bee-dep: print_conflicts: " + "could not get pkgname for \"%s\"\n", + s->n->name); + return 1; + } + + s = tree_next(s); + + if (!s) + puts(""); + else + printf(" "); + } + + t = tree_next(t); + } + } + + return 0; } diff --git a/src/graph.h b/src/graph.h index 964b83d..30edf41 100644 --- a/src/graph.h +++ b/src/graph.h @@ -35,20 +35,26 @@ #define DIR "DIRECTORY" #define UNKNOWN "VOID" -#define IS_FILE(a) ((a)[0] == '/') -#define IS_DIR(a) (!strcmp((a)->type, DIR)) -#define IS_WHITESPACE(a) ((a) == ' ' || (a) == '\t' || (a) == '\n' || (a) == '\r') -#define IS_PKG(a) (!strcmp((a)->type, PACKAGE)) - #include "hash.h" +#define IS_PKG(a) (!strcmp((a)->type, PACKAGE)) + extern int graph_insert_nodes(struct hash *hash, char *filename); -extern void print_dependencies(struct hash *hash, char *depend); extern void print_broken(struct hash *hash, char *remove); extern int print_removable(struct hash *hash, char *remove); +extern int count_removable(struct hash *hash, char *remove); +extern int list_files(struct hash *hash, char *pkgname); +extern int count_files(struct hash *hash, char *pkgname); +extern int print_providers(struct hash *hash, char *name); +extern int count_providers(struct hash *hash, char *name); +extern int print_needs(struct hash *hash, char *name); +extern int print_neededby(struct hash *hash, char *name); +extern void list_packages(struct hash *hash); +extern int count_packages(struct hash *hash); extern int remove_package(struct hash *hash, char *pkgname); +extern int print_conflicts(struct hash *hash); extern int save_cache(struct hash *hash, char *path); -extern int load_cache(struct hash *hash, FILE *file); +extern struct hash *load_cache(char *filename); extern unsigned long count_providedby(struct hash *hash, char *count); #endif diff --git a/src/hash.c b/src/hash.c index 54101cd..85bed0b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -34,8 +34,10 @@ struct hash *hash_new(void) struct hash *h; unsigned long i; - if (!(h = calloc(1, sizeof(struct hash)))) - return NULL; + if ((h = calloc(1, sizeof(struct hash))) == NULL) { + perror("bee-dep: hash_new: calloc"); + exit(EXIT_FAILURE); + } for (i = 0; i < TBLSIZE; i++) h->tbl[i] = tree_new(); @@ -45,7 +47,7 @@ struct hash *hash_new(void) unsigned long hash_index(char *key) { - unsigned long index = 0; + register unsigned long index = 0; char c; while ((c = *key++)) @@ -60,8 +62,20 @@ void hash_insert(struct hash *hash, struct node *n) unsigned long index = hash_index(n->name); tree_insert(hash->tbl[index], n); +} + +struct node *hash_safe_insert(struct hash *hash, struct node *n) +{ + unsigned long index = hash_index(n->name); + struct node *r; + + r = tree_search_node(hash->tbl[index], n->name); - hash->cnt++; + if (r) + return r; + + tree_insert(hash->tbl[index], n); + return n; } struct node *hash_search(struct hash *hash, char *key) diff --git a/src/hash.h b/src/hash.h index c4faf35..f0d0835 100644 --- a/src/hash.h +++ b/src/hash.h @@ -29,16 +29,16 @@ #include "beedep_tree.h" -#define TBLSIZE 2000003 /* prime number */ +#define TBLSIZE 2000003L /* prime number */ struct hash { struct tree *tbl[TBLSIZE]; - unsigned long cnt; }; extern struct hash *hash_new(void); extern unsigned long hash_index(char *key); extern void hash_insert(struct hash *hash, struct node *n); +extern struct node *hash_safe_insert(struct hash *hash, struct node *n); extern struct node *hash_search(struct hash *hash, char *key); extern void hash_free(struct hash *hash);