[LEDE-DEV] [PATCH opkg-lede 2/2] pkg: alternatives support
Yousong Zhou
yszhou4tech at gmail.com
Mon Mar 20 04:39:49 PDT 2017
It's a list of specs specs of the following form seprated by commas to describe
alternatives provided by the package
<prio>:<path>:<altpath>
<path> will be a symbolic link to <altpath> of the highest <prio>
Size comparison on x86_64 after the change
function old new delta
pkg_alternatives_update - 587 +587
pkg_parse_line 2101 2609 +522
.rodata 24594 24738 +144
pkg_formatted_field 2385 2528 +143
pkg_deinit 427 486 +59
pkg_print_status 264 280 +16
opkg_configure 59 69 +10
xreadlink 120 128 +8
opkg_remove_pkg 1079 1087 +8
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 8/0 up/down: 1483/0) Total: 1497 bytes
Signed-off-by: Yousong Zhou <yszhou4tech at gmail.com>
---
libopkg/CMakeLists.txt | 2 +-
libopkg/opkg_configure.c | 3 ++
libopkg/opkg_remove.c | 2 +
libopkg/pkg.c | 32 ++++++++++++-
libopkg/pkg.h | 19 ++++++++
libopkg/pkg_alternatives.c | 113 +++++++++++++++++++++++++++++++++++++++++++++
libopkg/pkg_alternatives.h | 23 +++++++++
libopkg/pkg_parse.c | 81 +++++++++++++++++++++++++++++++-
libopkg/pkg_parse.h | 53 ++++++++++-----------
9 files changed, 299 insertions(+), 29 deletions(-)
create mode 100644 libopkg/pkg_alternatives.c
create mode 100644 libopkg/pkg_alternatives.h
diff --git a/libopkg/CMakeLists.txt b/libopkg/CMakeLists.txt
index 637dadb..1b2a949 100644
--- a/libopkg/CMakeLists.txt
+++ b/libopkg/CMakeLists.txt
@@ -9,7 +9,7 @@ ADD_LIBRARY(opkg STATIC
active_list.c conffile.c conffile_list.c file_util.c hash_table.c
nv_pair.c nv_pair_list.c opkg.c opkg_cmd.c opkg_conf.c opkg_configure.c
opkg_download.c opkg_install.c opkg_message.c opkg_remove.c
- opkg_upgrade.c opkg_utils.c parse_util.c pkg.c pkg_depends.c pkg_dest.c
+ opkg_upgrade.c opkg_utils.c parse_util.c pkg.c pkg_alternatives.c pkg_depends.c pkg_dest.c
pkg_dest_list.c pkg_extract.c pkg_hash.c pkg_parse.c pkg_src.c
pkg_src_list.c pkg_vec.c sha256.c sprintf_alloc.c str_list.c
void_list.c xregex.c xsystem.c
diff --git a/libopkg/opkg_configure.c b/libopkg/opkg_configure.c
index dc05f1e..a043c52 100644
--- a/libopkg/opkg_configure.c
+++ b/libopkg/opkg_configure.c
@@ -21,6 +21,7 @@
#include "opkg_configure.h"
#include "opkg_message.h"
#include "opkg_cmd.h"
+#include "pkg_alternatives.h"
int opkg_configure(pkg_t * pkg)
{
@@ -38,5 +39,7 @@ int opkg_configure(pkg_t * pkg)
return err;
}
+ pkg_alternatives_update(pkg);
+
return 0;
}
diff --git a/libopkg/opkg_remove.c b/libopkg/opkg_remove.c
index 694c3f3..96ca558 100644
--- a/libopkg/opkg_remove.c
+++ b/libopkg/opkg_remove.c
@@ -22,6 +22,7 @@
#include "opkg_message.h"
#include "opkg_remove.h"
#include "opkg_cmd.h"
+#include "pkg_alternatives.h"
#include "file_util.h"
#include "sprintf_alloc.h"
#include "libbb/libbb.h"
@@ -312,6 +313,7 @@ int opkg_remove_pkg(pkg_t * pkg, int from_upgrade)
remove_maintainer_scripts(pkg);
pkg->state_status = SS_NOT_INSTALLED;
+ pkg_alternatives_update(pkg);
if (parent_pkg)
parent_pkg->state_status = SS_NOT_INSTALLED;
diff --git a/libopkg/pkg.c b/libopkg/pkg.c
index c0de884..8b873bd 100644
--- a/libopkg/pkg.c
+++ b/libopkg/pkg.c
@@ -321,6 +321,20 @@ void pkg_deinit(pkg_t * pkg)
pkg_set_ptr(pkg, blob_id(cur), NULL);
break;
+ case PKG_ALTERNATIVES:
+ ptr = pkg_get_ptr(pkg, blob_id(cur));
+
+ if (ptr) {
+ struct pkg_alternatives *pkg_alts = ptr;
+
+ while (pkg_alts->nalts)
+ free(pkg_alts->alts[--pkg_alts->nalts]);
+ free(pkg_alts->alts);
+ free(pkg_alts);
+ }
+
+ pkg_set_ptr(pkg, blob_id(cur), NULL);
+ break;
}
}
@@ -636,7 +650,22 @@ void pkg_formatted_field(FILE * fp, pkg_t * pkg, const char *field)
switch (field[0]) {
case 'a':
case 'A':
- if (strcasecmp(field, "Architecture") == 0) {
+ if (strcasecmp(field, "Alternatives") == 0) {
+ struct pkg_alternatives *pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES);
+
+ if (pkg_alts && pkg_alts->nalts > 0) {
+ int i;
+ struct pkg_alternative *alt;
+
+ alt = pkg_alts->alts[0];
+ fprintf(fp, "Alternatives: %d:%s:%s", alt->prio, alt->path, alt->altpath);
+ for (i = 1; i < pkg_alts->nalts; i++) {
+ alt = pkg_alts->alts[i];
+ fprintf(fp, ", %d:%s:%s", alt->prio, alt->path, alt->altpath);
+ }
+ fputs("\n", fp);
+ }
+ } else if (strcasecmp(field, "Architecture") == 0) {
p = pkg_get_architecture(pkg);
if (p) {
fprintf(fp, "Architecture: %s\n",
@@ -938,6 +967,7 @@ void pkg_print_status(pkg_t * pkg, FILE * file)
pkg_formatted_field(file, pkg, "Conffiles");
pkg_formatted_field(file, pkg, "Installed-Time");
pkg_formatted_field(file, pkg, "Auto-Installed");
+ pkg_formatted_field(file, pkg, "Alternatives");
fputs("\n", file);
}
diff --git a/libopkg/pkg.h b/libopkg/pkg.h
index cf405b1..600fc9e 100644
--- a/libopkg/pkg.h
+++ b/libopkg/pkg.h
@@ -100,6 +100,7 @@ enum pkg_fields {
PKG_DEPENDS,
PKG_CONFLICTS,
PKG_CONFFILES,
+ PKG_ALTERNATIVES,
};
struct abstract_pkg {
@@ -118,6 +119,24 @@ struct abstract_pkg {
#include "pkg_depends.h"
+enum pkg_alternative_field {
+ PAF_PRIO,
+ PAF_PATH,
+ PAF_ALTPATH,
+ __PAF_MAX,
+};
+
+struct pkg_alternative {
+ int prio;
+ char *path;
+ char *altpath;
+};
+
+struct pkg_alternatives {
+ int nalts;
+ struct pkg_alternative **alts;
+};
+
/* XXX: CLEANUP: I'd like to clean up pkg_t in several ways:
The 3 version fields should go into a single version struct. (This
diff --git a/libopkg/pkg_alternatives.c b/libopkg/pkg_alternatives.c
new file mode 100644
index 0000000..66b64de
--- /dev/null
+++ b/libopkg/pkg_alternatives.c
@@ -0,0 +1,113 @@
+/* pkg_alternatives.c - the opkg package management system
+
+ Copyright (C) 2017 Yousong Zhou
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include <stdio.h>
+#include <sys/types.h> /* stat */
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "libbb/libbb.h"
+#include "opkg_message.h"
+#include "pkg.h"
+#include "pkg_hash.h"
+#include "pkg_alternatives.h"
+#include "sprintf_alloc.h"
+
+static int pkg_alternatives_update_path(pkg_t *pkg, const pkg_vec_t *installed, const char *path)
+{
+ struct pkg_alternatives *pkg_alts;
+ struct pkg_alternative *the_alt = NULL;
+ pkg_t *the_pkg = pkg;
+ int i, j;
+ int r;
+ char *path_in_dest;
+
+ for (i = 0; i < installed->len; i++) {
+ pkg_t *pkg = installed->pkgs[i];
+ pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES);
+ if (!pkg_alts)
+ continue;
+
+ for (j = 0; j < pkg_alts->nalts; j++) {
+ struct pkg_alternative *alt = pkg_alts->alts[j];
+
+ if (strcmp(path, alt->path))
+ continue;
+ if (!the_alt || the_alt->prio < alt->prio) {
+ the_pkg = pkg;
+ the_alt = alt;
+ }
+ }
+ }
+
+ /* path is assumed to be an absolute one */
+ sprintf_alloc(&path_in_dest, "%s%s", the_pkg->dest->root_dir, &path[1]);
+ if (!path_in_dest)
+ return -1;
+
+ if (the_alt) {
+ struct stat sb;
+
+ r = lstat(path_in_dest, &sb);
+ if (!r) {
+ char *realpath;
+
+ if (!S_ISLNK(sb.st_mode)) {
+ opkg_msg(ERROR, "%s exists but is not a symlink\n", path_in_dest);
+ r = -1;
+ goto out;
+ }
+ realpath = xreadlink(path_in_dest);
+ if (realpath && strcmp(realpath, the_alt->altpath))
+ unlink(path_in_dest);
+ free(realpath);
+ } else if (errno != ENOENT) {
+ goto out;
+ }
+ r = symlink(the_alt->altpath, path_in_dest);
+ if (r)
+ opkg_msg(INFO, "failed symlinking %s -> %s\n", path_in_dest, the_alt->altpath);
+ } else {
+ unlink(path_in_dest);
+ r = 0;
+ }
+
+out:
+ free(path_in_dest);
+ return r;
+}
+
+int pkg_alternatives_update(pkg_t * pkg)
+{
+ int r = 0;
+ int i;
+ struct pkg_alternatives *pkg_alts;
+ struct pkg_alternative *alt = NULL;
+ pkg_vec_t *installed;
+
+ pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES);
+ if (!pkg_alts)
+ return 0;
+
+ installed = pkg_vec_alloc();
+ pkg_hash_fetch_all_installed(installed);
+ for (i = 0; i < pkg_alts->nalts; i++) {
+ alt = pkg_alts->alts[i];
+ r |= pkg_alternatives_update_path(pkg, installed, alt->path);
+ }
+ pkg_vec_free(installed);
+
+ return r;
+}
diff --git a/libopkg/pkg_alternatives.h b/libopkg/pkg_alternatives.h
new file mode 100644
index 0000000..25a5fba
--- /dev/null
+++ b/libopkg/pkg_alternatives.h
@@ -0,0 +1,23 @@
+/* pkg_alternatives.c - the opkg package management system
+
+ Copyright (C) 2017 Yousong Zhou
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef OPKG_ALTERNATIVES_H
+#define OPKG_ALTERNATIVES_H
+
+#include "pkg.h"
+
+int pkg_alternatives_update(pkg_t * pkg);
+
+#endif
diff --git a/libopkg/pkg_parse.c b/libopkg/pkg_parse.c
index 121f147..d35770c 100644
--- a/libopkg/pkg_parse.c
+++ b/libopkg/pkg_parse.c
@@ -112,6 +112,83 @@ static char *parse_architecture(pkg_t *pkg, const char *str)
return pkg_set_architecture(pkg, s, e - s);
}
+static void parse_alternatives(pkg_t *pkg, char *list)
+{
+ char *item, *tok;
+ struct pkg_alternatives *pkg_alts;
+ struct pkg_alternative **alts;
+ int nalts;
+
+ pkg_alts = pkg_get_ptr(pkg, PKG_ALTERNATIVES);
+ if (!pkg_alts) {
+ nalts = 0;
+ alts = NULL;
+ } else {
+ nalts = pkg_alts->nalts;
+ alts = pkg_alts->alts;
+ }
+
+ for (item = strtok_r(list, ",", &tok);
+ item;
+ item = strtok_r(NULL, ",", &tok)) {
+ enum pkg_alternative_field i;
+ char *val, *tok1;
+ /* the assignment was intended to quash the -Wmaybe-uninitialized warnings */
+ int prio = prio;
+ char *path = path, *altpath = altpath;
+
+ for (i = PAF_PRIO, val = strtok_r(item, ":", &tok1);
+ val && i < __PAF_MAX;
+ val = strtok_r(NULL, ":", &tok1), i++) {
+ switch (i) {
+ case PAF_PRIO:
+ prio = atoi(val);
+ break;
+ case PAF_PATH:
+ path = val;
+ break;
+ case PAF_ALTPATH:
+ altpath = val;
+ break;
+ default:
+ break;
+ }
+ }
+ if (!val && i == __PAF_MAX) {
+ char *_path, *_altpath;
+ struct pkg_alternative *alt;
+
+ /*
+ * - path must be absolute
+ * - altpath must be non-empty
+ */
+ if (path[0] != '/' || !altpath[0])
+ continue;
+
+ alt = calloc_a(sizeof(*alt),
+ &_path, strlen(path) + 1,
+ &_altpath, strlen(altpath) + 1);
+ if (!alt)
+ continue;
+ strcpy(_path, path);
+ strcpy(_altpath, altpath);
+ alt->prio = prio;
+ alt->path = _path;
+ alt->altpath = _altpath;
+ alts = xrealloc(alts, sizeof(*alts) * (nalts + 1));
+ alts[nalts++] = alt;
+ }
+ }
+
+ if (nalts > 0) {
+ if (!pkg_alts)
+ pkg_alts = xmalloc(sizeof(*pkg_alts));
+ pkg_alts->nalts = nalts;
+ pkg_alts->alts = alts;
+ pkg_set_ptr(pkg, PKG_ALTERNATIVES, pkg_alts);
+ }
+}
+
int pkg_parse_line(void *ptr, char *line, uint mask)
{
pkg_t *pkg = (pkg_t *) ptr;
@@ -131,7 +208,9 @@ int pkg_parse_line(void *ptr, char *line, uint mask)
switch (*line) {
case 'A':
- if ((mask & PFM_ARCHITECTURE) && is_field("Architecture", line))
+ if ((mask & PFM_ALTERNATIVES) && is_field("Alternatives", line))
+ parse_alternatives(pkg, line + strlen("Alternatives") + 1);
+ else if ((mask & PFM_ARCHITECTURE) && is_field("Architecture", line))
parse_architecture(pkg, line + strlen("Architecture") + 1);
else if ((mask & PFM_AUTO_INSTALLED)
&& is_field("Auto-Installed", line)) {
diff --git a/libopkg/pkg_parse.h b/libopkg/pkg_parse.h
index ac8d7c0..d1f901a 100644
--- a/libopkg/pkg_parse.h
+++ b/libopkg/pkg_parse.h
@@ -27,32 +27,33 @@ int pkg_parse_line(void *ptr, char *line, uint mask);
#define EXCESSIVE_LINE_LEN (4096 << 8)
/* package field mask */
-#define PFM_ARCHITECTURE (1 << 1)
-#define PFM_AUTO_INSTALLED (1 << 2)
-#define PFM_CONFFILES (1 << 3)
-#define PFM_CONFLICTS (1 << 4)
-#define PFM_DESCRIPTION (1 << 5)
-#define PFM_DEPENDS (1 << 6)
-#define PFM_ESSENTIAL (1 << 7)
-#define PFM_FILENAME (1 << 8)
-#define PFM_INSTALLED_SIZE (1 << 9)
-#define PFM_INSTALLED_TIME (1 << 10)
-#define PFM_MD5SUM (1 << 11)
-#define PFM_MAINTAINER (1 << 12)
-#define PFM_PACKAGE (1 << 13)
-#define PFM_PRIORITY (1 << 14)
-#define PFM_PROVIDES (1 << 15)
-#define PFM_PRE_DEPENDS (1 << 16)
-#define PFM_RECOMMENDS (1 << 17)
-#define PFM_REPLACES (1 << 18)
-#define PFM_SECTION (1 << 19)
-#define PFM_SHA256SUM (1 << 20)
-#define PFM_SIZE (1 << 21)
-#define PFM_SOURCE (1 << 22)
-#define PFM_STATUS (1 << 23)
-#define PFM_SUGGESTS (1 << 24)
-#define PFM_TAGS (1 << 25)
-#define PFM_VERSION (1 << 26)
+#define PFM_ALTERNATIVES (1 << 1)
+#define PFM_ARCHITECTURE (1 << 2)
+#define PFM_AUTO_INSTALLED (1 << 3)
+#define PFM_CONFFILES (1 << 4)
+#define PFM_CONFLICTS (1 << 5)
+#define PFM_DESCRIPTION (1 << 6)
+#define PFM_DEPENDS (1 << 7)
+#define PFM_ESSENTIAL (1 << 8)
+#define PFM_FILENAME (1 << 9)
+#define PFM_INSTALLED_SIZE (1 << 10)
+#define PFM_INSTALLED_TIME (1 << 11)
+#define PFM_MD5SUM (1 << 12)
+#define PFM_MAINTAINER (1 << 13)
+#define PFM_PACKAGE (1 << 14)
+#define PFM_PRIORITY (1 << 15)
+#define PFM_PROVIDES (1 << 16)
+#define PFM_PRE_DEPENDS (1 << 17)
+#define PFM_RECOMMENDS (1 << 18)
+#define PFM_REPLACES (1 << 19)
+#define PFM_SECTION (1 << 20)
+#define PFM_SHA256SUM (1 << 21)
+#define PFM_SIZE (1 << 22)
+#define PFM_SOURCE (1 << 23)
+#define PFM_STATUS (1 << 24)
+#define PFM_SUGGESTS (1 << 25)
+#define PFM_TAGS (1 << 26)
+#define PFM_VERSION (1 << 27)
#define PFM_ALL (~(uint)0)
--
2.6.4
More information about the Lede-dev
mailing list