Author: Robie Basak <robie.basak@oss.qualcomm.com>
Description: Use env var DSP_LIBRARY_PATH to find libraries
 This is set by guess-dsp.sh (currently in packaging) according to the DSP
 found on the hardware to the appropriate FHS path as provided by the
 hexagon-dsp-binaries package.
 .
 Updated 2025-10-22: upstream now expects DSP_LIBRARY_PATH to be ';'-separated,
 so the function is rewritten to try each of these paths only since Debian only
 needs these. ':' is given as a possible separator too, since this is Unix
 convention and upstream may change to follow this convention in the future.
Forwarded: no
Last-Update: 2025-10-22

--- a/src/fastrpc_apps_user.c
+++ b/src/fastrpc_apps_user.c
@@ -3437,11 +3437,16 @@
   char *absName = NULL;
   char *shell_absName = NULL;
   char *domain_str = NULL;
-  uint16_t shell_absNameLen = 0, absNameLen = 0;
-  ;
+  char *lib_path_env = NULL;
+  char *lib_path_env_dup = NULL;
+  char *saveptr = NULL;
+  char *path = NULL;
   int nErr = AEE_SUCCESS;
   int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id);
   const char *shell_name = SIGNED_SHELL;
+  uint16_t shell_absNameLen = 0, absNameLen = 0;
+  size_t pathLen = 0;
+  int found = 0;
 
   if (1 == unsigned_shell) {
     shell_name = UNSIGNED_SHELL;
@@ -3450,60 +3455,76 @@
   if (domain == MDSP_DOMAIN_ID) {
     return nErr;
   }
-  VERIFYC(NULL != (domain_str = (char *)malloc(sizeof(domain))), AEE_ENOMEMORY);
-  snprintf(domain_str, sizeof(domain), "%d", domain);
+  VERIFYC(NULL != (domain_str = (char *)malloc(16)), AEE_ENOMEMORY);
+  snprintf(domain_str, 16, "%d", domain);
 
   shell_absNameLen = strlen(shell_name) + strlen(domain_str) + 1;
 
   VERIFYC(NULL !=
-              (shell_absName = (char *)malloc(sizeof(char) * shell_absNameLen)),
+              (shell_absName = (char *)malloc(shell_absNameLen)),
           AEE_ENOMEMORY);
   strlcpy(shell_absName, shell_name, shell_absNameLen);
 
   strlcat(shell_absName, domain_str, shell_absNameLen);
 
-  absNameLen = strlen(DSP_MOUNT_LOCATION) + shell_absNameLen + 1;
-  VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)),
-          AEE_ENOMEMORY);
-  strlcpy(absName, DSP_MOUNT_LOCATION, absNameLen);
-  strlcat(absName, shell_absName, absNameLen);
-
-  nErr = apps_std_fopen(absName, "r", fh);
-  if (nErr) {
-    absNameLen = strlen(DSP_DOM_LOCATION) + shell_absNameLen + 1;
-    VERIFYC(NULL !=
-                (absName = (char *)realloc(absName, sizeof(char) * absNameLen)),
-            AEE_ENOMEMORY);
-    strlcpy(absName, DSP_MOUNT_LOCATION, absNameLen);
-    strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen);
-    strlcat(absName, "/", absNameLen);
-    strlcat(absName, shell_absName, absNameLen);
-    nErr = apps_std_fopen(absName, "r", fh);
+  lib_path_env = getenv("DSP_LIBRARY_PATH");
+  if (!lib_path_env || !*lib_path_env) {
+    nErr = AEE_EBADPARM;
+    goto bail;
   }
