sys: use "Auto-Installed" field for packagelist
authorJustin Klaassen <justin@tidylabs.app>
Wed, 21 Feb 2024 22:49:32 +0000 (22:49 +0000)
committerDaniel Golle <daniel@makrotopia.org>
Thu, 22 Feb 2024 19:07:37 +0000 (19:07 +0000)
A change to the build scripts (openwrt/openwrt#14428) removed the "user" flag
from all installed packages in the rootfs. This caused problems for tools
like "auc" which rely on the rpcd packagelist command to determine which
packages to request when building a new image.

This change modifies the packagelist implementation to use the "Auto-Installed"
field rather than the "user" flag in order to filter dependencies from the
returned list of packages. The resulting package list is identical without
relying on the semantics of the "user" flag which is typically used to
indicate which packages have been interactively installed by the user.

Signed-off-by: Justin Klaassen <justin@tidylabs.app>
[use 'bool' instead of 'int' type for booleans]
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
sys.c

diff --git a/sys.c b/sys.c
index 42a2fc6ec0c327568539b8dffa29e734975a3e34..da3508ea989cfae34deb10d612c8707535281cd6 100644 (file)
--- a/sys.c
+++ b/sys.c
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <stdbool.h>
 #include <libubus.h>
 
 #include <rpcd/exec.h>
@@ -164,16 +165,31 @@ rpc_cgi_password_set(struct ubus_context *ctx, struct ubus_object *obj,
        }
 }
 
+static bool
+is_field(const char *type, const char *line)
+{
+       return strncmp(line, type, strlen(type)) == 0;
+}
+
+static bool
+is_blank(const char *line)
+{
+       for (; *line; line++)
+               if (!isspace(*line))
+                       return false;
+       return true;
+}
+
 static int
 rpc_sys_packagelist(struct ubus_context *ctx, struct ubus_object *obj,
                 struct ubus_request_data *req, const char *method,
                 struct blob_attr *msg)
 {
        struct blob_attr *tb[__RPC_PACKAGELIST_MAX];
-       int all = false;
+       bool all = false, installed = false, auto_installed = false;
        struct blob_buf buf = { 0 };
-       char var[256], pkg[128] = { 0 }, ver[128] = { 0 };
-       char *tmp, *p1, *p2, *p3;
+       char line[256], tmp[128], pkg[128], ver[128];
+       char *pkg_abi;
        void *tbl;
 
        blobmsg_parse(rpc_packagelist_policy, __RPC_PACKAGELIST_MAX, tb,
@@ -190,68 +206,44 @@ rpc_sys_packagelist(struct ubus_context *ctx, struct ubus_object *obj,
        tbl = blobmsg_open_table(&buf, "packages");
        pkg[0] = ver[0] = '\0';
 
-       while(fgets(var, sizeof(var), f)) {
-               p1 = strchr(var, ' ');
-               p2 = p3 = NULL;
-               if (!p1)
-                       goto procstr;
-
-               *p1++ = '\0';
-               p2 = strchr(p1, ' ');
-               if (!p2) {
-                       tmp = strchr(p1, '\n');
-                       if (tmp)
-                               *tmp = '\0';
-                       goto procstr;
-               }
-
-               *p2++ = '\0';
-               p3 = strchr(p2, ' ');
-               if (!p3) {
-                       tmp = strchr(p2, '\n');
-                       if (tmp)
-                               *tmp = '\0';
-                       goto procstr;
-               }
-
-               *p3++ = '\0';
-               tmp = strchr(p3, '\n');
-               if (tmp)
-                       *tmp = '\0';
-
-procstr:
-               if (!p1)
-                       continue;
-
-               if (!strcmp(var, "Package:")) {
-                       strncpy(pkg, p1, sizeof(pkg) - 1);
-                       continue;
-               }
-
-               /* If there is ABIVersion, remove that suffix */
-               if (!strcmp(var, "ABIVersion:")) {
-                       if (strlen(pkg) <= strlen(p1))
-                               continue;
-                       tmp = &pkg[strlen(pkg) - strlen(p1)];
-                       if (strncmp(p1, tmp, strlen(p1)))
-                               continue;
-
-                       *tmp = '\0';
-                       continue;
-               }
-
-               if (!strcmp(var, "Version:")) {
-                       strncpy(ver, p1, sizeof(ver) - 1);
-                       continue;
-               }
-
-               if (p2 && p3 &&
-                   !strcmp(var, "Status:") &&
-                   !strcmp(p1, "install") &&
-                   (all || strstr(p2, "user")) &&
-                   !strcmp(p3, "installed") && pkg[0] && ver[0]) {
-                       blobmsg_add_string(&buf, pkg, ver);
-                       pkg[0] = ver[0] = '\0';
+       while (fgets(line, sizeof(line), f)) {
+               switch (line[0]) {
+               case 'A':
+                       if (is_field("ABIVersion", line)) {
+                               /* if there is ABIVersion, remove that suffix */
+                               if (sscanf(line, "ABIVersion: %127s", tmp) == 1
+                                       && strlen(tmp) < strlen(pkg)) {
+                                       pkg_abi = pkg + (strlen(pkg) - strlen(tmp));
+                                       if (strncmp(pkg_abi, tmp, strlen(tmp)) == 0)
+                                               pkg_abi[0] = '\0';
+                               }
+                       } else if (is_field("Auto-Installed", line))
+                               if (sscanf(line, "Auto-Installed: %63s", tmp) == 1)
+                                       auto_installed = (strcmp(tmp, "yes") == 0);
+                       break;
+               case 'P':
+                       if (is_field("Package", line))
+                               if (sscanf(line, "Package: %127s", pkg) != 1)
+                                       pkg[0] = '\0';
+                       break;
+               case 'V':
+                       if (is_field("Version", line))
+                               if (sscanf(line, "Version: %127s", ver) != 1)
+                                       ver[0] = '\0';
+                       break;
+               case 'S':
+                       if (is_field("Status", line))
+                               if (sscanf(line, "Status: install %63s installed", tmp) == 1)
+                                       installed = true;
+                       break;
+               default:
+                       if (is_blank(line)) {
+                               if (installed && (all || !auto_installed) && pkg[0] && ver[0])
+                                       blobmsg_add_string(&buf, pkg, ver);
+                               pkg[0] = ver[0] = '\0';
+                               installed = auto_installed = false;
+                       }
+                       break;
                }
        }