distroquery: start implementing Distroquery API and some C to C++ string management conversions

This commit is contained in:
Silvan Calarco 2024-05-30 17:17:00 +02:00
parent 6732bdccfe
commit e6616f603b
2 changed files with 67 additions and 49 deletions

View File

@ -67,6 +67,7 @@ target_compile_options(distromatic PUBLIC -O2 -g -Wall -std=gnu11 -pedantic ${RP
# -fno-toplevel-reorder # -fno-toplevel-reorder
add_executable(distroquery add_executable(distroquery
DistroqueryAPI.cpp
distroquery.cpp distroquery.cpp
functions.c functions.c
headerlist.c headerlist.c
@ -94,6 +95,8 @@ target_include_directories(distroquery PUBLIC
${LIBUNWIND_INCLUDE_DIRS} ${LIBUNWIND_INCLUDE_DIRS}
) )
target_compile_options(distroquery PUBLIC -O2 -g -Wall $<$<COMPILE_LANGUAGE:CXX>:-std=c++14> -pedantic ${RPM_CFLAGS_OTHER})
install( install(
TARGETS distromatic TARGETS distromatic
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin DESTINATION ${CMAKE_INSTALL_PREFIX}/bin

View File

@ -17,7 +17,8 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include <distroquery.hpp> #include "distroquery.hpp"
#include "DistroqueryAPI.hpp"
#include <getopt.h> #include <getopt.h>
#include <errno.h> #include <errno.h>
@ -217,23 +218,23 @@ sqlite3* openRepositoryDatabase(struct configTag* ct, char* arch) {
} }
void attachCtDatabases(struct configTag* ct, sqlite3 *db, char* arch) { void attachCtDatabases(struct configTag* ct, sqlite3 *db, char* arch) {
char dbname[PATH_MAX]; string dbname;
string sql;
int i=0; int i=0;
char sql[PATH_MAX];
char *errmsg; char *errmsg;
while (ct->repository[i]) { while (ct->repository[i]) {
if (arch) { if (arch) {
snprintf(dbname, PATH_MAX, "%s%s-%s.db", ct->repository[i]->repository_dir, ct->repository[i]->tag, arch); dbname = string(ct->repository[i]->repository_dir) + ct->repository[i]->tag + "-" + arch + ".db";
snprintf(sql, PATH_MAX, "ATTACH DATABASE '%s' as '%s_%s'", dbname, ct->repository[i]->tag, arch); sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->repository[i]->tag + "_" + arch + "'";
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg)) { if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) {
fprintf(stderr, "ERROR: unable to exec statement for %s: %s\n", sql, errmsg); cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl;
} }
} else { } else {
snprintf(dbname, PATH_MAX, "%s%s-sources.db", ct->repository[i]->repository_dir, ct->repository[i]->tag); dbname = string(ct->repository[i]->repository_dir) + ct->repository[i]->tag + "-sources.db";
snprintf(sql, PATH_MAX, "ATTACH DATABASE '%s' as '%s_sources'", dbname, ct->repository[i]->tag); sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->repository[i]->tag + "_sources'";
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg)) { if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) {
fprintf(stderr, "ERROR: unable to exec statement for %s: %s\n", sql, errmsg); cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl;
} }
} }
i++; i++;
@ -241,22 +242,22 @@ void attachCtDatabases(struct configTag* ct, sqlite3 *db, char* arch) {
} }
void attachRepositoryDatabases(struct configTag* ct, sqlite3 *db, char* arch, int source) { void attachRepositoryDatabases(struct configTag* ct, sqlite3 *db, char* arch, int source) {
char dbname[PATH_MAX]; string dbname;
char sql[PATH_MAX]; string sql;
char *errmsg; char *errmsg;
snprintf(dbname, PATH_MAX, "%s%s-%s.db", ct->repository_dir, ct->tag, arch); dbname = string(ct->repository_dir) + ct->tag + "-" + arch + ".db";
snprintf(sql, PATH_MAX, "ATTACH DATABASE '%s' as '%s_%s'", dbname, ct->tag, arch); sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->tag + "_" + arch;
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg)) { if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) {
fprintf(stderr, "ERROR: unable to exec statement for %s: %s\n", sql, errmsg); cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl;
} }
if (source) { if (source) {
snprintf(dbname, PATH_MAX, "%s%s-sources.db", ct->repository_dir, ct->tag); dbname = string(ct->repository_dir) + ct->tag + "-sources.db";
snprintf(sql, PATH_MAX, "ATTACH DATABASE '%s' as '%s_sources'", dbname, ct->tag); sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->tag + "_sources'";
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg)) { if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) {
fprintf(stderr, "ERROR: unable to exec statement for %s: %s\n", sql, errmsg); cerr << "ERROR: unable to exec statement for " << sql << ":: " << errmsg << endl;
} }
} }
} }
void detachRepositoryDatabases(struct configTag* ct, sqlite3 *db, char* arch, int source) { void detachRepositoryDatabases(struct configTag* ct, sqlite3 *db, char* arch, int source) {
@ -363,11 +364,11 @@ void printInputForm() {
} }
int findFileIdFromPath(sqlite3 *db, char** path) { int findFileIdFromPath(sqlite3 *db, char** path) {
int frompos = 1, topos; size_t frompos = 1, topos;
int parent = -1; int parent = -1;
char* pt; char* pt;
char buffer[PATH_MAX]; char buffer[PATH_MAX];
char sql[PATH_MAX]; string sql;
char* linkpath = (char*)calloc(strlen(*path),1); char* linkpath = (char*)calloc(strlen(*path),1);
sqlite3_stmt* stmt1; sqlite3_stmt* stmt1;
@ -378,9 +379,8 @@ int findFileIdFromPath(sqlite3 *db, char** path) {
if (pt) topos = pt - *path; else topos = strlen(*path); if (pt) topos = pt - *path; else topos = strlen(*path);
strncpy(buffer, *path + frompos, topos - frompos); strncpy(buffer, *path + frompos, topos - frompos);
buffer[topos-frompos]=0; buffer[topos-frompos]=0;
snprintf(sql, PATH_MAX, "SELECT id FROM files WHERE parent=%d" sql = "SELECT id FROM files WHERE parent=" + to_string(parent) + " AND name='" + buffer + "'";
" AND name='%s'", parent, buffer); if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt1, NULL) == SQLITE_OK && sqlite3_step(stmt1) == SQLITE_ROW) {
if (sqlite3_prepare_v2(db, sql, strlen(sql), &stmt1, NULL) == SQLITE_OK && sqlite3_step(stmt1) == SQLITE_ROW) {
parent = sqlite3_column_int(stmt1,0); parent = sqlite3_column_int(stmt1,0);
sqlite3_finalize(stmt1); sqlite3_finalize(stmt1);
strncat(linkpath, "/", strlen(*path) - strlen(linkpath)); strncat(linkpath, "/", strlen(*path) - strlen(linkpath));
@ -490,28 +490,28 @@ int packageVerCmp(int e1, const char* v1, const char* r1, int e2, const char* v2
void printQueryResponse() { void printQueryResponse() {
int a, i, j, k, numresults = 0, otherresults = 0, localresults = 0, localprovidesresults = 0, localsourceresults = 0; int a, j, k, numresults = 0, otherresults = 0, localresults = 0, localprovidesresults = 0, localsourceresults = 0;
char dbname[PATH_MAX]; char dbname[PATH_MAX];
sqlite3 *dbf; sqlite3 *dbf;
sqlite3_stmt *statement, *stmt1; sqlite3_stmt *statement, *stmt1;
char sql[PATH_MAX]; char sql[PATH_MAX];
char buffer[PATH_MAX]; char buffer[PATH_MAX];
char queryenc[PATH_MAX]; string queryenc;
if (!reply_plain) printf("<%s><![CDATA[", reply_xmltag); if (!reply_plain) printf("<%s><![CDATA[", reply_xmltag);
strncpy(queryenc, query, PATH_MAX); queryenc = string(query);
for (i = 0; i < strlen(queryenc); i++) { for (size_t i = 0; i < queryenc.length(); i++) {
if (queryenc[i] == ' ') queryenc[i] = '%'; if (queryenc[i] == ' ') queryenc[i] = '%';
} }
for (i = 0; query_repositories[i] != NULL; i++) { for (auto i = 0; query_repositories[i] != NULL; i++) {
for (a = 0; a < ARCHS_MAX && query_repositories[i]->arch[a]; a++) { for (a = 0; a < ARCHS_MAX && query_repositories[i]->arch[a]; a++) {
if (find_query_arch(query_repositories[i]->arch[a]) >= 0) { if (find_query_arch(query_repositories[i]->arch[a]) >= 0) {
if (!query_repositories[i]->db[a]) { if (!query_repositories[i]->db[a]) {
snprintf(dbname, PATH_MAX, "%s%s-%s.db", snprintf(dbname, PATH_MAX, "%s%s-%s.db",
query_repositories[i]->repository_dir, query_repositories[i]->tag, query_repositories[i]->arch[a]); query_repositories[i]->repository_dir, query_repositories[i]->tag, query_repositories[i]->arch[a]);
if (sqlite3_open_v2(dbname, (sqlite3**)&query_repositories[i]->db[a], SQLITE_OPEN_READONLY, NULL)) { if (sqlite3_open_v2(dbname, (sqlite3**)&query_repositories[i]->db[a], SQLITE_OPEN_READONLY, NULL)) {
if (query_repositories[i]->db) sqlite3_close((sqlite3*)query_repositories[i]->db[a]); sqlite3_close((sqlite3*)query_repositories[i]->db[a]);
query_repositories[i]->db[a] = NULL; query_repositories[i]->db[a] = NULL;
fprintf(stderr, "ERROR: unable to open sqlite3 db %s; ignoring.\n", dbname); fprintf(stderr, "ERROR: unable to open sqlite3 db %s; ignoring.\n", dbname);
} }
@ -533,7 +533,8 @@ void printQueryResponse() {
"groupdescr LIKE 'Graphical Desktop/%%' DESC, groupdescr LIKE 'Applications/%%' DESC, " "groupdescr LIKE 'Graphical Desktop/%%' DESC, groupdescr LIKE 'Applications/%%' DESC, "
"groupdescr LIKE 'Development/%%' ASC, groupdescr LIKE 'Documentation%%' ASC, groupdescr LIKE 'System/Libraries%%' ASC, " "groupdescr LIKE 'Development/%%' ASC, groupdescr LIKE 'Documentation%%' ASC, groupdescr LIKE 'System/Libraries%%' ASC, "
"name LIKE '%%-devel' ASC, name LIKE '%%-debug' ASC " "name LIKE '%%-devel' ASC, name LIKE '%%-debug' ASC "
"LIMIT %d OFFSET %d", queryenc, queryenc, queryenc, queryenc, queryenc, queryenc, queryenc, query_limit, query_offset); "LIMIT %d OFFSET %d", queryenc.c_str(), queryenc.c_str(), queryenc.c_str(), queryenc.c_str(), queryenc.c_str(),
queryenc.c_str(), queryenc.c_str(), query_limit, query_offset);
if (sqlite3_prepare_v2((sqlite3*)query_repositories[i]->db[a], sql, strlen(sql), &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2((sqlite3*)query_repositories[i]->db[a], sql, strlen(sql), &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) { while (sqlite3_step(statement) == SQLITE_ROW) {
numresults++; numresults++;
@ -630,7 +631,8 @@ void printQueryResponse() {
"(provides.id_package=packages.id AND provided.id=provides.id_provided) " "(provides.id_package=packages.id AND provided.id=provides.id_provided) "
"AND provided.name LIKE '%%%s%%' " "AND provided.name LIKE '%%%s%%' "
"ORDER BY provided.name = '%s' DESC, provided.name LIKE '%s%%' DESC, provided.name LIKE '%%%s%%' DESC " "ORDER BY provided.name = '%s' DESC, provided.name LIKE '%s%%' DESC, provided.name LIKE '%%%s%%' DESC "
"LIMIT %d OFFSET %d", queryenc, queryenc, queryenc, queryenc, query_limit, query_offset); "LIMIT %d OFFSET %d", queryenc.c_str(), queryenc.c_str(), queryenc.c_str(), queryenc.c_str(),
query_limit, query_offset);
if (sqlite3_prepare_v2((sqlite3*)query_repositories[i]->db[a], sql, strlen(sql), &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2((sqlite3*)query_repositories[i]->db[a], sql, strlen(sql), &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) { while (sqlite3_step(statement) == SQLITE_ROW) {
numresults++; numresults++;
@ -685,7 +687,8 @@ void printQueryResponse() {
"packages_files_rel.id_file = files.id " "packages_files_rel.id_file = files.id "
"ORDER BY files.name = '%s' DESC, files.name LIKE '%s%%' DESC, " "ORDER BY files.name = '%s' DESC, files.name LIKE '%s%%' DESC, "
"files.name LIKE '%%%s%%' DESC LIMIT %d OFFSET %d", "files.name LIKE '%%%s%%' DESC LIMIT %d OFFSET %d",
queryenc, queryenc, queryenc, queryenc, query_limit, query_offset); queryenc.c_str(), queryenc.c_str(), queryenc.c_str(), queryenc.c_str(),
query_limit, query_offset);
if (sqlite3_prepare_v2(dbf, sql, strlen(sql), &stmt1, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2(dbf, sql, strlen(sql), &stmt1, NULL) == SQLITE_OK) {
while (sqlite3_step(stmt1) == SQLITE_ROW) { while (sqlite3_step(stmt1) == SQLITE_ROW) {
numresults++; numresults++;
@ -734,8 +737,9 @@ void printQueryResponse() {
snprintf(sql, PATH_MAX, snprintf(sql, PATH_MAX,
"SELECT * FROM sources WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%' OR version LIKE '%%%s%%' " "SELECT * FROM sources WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%' OR version LIKE '%%%s%%' "
"ORDER BY name = '%s' DESC, name LIKE '%s%%' DESC, name LIKE '%%%s%%' DESC LIMIT %d OFFSET %d", "ORDER BY name = '%s' DESC, name LIKE '%s%%' DESC, name LIKE '%%%s%%' DESC LIMIT %d OFFSET %d",
queryenc, queryenc, queryenc, queryenc, queryenc, queryenc, queryenc, query_limit, query_offset); queryenc.c_str(), queryenc.c_str(), queryenc.c_str(), queryenc.c_str(), queryenc.c_str(), queryenc.c_str(),
for (i = 0; query_repositories[i] != NULL; i++) { queryenc.c_str(), query_limit, query_offset);
for (auto i = 0; query_repositories[i] != NULL; i++) {
if (!query_repositories[i]->db[ARCHS_MAX]) { if (!query_repositories[i]->db[ARCHS_MAX]) {
snprintf(dbname, PATH_MAX, "%s%s-sources.db", query_repositories[i]->repository_dir, query_repositories[i]->tag); snprintf(dbname, PATH_MAX, "%s%s-sources.db", query_repositories[i]->repository_dir, query_repositories[i]->tag);
if (sqlite3_open_v2(dbname, (sqlite3**)&query_repositories[i]->db[ARCHS_MAX], SQLITE_OPEN_READONLY, NULL)) { if (sqlite3_open_v2(dbname, (sqlite3**)&query_repositories[i]->db[ARCHS_MAX], SQLITE_OPEN_READONLY, NULL)) {
@ -814,7 +818,7 @@ void printQueryResponse() {
} else a=j+9; /* a = number of page links displayed */ } else a=j+9; /* a = number of page links displayed */
if (a > 1) { if (a > 1) {
printf("&nbsp;[&nbsp;"); printf("&nbsp;[&nbsp;");
for (i = j; i <= a; i++) { for (auto i = j; i <= a; i++) {
if (i != k) printf("<a href=#reply onclick='distroquery_request(\"%s&limit=%d&offset=%d\")'>", if (i != k) printf("<a href=#reply onclick='distroquery_request(\"%s&limit=%d&offset=%d\")'>",
query_next, query_limit, query_limit * (i-1)); query_next, query_limit, query_limit * (i-1));
printf("%d", i); printf("%d", i);
@ -829,7 +833,7 @@ void printQueryResponse() {
printf("]]></title>"); printf("]]></title>");
} }
for (i = 0; query_repositories[i] != NULL; i++) { for (auto i = 0; query_repositories[i] != NULL; i++) {
for (a = 0; a <= ARCHS_MAX && query_repositories[i]->arch[a]; a++) { for (a = 0; a <= ARCHS_MAX && query_repositories[i]->arch[a]; a++) {
if (query_repositories[i]->db[a]) { if (query_repositories[i]->db[a]) {
sqlite3_close((sqlite3*)query_repositories[i]->db[a]); sqlite3_close((sqlite3*)query_repositories[i]->db[a]);
@ -1608,7 +1612,7 @@ void parse_request_variables(char *data) {
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
char *data; char *path_info, *query_string;
int responsed = 0; int responsed = 0;
// install backtrace handler // install backtrace handler
@ -1620,11 +1624,22 @@ main(int argc, char *argv[])
exit(1); exit(1);
} }
data = getenv("QUERY_STRING"); path_info = getenv("PATH_INFO");
if (data && strlen(data)) { query_string = getenv("QUERY_STRING");
parse_request_variables(data);
if (strncmp(path_info, "/api/v1/", strlen(API_PREFIX)) == 0) {
DistroqueryAPI api;
api.getApiResponse(&path_info[strlen(API_PREFIX)]);
} else if (strlen(path_info) > 0) {
cout << "Content-Type: text/html;charset=utf-8" << endl;
cout << "Status: 400 Bad request" << endl << endl;
cout << "ERROR: invalid path: " << path_info;
exit(1);
} }
if (query_string && strlen(query_string)) {
parse_request_variables(query_string);
}
if (!reply_plain) if (!reply_plain)
printf("Content-Type: text/xml;charset=utf-8\n\n<distroquery>"); printf("Content-Type: text/xml;charset=utf-8\n\n<distroquery>");