-  if (nErr) {
-    absNameLen = strlen(VENDOR_DSP_LOCATION) + shell_absNameLen + 1;
-    VERIFYC(NULL !=
-                (absName = (char *)realloc(absName, sizeof(char) * absNameLen)),
-            AEE_ENOMEMORY);
-    strlcpy(absName, VENDOR_DSP_LOCATION, absNameLen);
-    strlcat(absName, shell_absName, absNameLen);
+
+  // Defensive copy for strtok_r
+  VERIFYC(NULL != (lib_path_env_dup = strdup(lib_path_env)), AEE_ENOMEMORY);
+
+  for (path = strtok_r(lib_path_env_dup, ":;", &saveptr); path != NULL; path = strtok_r(NULL, ":;", &saveptr)) {
+    if (!*path) continue;
+
+    pathLen = strlen(path);
+    absNameLen = pathLen + shell_absNameLen + 2; // +2 for possible '/' and '\0'
+    VERIFYC(NULL != (absName = (char *)malloc(absNameLen)), AEE_ENOMEMORY);
+
+    snprintf(absName, absNameLen, "%s%s%s", path, (path[pathLen-1] == '/' ? "" : "/"), shell_absName);
 
     nErr = apps_std_fopen(absName, "r", fh);
-    if (nErr) {
-      absNameLen = strlen(VENDOR_DOM_LOCATION) + shell_absNameLen + 1;
-      VERIFYC(NULL != (absName =
-                           (char *)realloc(absName, sizeof(char) * absNameLen)),
-              AEE_ENOMEMORY);
-      strlcpy(absName, VENDOR_DSP_LOCATION, absNameLen);
-      strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen);
-      strlcat(absName, "/", absNameLen);
-      strlcat(absName, shell_absName, absNameLen);
+    if (!nErr) {
+      found = 1;
+      break;
+    }
+    free(absName);
+    absName = NULL;
+
+    if (SUBSYSTEM_NAME[domain]) {
+      size_t subsysLen = strlen(SUBSYSTEM_NAME[domain]);
+      absNameLen = pathLen + subsysLen + shell_absNameLen + 3; // +3 for two '/' and '\0'
+      VERIFYC(NULL != (absName = (char *)malloc(absNameLen)), AEE_ENOMEMORY);
+
+      snprintf(absName, absNameLen, "%s%s%s/%s", path, (path[pathLen-1] == '/' ? "" : "/"), SUBSYSTEM_NAME[domain], shell_absName);
 
       nErr = apps_std_fopen(absName, "r", fh);
+      if (!nErr) {
+        found = 1;
+        break;
+      }
+      free(absName);
+      absName = NULL;
     }
   }
-  if (!nErr)
+
+  if (found && absName) {
     FARF(RUNTIME_RPC_HIGH, "Successfully opened %s, domain %d", absName, domain);
+    nErr = AEE_SUCCESS;
+  } else {
+    nErr = nErr ? nErr : AEE_ENOMEMORY;
+    if (domain == SDSP_DOMAIN_ID && fh != NULL) {
+      nErr = AEE_SUCCESS;
+      *fh = -1;
+    } else {
+      FARF(ERROR,
+           "Error 0x%x: %s failed for domain %d using DSP_LIBRARY_PATH=%s (errno %s)\n",
+           nErr, __func__, domain, lib_path_env ? lib_path_env : "(unset)", strerror(errno));
+    }
+  }
+
 bail:
   if (domain_str) {
     free(domain_str);
@@ -3517,17 +3538,9 @@
     free(absName);
     absName = NULL;
   }
-  if (nErr != AEE_SUCCESS) {
-    if (domain == SDSP_DOMAIN_ID && fh != NULL) {
-      nErr = AEE_SUCCESS;
-      *fh = -1;
-    } else {
-      FARF(ERROR,
-           "Error 0x%x: %s failed for domain %d search paths used are %s, %s, "
-           "%s (errno %s)\n",
-           nErr, __func__, domain, DSP_MOUNT_LOCATION, VENDOR_DSP_LOCATION,
-           VENDOR_DOM_LOCATION, strerror(errno));
-    }
+  if (lib_path_env_dup) {
+    free(lib_path_env_dup);
+    lib_path_env_dup = NULL;
   }
   return nErr;
 }
