diff --git a/DBSCHEMA b/DBSCHEMA index 06af863..33ef516 100644 --- a/DBSCHEMA +++ b/DBSCHEMA @@ -50,3 +50,4 @@ There are three tables in the database at present: 3. section The section number 4. machine The machine architecture (if any) for which the page is relevant + 5. md5_hash MD5 Hash of the target man page. diff --git a/Makefile b/Makefile index 3d97c83..120654d 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ -# $NetBSD: Makefile,v 1.2 2012/02/16 20:58:55 joerg Exp $ +# $NetBSD: Makefile,v 1.3 2012/10/06 15:33:59 wiz Exp $ .include MDIST= ${NETBSDSRCDIR}/external/bsd/mdocml/dist MDOCDIR=${NETBSDSRCDIR}/external/bsd/mdocml +MANCONFDIR=${NETBSDSRCDIR}/usr.bin/man PROGS= makemandb apropos whatis apropos.cgi suggest.cgi -SRCS.makemandb= makemandb.c apropos-utils.c -SRCS.apropos= apropos.c apropos-utils.c -SRCS.whatis= whatis.c apropos-utils.c +SRCS.makemandb= makemandb.c apropos-utils.c manconf.c +SRCS.apropos= apropos.c apropos-utils.c manconf.c +SRCS.whatis= whatis.c apropos-utils.c manconf.c SRCS.apropos.cgi= apropos_cgi.c apropos-utils.c cgi-utils.c SRCS.suggest.cgi= suggest_cgi.c cgi-utils.c apropos-utils.c MAN.makemandb= makemandb.8 @@ -19,7 +20,9 @@ BINDIR.apropos= /usr/bin BINDIR.makemandb= /usr/sbin BINDIR.whatis= /usr/bin -CPPFLAGS+=-I${MDIST} -I${.OBJDIR} +.PATH: ${MANCONFDIR} + +CPPFLAGS+=-I${MDIST} -I${MANCONFDIR} -I${.OBJDIR} MDOCMLOBJDIR!= cd ${MDOCDIR}/lib/libmandoc && ${PRINTOBJDIR} MDOCMLLIB= ${MDOCMLOBJDIR}/libmandoc.a diff --git a/apropos-utils.c b/apropos-utils.c index 08ef15e..07d4c61 100644 --- a/apropos-utils.c +++ b/apropos-utils.c @@ -1,4 +1,4 @@ -/* $NetBSD: apropos-utils.c,v 1.2 2012/02/07 19:17:16 joerg Exp $ */ +/* $NetBSD: apropos-utils.c,v 1.7 2012/10/06 15:33:59 wiz Exp $ */ /*- * Copyright (c) 2011 Abhinav Upadhyay * All rights reserved. @@ -31,8 +31,9 @@ */ #include -__RCSID("$NetBSD: apropos-utils.c,v 1.2 2012/02/07 19:17:16 joerg Exp $"); +__RCSID("$NetBSD: apropos-utils.c,v 1.7 2012/10/06 15:33:59 wiz Exp $"); +#include #include #include @@ -46,6 +47,7 @@ __RCSID("$NetBSD: apropos-utils.c,v 1.2 2012/02/07 19:17:16 joerg Exp $"); #include #include "apropos-utils.h" +#include "manconf.h" #include "mandoc.h" #include "sqlite3.h" @@ -223,7 +225,7 @@ create_db(sqlite3 *db) "file UNIQUE, md5_hash UNIQUE, id INTEGER PRIMARY KEY); " //mandb_meta "CREATE TABLE IF NOT EXISTS mandb_links(link, target, section, " - "machine); " //mandb_links + "machine, md5_hash); " //mandb_links "CREATE TABLE mandb_dict(word UNIQUE, frequency);"; //mandb_dict; @@ -234,7 +236,9 @@ create_db(sqlite3 *db) sqlstr = "CREATE INDEX IF NOT EXISTS index_mandb_links ON mandb_links " "(link); " "CREATE INDEX IF NOT EXISTS index_mandb_meta_dev ON mandb_meta " - "(device, inode)"; + "(device, inode); " + "CREATE INDEX IF NOT EXISTS index_mandb_links_md5 ON mandb_links " + "(md5_hash);"; sqlite3_exec(db, sqlstr, NULL, NULL, &errmsg); if (errmsg != NULL) goto out; @@ -311,6 +315,28 @@ unzip(sqlite3_context *pctx, int nval, sqlite3_value **apval) sqlite3_result_text(pctx, (const char *) outbuf, stream.total_out, free); } +/* + * get_dbpath -- + * Read the path of the database from man.conf and return. + */ +char * +get_dbpath(const char *manconf) +{ + TAG *tp; + char *dbpath; + + config(manconf); + tp = gettag("_mandb", 1); + if (!tp) + return NULL; + + if (TAILQ_EMPTY(&tp->entrylist)) + return NULL; + + dbpath = TAILQ_LAST(&tp->entrylist, tqh)->s; + return dbpath; +} + /* init_db -- * Prepare the database. Register the compress/uncompress functions and the * stopword tokenizer. @@ -327,7 +353,7 @@ unzip(sqlite3_context *pctx, int nval, sqlite3_value **apval) * In normal cases the function should return a handle to the db. */ sqlite3 * -init_db(int db_flag) +init_db(int db_flag, const char *manconf) { sqlite3 *db = NULL; sqlite3_stmt *stmt; @@ -335,8 +361,11 @@ init_db(int db_flag) int rc; int create_db_flag = 0; + char *dbpath = get_dbpath(manconf); + if (dbpath == NULL) + errx(EXIT_FAILURE, "_mandb entry not found in man.conf"); /* Check if the database exists or not */ - if (!(stat(DBPATH, &sb) == 0 && S_ISREG(sb.st_mode))) { + if (!(stat(dbpath, &sb) == 0 && S_ISREG(sb.st_mode))) { /* Database does not exist, check if DB_CREATE was specified, and set * flag to create the database schema */ @@ -350,7 +379,7 @@ init_db(int db_flag) /* Now initialize the database connection */ sqlite3_initialize(); - rc = sqlite3_open_v2(DBPATH, &db, db_flag, NULL); + rc = sqlite3_open_v2(dbpath, &db, db_flag, NULL); if (rc != SQLITE_OK) { warnx("%s", sqlite3_errmsg(db)); @@ -365,12 +394,14 @@ init_db(int db_flag) rc = sqlite3_prepare_v2(db, "PRAGMA user_version", -1, &stmt, NULL); if (rc != SQLITE_OK) { - warnx("Unable to query schema version"); + warnx("Unable to query schema version: %s", + sqlite3_errmsg(db)); goto error; } if (sqlite3_step(stmt) != SQLITE_ROW) { sqlite3_finalize(stmt); - warnx("Unable to query schema version"); + warnx("Unable to query schema version: %s", + sqlite3_errmsg(db)); goto error; } if (sqlite3_column_int(stmt, 0) != APROPOS_SCHEMA_VERSION) { @@ -386,17 +417,20 @@ init_db(int db_flag) /* Register the zip and unzip functions for FTS compression */ rc = sqlite3_create_function(db, "zip", 1, SQLITE_ANY, NULL, zip, NULL, NULL); if (rc != SQLITE_OK) { - warnx("Unable to register function: compress"); + warnx("Unable to register function: compress: %s", + sqlite3_errmsg(db)); goto error; } rc = sqlite3_create_function(db, "unzip", 1, SQLITE_ANY, NULL, unzip, NULL, NULL); if (rc != SQLITE_OK) { - warnx("Unable to register function: uncompress"); + warnx("Unable to register function: uncompress: %s", + sqlite3_errmsg(db)); goto error; } return db; + error: sqlite3_close(db); sqlite3_shutdown(); @@ -794,6 +828,8 @@ run_query(sqlite3 *db, const char *snippet_args[3], query_args *args) const char *name_desc; const char *machine; const char *snippet; + const char *name_temp; + char *slash_ptr; char *m = NULL; int rc; inverse_document_frequency idf = {0, 0}; @@ -806,9 +842,11 @@ run_query(sqlite3 *db, const char *snippet_args[3], query_args *args) rc = sqlite3_create_function(db, "rank_func", 1, SQLITE_ANY, (void *)&idf, rank_func, NULL, NULL); if (rc != SQLITE_OK) { + warnx("Unable to register the ranking function: %s", + sqlite3_errmsg(db)); sqlite3_close(db); sqlite3_shutdown(); - errx(EXIT_FAILURE, "Unable to register the ranking function"); + exit(EXIT_FAILURE); } /* We want to build a query of the form: "select x,y,z from mandb where @@ -892,13 +930,16 @@ run_query(sqlite3 *db, const char *snippet_args[3], query_args *args) while (sqlite3_step(stmt) == SQLITE_ROW) { section = (const char *) sqlite3_column_text(stmt, 0); + name_temp = (const char *) sqlite3_column_text(stmt, 1); name_desc = (const char *) sqlite3_column_text(stmt, 2); machine = (const char *) sqlite3_column_text(stmt, 3); snippet = (const char *) sqlite3_column_text(stmt, 4); + if ((slash_ptr = strrchr(name_temp, '/')) != NULL) + name_temp = slash_ptr + 1; if (machine && machine[0]) { m = estrdup(machine); easprintf(&name, "%s/%s", lower(m), - sqlite3_column_text(stmt, 1)); + name_temp); free(m); } else { name = estrdup((const char *) sqlite3_column_text(stmt, 1)); diff --git a/apropos-utils.h b/apropos-utils.h index 2ef0064..6157908 100644 --- a/apropos-utils.h +++ b/apropos-utils.h @@ -1,4 +1,4 @@ -/* $NetBSD: apropos-utils.h,v 1.2 2012/02/07 19:17:16 joerg Exp $ */ +/* $NetBSD: apropos-utils.h,v 1.4 2012/10/06 15:33:59 wiz Exp $ */ /*- * Copyright (c) 2011 Abhinav Upadhyay * All rights reserved. @@ -35,7 +35,7 @@ #include "sqlite3.h" -#define DBPATH "/var/db/man.db" +#define MANCONF "/etc/man.conf" #define SECMAX 9 /* Flags for opening the database */ @@ -43,7 +43,7 @@ #define MANDB_WRITE SQLITE_OPEN_READWRITE #define MANDB_CREATE SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE -#define APROPOS_SCHEMA_VERSION 20120130 +#define APROPOS_SCHEMA_VERSION 20120507 /* * Used to identify the section of a man(7) page. @@ -84,8 +84,9 @@ typedef struct query_args { char *lower(char *); void concat(char **, const char *); void concat2(char **, const char *, size_t); -sqlite3 *init_db(int); +sqlite3 *init_db(int, const char *); void close_db(sqlite3 *); +char *get_dbpath(const char *); int run_query(sqlite3 *, const char *[3], query_args *); int run_query_html(sqlite3 *, query_args *); int run_query_pager(sqlite3 *, query_args *); diff --git a/apropos.1 b/apropos.1 index 6e45fd7..b4a7363 100644 --- a/apropos.1 +++ b/apropos.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: apropos.1,v 1.3 2012/02/15 23:53:13 joerg Exp $ +.\" $NetBSD: apropos.1,v 1.6 2012/10/06 15:33:59 wiz Exp $ .\" .\" Copyright (c) 2011 Abhinav Upadhyay .\" All rights reserved. @@ -29,7 +29,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 15, 2012 +.Dd October 5, 2012 .Dt APROPOS 1 .Os .Sh NAME @@ -106,12 +106,22 @@ using it is equivalent to using the options directly. .El .Sh FILES -.Bl -hang -width -compact -.It Pa /var/db/man.db -The Sqlite FTS database which contains an index of the manual pages. +.Bl -hang -width /etc/man.conf -compact +.It Pa /etc/man.conf +The location of the Sqlite FTS database can be configured using the +.Cd _mandb +tag. .El .Sh SEE ALSO .Xr man 1 , +.Xr whatis 1 , .Xr makemandb 8 +.Sh HISTORY +The +.Nm +command appeared in 3.0BSD. +It was rewritten in +.Nx 6.0 +to support full text search using Sqlite. .Sh AUTHORS .An Abhinav Upadhyay diff --git a/apropos.c b/apropos.c index 5655c87..ecd6424 100644 --- a/apropos.c +++ b/apropos.c @@ -1,4 +1,4 @@ -/* $NetBSD: apropos.c,v 1.5 2012/02/15 23:53:13 joerg Exp $ */ +/* $NetBSD: apropos.c,v 1.8 2012/10/06 15:33:59 wiz Exp $ */ /*- * Copyright (c) 2011 Abhinav Upadhyay * All rights reserved. @@ -31,7 +31,7 @@ */ #include -__RCSID("$NetBSD: apropos.c,v 1.5 2012/02/15 23:53:13 joerg Exp $"); +__RCSID("$NetBSD: apropos.c,v 1.8 2012/10/06 15:33:59 wiz Exp $"); #include #include @@ -153,7 +153,7 @@ main(int argc, char *argv[]) errx(EXIT_FAILURE, "Try using more relevant keywords"); build_boolean_query(query); - if ((db = init_db(MANDB_WRITE)) == NULL) + if ((db = init_db(MANDB_READONLY, MANCONF)) == NULL) exit(EXIT_FAILURE); /* If user wants to page the output, then set some settings */ @@ -227,7 +227,7 @@ query_callback(void *data, const char *section, const char *name, callback_data *cbdata = (callback_data *) data; FILE *out = cbdata->out; cbdata->count++; - fprintf(out, "%s(%s)\t%s\n", name, section, name_desc); + fprintf(out, "%s (%s)\t%s\n", name, section, name_desc); if (cbdata->aflags->no_context == 0) fprintf(out, "%s\n\n", snippet); @@ -243,7 +243,7 @@ static void usage(void) { fprintf(stderr, - "Usage: %s [-n Number of records] [-p] [-123456789] [-S machine] query\n", + "Usage: %s [-n Number of records] [-123456789Ccp] [-S machine] query\n", getprogname()); exit(1); } diff --git a/init_db.3 b/init_db.3 index bee7241..359f1ee 100644 --- a/init_db.3 +++ b/init_db.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: init_db.3,v 1.1 2012/02/07 19:13:32 joerg Exp $ +.\" $NetBSD: init_db.3,v 1.2 2012/10/06 15:33:59 wiz Exp $ .\" .\" Copyright (c) 2011 Abhinav Upadhyay .\" All rights reserved. @@ -29,7 +29,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 17, 2011 +.Dd October 5, 2011 .Dt INIT_DB 3 .Os .Sh NAME @@ -38,7 +38,7 @@ .Sh SYNOPSIS .In apropos-utils.h .Ft sqlite3 * -.Fn init_db "int db_flag" +.Fn init_db "int db_flag" "char *manconf" .Sh DESCRIPTION The .Fn init_db @@ -63,24 +63,34 @@ This will open the database in read/write mode. This will open the database in read/write mode, and will also create the database schema if it does not exist already. .El +.Pp +The second argument +.Fa manconf +specifies the location of the man.conf configuration file. +By default it is stored at +.Pa /etc/man.conf . +The location of the man.db database is configured in the configuration file +using the +.Cd _mandb +tag. .Sh RETURN VALUES On successful execution the .Fn init_db function will return a pointer to a sqlite3 structure which represents a connection to the database. .Pp -In case the file -.Pa /var/db/man.db -does not exist and +In case the man.db file does not exist and .Dv DB_CREATE is not used as a value of .Fa db_flag , .Dv NULL will be returned. .Sh FILES -.Bl -hang -width /var/db/man.db -compact -.It Pa /var/db/man.db -The Sqlite FTS database which contains an index of the manual pages. +.Bl -hang -width /etc/man.conf -compact +.It Pa /etc/man.conf +The location of the Sqlite FTS database can be configured using the +.Cd _mandb +tag. .El .Sh SEE ALSO .Xr apropos-utils 3 , diff --git a/makemandb.8 b/makemandb.8 index c23c6fa..3298925 100644 --- a/makemandb.8 +++ b/makemandb.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: makemandb.8,v 1.1 2012/02/07 19:13:32 joerg Exp $ +.\" $NetBSD: makemandb.8,v 1.6 2012/10/06 15:33:59 wiz Exp $ .\" .\" Copyright (c) 2011 Abhinav Upadhyay .\" All rights reserved. @@ -29,7 +29,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 4, 2012 +.Dd October 5, 2012 .Dt MAKEMANDB 8 .Os .Sh NAME @@ -37,8 +37,8 @@ .Nd parse the manual pages and build a search index over them .Sh SYNOPSIS .Nm +.Op Fl floQqv .Op Fl C Ar path -.Op Fl floqv .Sh DESCRIPTION The .Nm @@ -71,16 +71,17 @@ and also to substantially save disk space. Use this option to optimize the index for speed and also to significantly reduce disk space usage. This is a somewhat expensive operation. +.It Fl Q +Print only fatal error messages (i.e., when the database is left in +an inconsistent state and needs manual intervention). .It Fl q -Print only error messages and no status updates. +Print only warnings and error messages but no status updates. .It Fl v Enable verbose output. -This prints the name of every file being parsed. +This prints the name of every file being parsed +and a summary at the end of the index update. .El .Pp -As the database file is stored under -.Pa /var/db , -root privileges are required to run .Nm . .Ss DATABASE SCHEMA The name of the FTS table is mandb and its schema is as follows: @@ -94,16 +95,23 @@ The name of the FTS table is mandb and its schema is as follows: .It Li env Ta The ENVIRONMENT section. .It Li files Ta The FILES section. .It Li exit_status Ta The EXIT STATUS section. +.It Li diagnostics Ta The DIAGNOSTICS section. .It Li errors Ta The ERRORS section. +.It Li md5_hash Ta MD5 checksum of the man page. +.It Li machine Ta The machine architecture (if any) for which the man +page is relevant. .El .Sh FILES -.Bl -hang -width /var/db/man.db -compact -.It Pa /var/db/man.db -The Sqlite FTS database which contains an index of the manual pages. +.Bl -hang -width /etc/man.conf -compact +.It Pa /etc/man.conf +The location of the Sqlite FTS database can be configured using the +.Cd _mandb +tag. .El .Sh SEE ALSO .Xr apropos 1 , .Xr man 1 , +.Xr whatis 1 , .Xr man.conf 5 .Sh AUTHORS .An Abhinav Upadhyay diff --git a/makemandb.c b/makemandb.c index 158196c..4f77ffe 100644 --- a/makemandb.c +++ b/makemandb.c @@ -1,4 +1,4 @@ -/* $NetBSD: makemandb.c,v 1.5 2012/02/16 20:58:55 joerg Exp $ */ +/* $NetBSD: makemandb.c,v 1.16 2012/11/08 19:17:54 christos Exp $ */ /* * Copyright (c) 2011 Abhinav Upadhyay * Copyright (c) 2011 Kristaps Dzonsons @@ -17,7 +17,7 @@ */ #include -__RCSID("$NetBSD: makemandb.c,v 1.5 2012/02/16 20:58:55 joerg Exp $"); +__RCSID("$NetBSD: makemandb.c,v 1.16 2012/11/08 19:17:54 christos Exp $"); #include #include @@ -115,10 +115,11 @@ static void pman_parse_node(const struct man_node *, secbuff *); static void pman_parse_name(const struct man_node *, mandb_rec *); static void pman_sh(const struct man_node *, mandb_rec *); static void pman_block(const struct man_node *, mandb_rec *); -static void traversedir(const char *, sqlite3 *, struct mparse *); +static void traversedir(const char *, const char *, sqlite3 *, struct mparse *); static void mdoc_parse_section(enum mdoc_sec, const char *, mandb_rec *); static void man_parse_section(enum man_sec, const struct man_node *, mandb_rec *); -static void build_file_cache(sqlite3 *, const char *, struct stat *); +static void build_file_cache(sqlite3 *, const char *, const char *, + struct stat *); static void update_db(sqlite3 *, struct mparse *, mandb_rec *); __dead static void usage(void); static void optimize(sqlite3 *); @@ -303,13 +304,12 @@ main(int argc, char *argv[]) size_t linesize; struct mandb_rec rec; - while ((ch = getopt(argc, argv, "C:floqv")) != -1) { + while ((ch = getopt(argc, argv, "C:floQqv")) != -1) { switch (ch) { case 'C': manconf = optarg; break; case 'f': - remove(DBPATH); mflags.recreate = 1; break; case 'l': @@ -318,9 +318,12 @@ main(int argc, char *argv[]) case 'o': mflags.optimize = 1; break; - case 'q': + case 'Q': mflags.verbosity = 0; break; + case 'q': + mflags.verbosity = 1; + break; case 'v': mflags.verbosity = 2; break; @@ -334,7 +337,22 @@ main(int argc, char *argv[]) init_secbuffs(&rec); mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL); - if ((db = init_db(MANDB_CREATE)) == NULL) + if (manconf) { + char *arg; + size_t command_len = shquote(manconf, NULL, 0) + 1; + arg = emalloc(command_len); + shquote(manconf, arg, command_len); + easprintf(&command, "man -p -C %s", arg); + free(arg); + } else { + command = estrdup("man -p"); + manconf = MANCONF; + } + + if (mflags.recreate) + remove(get_dbpath(manconf)); + + if ((db = init_db(MANDB_CREATE, manconf)) == NULL) exit(EXIT_FAILURE); sqlite3_exec(db, "PRAGMA synchronous = 0", NULL, NULL, &errmsg); @@ -354,16 +372,6 @@ main(int argc, char *argv[]) exit(EXIT_FAILURE); } - if (manconf) { - char *arg; - size_t command_len = shquote(manconf, NULL, 0) + 1; - arg = malloc(command_len ); - shquote(manconf, arg, command_len); - easprintf(&command, "man -p -C %s", arg); - free(arg); - } else { - command = estrdup("man -p"); - } /* Call man -p to get the list of man page dirs */ if ((file = popen(command, "r")) == NULL) { @@ -380,15 +388,16 @@ main(int argc, char *argv[]) exit(EXIT_FAILURE); } - sqlstr = "CREATE TABLE IF NOT EXISTS metadb.file_cache(device, inode," - " mtime, file PRIMARY KEY);" - "CREATE UNIQUE INDEX IF NOT EXISTS metadb.index_file_cache_dev" + sqlstr = "CREATE TABLE metadb.file_cache(device, inode," + " mtime, parent, file PRIMARY KEY);" + "CREATE UNIQUE INDEX metadb.index_file_cache_dev" " ON file_cache (device, inode); " "CREATE VIRTUAL TABLE metadb.mandb_dup USING fts4(section, name, " "name_desc, desc, lib, return_vals, env, files, " "exit_status, diagnostics, errors, machine " "); " //mandb_dup "CREATE VIRTUAL TABLE metadb.mandb_dupaux USING fts4aux(mandb_dup); "; // mandb_dict + sqlite3_exec(db, sqlstr, NULL, NULL, &errmsg); if (errmsg != NULL) { warnx("%s", errmsg); @@ -405,10 +414,11 @@ main(int argc, char *argv[]) /* Replace the new line character at the end of string with '\0' */ line[len - 1] = '\0'; parent = estrdup(line); - chdir(dirname(parent)); + char *pdir = estrdup(dirname(parent)); free(parent); /* Traverse the man page directories and parse the pages */ - traversedir(line, db, mp); + traversedir(pdir, line, db, mp); + free(pdir); } free(line); @@ -419,6 +429,8 @@ main(int argc, char *argv[]) err(EXIT_FAILURE, "pclose error"); } + if (mflags.verbosity) + printf("Performing index update\n"); update_db(db, mp, &rec); mparse_free(mp); free_secbuffs(&rec); @@ -453,7 +465,8 @@ main(int argc, char *argv[]) * in the way to build_file_cache() */ static void -traversedir(const char *file, sqlite3 *db, struct mparse *mp) +traversedir(const char *parent, const char *file, sqlite3 *db, + struct mparse *mp) { struct stat sb; struct dirent *dirp; @@ -461,20 +474,22 @@ traversedir(const char *file, sqlite3 *db, struct mparse *mp) char *buf; if (stat(file, &sb) < 0) { - warn("stat failed: %s", file); + if (mflags.verbosity) + warn("stat failed: %s", file); return; } /* If it is a regular file or a symlink, pass it to build_cache() */ if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) { - build_file_cache(db, file, &sb); + build_file_cache(db, parent, file, &sb); return; } /* If it is a directory, traverse it recursively */ if (S_ISDIR(sb.st_mode)) { if ((dp = opendir(file)) == NULL) { - warn("opendir error: %s", file); + if (mflags.verbosity) + warn("opendir error: %s", file); return; } @@ -482,7 +497,7 @@ traversedir(const char *file, sqlite3 *db, struct mparse *mp) /* Avoid . and .. entries in a directory */ if (strncmp(dirp->d_name, ".", 1)) { easprintf(&buf, "%s/%s", file, dirp->d_name); - traversedir(buf, db, mp); + traversedir(parent, buf, db, mp); free(buf); } } @@ -498,7 +513,8 @@ traversedir(const char *file, sqlite3 *db, struct mparse *mp) * update_db(), once the database has been updated. */ static void -build_file_cache(sqlite3 *db, const char *file, struct stat *sb) +build_file_cache(sqlite3 *db, const char *parent, const char *file, + struct stat *sb) { const char *sqlstr; sqlite3_stmt *stmt = NULL; @@ -509,17 +525,19 @@ build_file_cache(sqlite3 *db, const char *file, struct stat *sb) time_t mtime_cache = sb->st_mtime; sqlstr = "INSERT INTO metadb.file_cache VALUES (:device, :inode," - " :mtime, :file)"; + " :mtime, :parent, :file)"; rc = sqlite3_prepare_v2(db, sqlstr, -1, &stmt, NULL); if (rc != SQLITE_OK) { - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); return; } idx = sqlite3_bind_parameter_index(stmt, ":device"); rc = sqlite3_bind_int64(stmt, idx, device_cache); if (rc != SQLITE_OK) { - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return; } @@ -527,7 +545,8 @@ build_file_cache(sqlite3 *db, const char *file, struct stat *sb) idx = sqlite3_bind_parameter_index(stmt, ":inode"); rc = sqlite3_bind_int64(stmt, idx, inode_cache); if (rc != SQLITE_OK) { - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return; } @@ -535,7 +554,17 @@ build_file_cache(sqlite3 *db, const char *file, struct stat *sb) idx = sqlite3_bind_parameter_index(stmt, ":mtime"); rc = sqlite3_bind_int64(stmt, idx, mtime_cache); if (rc != SQLITE_OK) { - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); + sqlite3_finalize(stmt); + return; + } + + idx = sqlite3_bind_parameter_index(stmt, ":parent"); + rc = sqlite3_bind_text(stmt, idx, parent, -1, NULL); + if (rc != SQLITE_OK) { + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return; } @@ -543,7 +572,8 @@ build_file_cache(sqlite3 *db, const char *file, struct stat *sb) idx = sqlite3_bind_parameter_index(stmt, ":file"); rc = sqlite3_bind_text(stmt, idx, file, -1, NULL); if (rc != SQLITE_OK) { - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return; } @@ -568,7 +598,8 @@ update_existing_entry(sqlite3 *db, const char *file, const char *hash, " :inode2 OR mtime <> :mtime2)"; rc = sqlite3_prepare_v2(db, inner_sqlstr, -1, &inner_stmt, NULL); if (rc != SQLITE_OK) { - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); return; } idx = sqlite3_bind_parameter_index(inner_stmt, ":device"); @@ -592,7 +623,7 @@ update_existing_entry(sqlite3 *db, const char *file, const char *hash, if (rc == SQLITE_DONE) { /* Check if an update has been performed. */ if (update_count != sqlite3_total_changes(db)) { - if (mflags.verbosity) + if (mflags.verbosity == 2) printf("Updated %s\n", file); (*new_count)++; } else { @@ -600,7 +631,8 @@ update_existing_entry(sqlite3 *db, const char *file, const char *hash, (*link_count)++; } } else { - warnx("Could not update the meta data for %s", file); + if (mflags.verbosity == 2) + warnx("Could not update the meta data for %s", file); (*err_count)++; } sqlite3_finalize(inner_stmt); @@ -644,7 +676,8 @@ read_and_decompress(const char *file, void **buf, size_t *len) if (off == *len) { *len *= 2; if (*len < off) { - warnx("File too large: %s", file); + if (mflags.verbosity) + warnx("File too large: %s", file); free(*buf); archive_read_close(a); return -1; @@ -672,6 +705,7 @@ update_db(sqlite3 *db, struct mparse *mp, mandb_rec *rec) const char *sqlstr; sqlite3_stmt *stmt = NULL; const char *file; + const char *parent; char *errmsg = NULL; char *md5sum; void *buf; @@ -683,11 +717,15 @@ update_db(sqlite3 *db, struct mparse *mp, mandb_rec *rec) int md5_status; int rc; - sqlstr = "SELECT device, inode, mtime, file FROM metadb.file_cache" - " EXCEPT SELECT device, inode, mtime, file from mandb_meta"; + sqlstr = "SELECT device, inode, mtime, parent, file" + " FROM metadb.file_cache fc" + " WHERE NOT EXISTS(SELECT 1 FROM mandb_meta WHERE" + " device = fc.device AND inode = fc.inode AND " + " mtime = fc.mtime AND file = fc.file)"; rc = sqlite3_prepare_v2(db, sqlstr, -1, &stmt, NULL); if (rc != SQLITE_OK) { + if (mflags.verbosity) warnx("%s", sqlite3_errmsg(db)); close_db(db); errx(EXIT_FAILURE, "Could not query file cache"); @@ -700,7 +738,8 @@ update_db(sqlite3 *db, struct mparse *mp, mandb_rec *rec) rec->device = sqlite3_column_int64(stmt, 0); rec->inode = sqlite3_column_int64(stmt, 1); rec->mtime = sqlite3_column_int64(stmt, 2); - file = (const char *) sqlite3_column_text(stmt, 3); + parent = (const char *) sqlite3_column_text(stmt, 3); + file = (const char *) sqlite3_column_text(stmt, 4); if (read_and_decompress(file, &buf, &buflen)) { err_count++; buf = NULL; @@ -709,7 +748,8 @@ update_db(sqlite3 *db, struct mparse *mp, mandb_rec *rec) md5_status = check_md5(file, db, "mandb_meta", &md5sum, buf, buflen); assert(md5sum != NULL); if (md5_status == -1) { - warnx("An error occurred in checking md5 value" + if (mflags.verbosity) + warnx("An error occurred in checking md5 value" " for file %s", file); err_count++; continue; @@ -739,14 +779,16 @@ update_db(sqlite3 *db, struct mparse *mp, mandb_rec *rec) * This means is either a new file or an updated file. * We should go ahead with parsing. */ - if (mflags.verbosity > 1) + if (mflags.verbosity == 2) printf("Parsing: %s\n", file); rec->md5_hash = md5sum; rec->file_path = estrdup(file); // file_path is freed by insert_into_db itself. + chdir(parent); begin_parse(file, mp, rec, buf, buflen); if (insert_into_db(db, rec) < 0) { - warnx("Error in indexing %s", file); + if (mflags.verbosity) + warnx("Error in indexing %s", file); err_count++; } else { new_count++; @@ -757,24 +799,26 @@ update_db(sqlite3 *db, struct mparse *mp, mandb_rec *rec) sqlite3_finalize(stmt); - if (mflags.verbosity) { - printf("Total Number of new or updated pages enountered = %d\n" + if (mflags.verbosity == 2) { + printf("Total Number of new or updated pages encountered = %d\n" + "Total number of (hard or symbolic) links found = %d\n" "Total number of pages that were successfully" " indexed/updated = %d\n" - "Total number of (hard or symbolic) links found = %d\n" "Total number of pages that could not be indexed" " due to errors = %d\n", - total_count, new_count, link_count, err_count); + total_count - link_count, link_count, new_count, err_count); } - if (mflags.recreate == 0) + if (mflags.recreate) return; - if (mflags.verbosity) + if (mflags.verbosity == 2) printf("Deleting stale index entries\n"); sqlstr = "DELETE FROM mandb_meta WHERE file NOT IN" " (SELECT file FROM metadb.file_cache);" + "DELETE FROM mandb_links WHERE md5_hash NOT IN" + " (SELECT md5_hash from mandb_meta);" "DROP TABLE metadb.file_cache;" "DELETE FROM mandb WHERE rowid NOT IN" " (SELECT id FROM mandb_meta);"; @@ -803,13 +847,19 @@ begin_parse(const char *file, struct mparse *mp, mandb_rec *rec, rec->xr_found = 0; if (mparse_readmem(mp, buf, len, file) >= MANDOCLEVEL_FATAL) { - warnx("%s: Parse failure", file); + /* Printing this warning at verbosity level 2 + * because some packages from pkgsrc might trigger several + * of such warnings. + */ + if (mflags.verbosity == 2) + warnx("%s: Parse failure", file); return; } mparse_result(mp, &mdoc, &man); if (mdoc == NULL && man == NULL) { - warnx("Not a man(7) or mdoc(7) page"); + if (mflags.verbosity == 2) + warnx("Not a man(7) or mdoc(7) page"); return; } @@ -1241,6 +1291,8 @@ pman_sh(const struct man_node *n, mandb_rec *rec) pman_parse_name(n, rec); name_desc = rec->name_desc; + if (name_desc == NULL) + return; /* Remove any leading spaces. */ while (name_desc[0] == ' ') @@ -1264,8 +1316,8 @@ pman_sh(const struct man_node *n, mandb_rec *rec) */ int has_alias = 0; // Any more aliases left? while (*name_desc) { - /* Remove any leading spaces. */ - if (name_desc[0] == ' ') { + /* Remove any leading spaces or hyphens. */ + if (name_desc[0] == ' ' || name_desc[0] =='-') { name_desc++; continue; } @@ -1773,7 +1825,8 @@ insert_into_db(sqlite3 *db, mandb_rec *rec) sqlite3_exec(db, sql, NULL, NULL, &errmsg); sqlite3_free(sql); if (errmsg != NULL) { - warnx("%s", errmsg); + if (mflags.verbosity) + warnx("%s", errmsg); free(errmsg); } sqlstr = "UPDATE mandb_meta SET device = :device," @@ -1781,7 +1834,8 @@ insert_into_db(sqlite3 *db, mandb_rec *rec) " md5_hash = :md5 WHERE file = :file"; rc = sqlite3_prepare_v2(db, sqlstr, -1, &stmt, NULL); if (rc != SQLITE_OK) { - warnx("Update failed with error: %s", + if (mflags.verbosity) + warnx("Update failed with error: %s", sqlite3_errmsg(db)); close_db(db); cleanup(rec); @@ -1805,7 +1859,8 @@ insert_into_db(sqlite3 *db, mandb_rec *rec) sqlite3_finalize(stmt); if (rc != SQLITE_DONE) { - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); close_db(db); cleanup(rec); errx(EXIT_FAILURE, @@ -1831,9 +1886,9 @@ insert_into_db(sqlite3 *db, mandb_rec *rec) ln[strlen(ln) - 1] = 0; str = sqlite3_mprintf("INSERT INTO mandb_links" - " VALUES (%Q, %Q, %Q, %Q)", + " VALUES (%Q, %Q, %Q, %Q, %Q)", ln, rec->name, rec->section, - rec->machine); + rec->machine, rec->md5_hash); sqlite3_exec(db, str, NULL, NULL, &errmsg); sqlite3_free(str); if (errmsg != NULL) { @@ -1849,7 +1904,8 @@ insert_into_db(sqlite3 *db, mandb_rec *rec) return 0; Out: - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); cleanup(rec); return -1; } @@ -1879,7 +1935,8 @@ check_md5(const char *file, sqlite3 *db, const char *table, char **md5sum, assert(file != NULL); *md5sum = MD5Data(buf, buflen, NULL); if (*md5sum == NULL) { - warn("md5 failed: %s", file); + if (mflags.verbosity) + warn("md5 failed: %s", file); return -1; } @@ -1896,7 +1953,8 @@ check_md5(const char *file, sqlite3 *db, const char *table, char **md5sum, idx = sqlite3_bind_parameter_index(stmt, ":md5_hash"); rc = sqlite3_bind_text(stmt, idx, *md5sum, -1, NULL); if (rc != SQLITE_OK) { - warnx("%s", sqlite3_errmsg(db)); + if (mflags.verbosity) + warnx("%s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); free(sqlstr); free(*md5sum); @@ -1922,13 +1980,14 @@ optimize(sqlite3 *db) const char *sqlstr; char *errmsg = NULL; - if (mflags.verbosity) + if (mflags.verbosity == 2) printf("Optimizing the database index\n"); sqlstr = "INSERT INTO mandb(mandb) VALUES (\'optimize\');" "VACUUM"; sqlite3_exec(db, sqlstr, NULL, NULL, &errmsg); if (errmsg != NULL) { - warnx("%s", errmsg); + if (mflags.verbosity) + warnx("%s", errmsg); free(errmsg); return; } @@ -2139,6 +2198,6 @@ append(secbuff *sbuff, const char *src) static void usage(void) { - fprintf(stderr, "Usage: %s [-flo]\n", getprogname()); + fprintf(stderr, "Usage: %s [-floQqv] [-C path]\n", getprogname()); exit(1); } diff --git a/whatis.1 b/whatis.1 index 4660b5a..beef08d 100644 --- a/whatis.1 +++ b/whatis.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: whatis.1,v 1.1 2012/02/07 19:13:32 joerg Exp $ +.\" $NetBSD: whatis.1,v 1.2 2012/10/06 15:33:59 wiz Exp $ .\" .\" Copyright (c) 2012 Joerg Sonnenberger .\" All rights reserved. @@ -27,7 +27,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 1, 2012 +.Dd October 5, 2012 .Dt WHATIS 1 .Os .Sh NAME @@ -39,12 +39,19 @@ .Sh DESCRIPTION The .Nm -program queries the database -.Pa /var/db/man.db -for manual pages with name +program queries the apropos database built by +.Xr makemandb 8 . +It searches for manual pages with name .Ar command -and prints the name of the manual page, the section and the description from -the section NAME. +and outputs name of the matching manual pages along with the section and the +brief description from the NAME section. +.Sh FILES +.Bl -hang -width /etc/man.conf -compact +.It Pa /etc/man.conf +The location of the Sqlite FTS database can be configured using the +.Cd _mandb +tag. +.El .Sh SEE ALSO .Xr apropos 1 , .Xr makemandb 8 diff --git a/whatis.c b/whatis.c index acc875e..68f95ed 100644 --- a/whatis.c +++ b/whatis.c @@ -1,4 +1,4 @@ -/* $NetBSD: whatis.c,v 1.2 2012/02/07 19:17:16 joerg Exp $ */ +/* $NetBSD: whatis.c,v 1.4 2012/10/06 15:33:59 wiz Exp $ */ /*- * Copyright (c) 2012 Joerg Sonnenberger * All rights reserved. @@ -29,7 +29,7 @@ */ #include -__RCSID("$NetBSD: whatis.c,v 1.2 2012/02/07 19:17:16 joerg Exp $"); +__RCSID("$NetBSD: whatis.c,v 1.4 2012/10/06 15:33:59 wiz Exp $"); #include #include @@ -49,7 +49,7 @@ static int whatis(sqlite3 *db, const char *cmd) { static const char sqlstr[] = "SELECT name, section, name_desc" - " FROM mandb WHERE name=?" + " FROM mandb WHERE name MATCH ? AND name=?" " ORDER BY section, name"; sqlite3_stmt *stmt = NULL; int retval; @@ -58,6 +58,8 @@ whatis(sqlite3 *db, const char *cmd) errx(EXIT_FAILURE, "Unable to query database"); if (sqlite3_bind_text(stmt, 1, cmd, -1, NULL) != SQLITE_OK) errx(EXIT_FAILURE, "Unable to query database"); + if (sqlite3_bind_text(stmt, 2, cmd, -1, NULL) != SQLITE_OK) + errx(EXIT_FAILURE, "Unable to query database"); retval = 1; while (sqlite3_step(stmt) == SQLITE_ROW) { printf("%s(%s) - %s\n", sqlite3_column_text(stmt, 0), @@ -89,7 +91,7 @@ main(int argc, char *argv[]) if (argc == 0) usage(); - if ((db = init_db(MANDB_READONLY)) == NULL) + if ((db = init_db(MANDB_READONLY, MANCONF)) == NULL) exit(EXIT_FAILURE); retval = 0;