From cb475206789cbb427e64e801579506ca9f1a76fe Mon Sep 17 00:00:00 2001
From: Joao Afonso <joao.afonso@cern.ch>
Date: Wed, 3 Nov 2021 14:18:46 +0100
Subject: [PATCH] Remove the need for special Spectra Logic SMC configuration

---
 mediachanger/castorrmc/h/rmc_smcsubr.h        |  3 +-
 mediachanger/castorrmc/h/spectra_like_libs.h  | 22 ++++++
 mediachanger/castorrmc/rmc/CMakeLists.txt     |  2 +
 mediachanger/castorrmc/rmc/rmc_procreq.c      |  2 +-
 mediachanger/castorrmc/rmc/rmc_smcsubr.c      | 16 ++---
 mediachanger/castorrmc/rmc/smc.c              |  8 +--
 .../castorrmc/rmc/spectra_like_libs.c         | 72 +++++++++++++++++++
 7 files changed, 108 insertions(+), 17 deletions(-)
 create mode 100644 mediachanger/castorrmc/h/spectra_like_libs.h
 create mode 100644 mediachanger/castorrmc/rmc/spectra_like_libs.c

diff --git a/mediachanger/castorrmc/h/rmc_smcsubr.h b/mediachanger/castorrmc/h/rmc_smcsubr.h
index 24228c43a0..a109f29886 100644
--- a/mediachanger/castorrmc/h/rmc_smcsubr.h
+++ b/mediachanger/castorrmc/h/rmc_smcsubr.h
@@ -49,7 +49,8 @@ EXTERN_C int smc_find_cartridge(
   const int type,
   const int start,
   const int nbelem,
-  struct smc_element_info element_info[]);
+  struct smc_element_info element_info[],
+  struct robot_info *const robot_info);
 
 EXTERN_C int smc_lasterror(
   struct smc_status *const smc_stat,
diff --git a/mediachanger/castorrmc/h/spectra_like_libs.h b/mediachanger/castorrmc/h/spectra_like_libs.h
new file mode 100644
index 0000000000..be7be63dc4
--- /dev/null
+++ b/mediachanger/castorrmc/h/spectra_like_libs.h
@@ -0,0 +1,22 @@
+/*
+ * @project        The CERN Tape Archive (CTA)
+ * @copyright      Copyright(C) 2003-2021 CERN
+ * @license        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 3 of the License, 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.
+ *
+ *                 You should have received a copy of the GNU General Public License
+ *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "smc_struct.h"
+
+int is_library_spectra_like(const struct robot_info *const robot_info);
diff --git a/mediachanger/castorrmc/rmc/CMakeLists.txt b/mediachanger/castorrmc/rmc/CMakeLists.txt
index 63e53e84d6..f95cc575dd 100644
--- a/mediachanger/castorrmc/rmc/CMakeLists.txt
+++ b/mediachanger/castorrmc/rmc/CMakeLists.txt
@@ -25,6 +25,7 @@ set (RMCD_SRC_FILES
   rmc_send_scsi_cmd.c
   rmc_serv.c
   rmc_smcsubr.c
+  spectra_like_libs.c
 )
 
 if(CMAKE_COMPILER_IS_GNUCC)
@@ -55,6 +56,7 @@ set (SMC_SRC_FILES
   rmc_mount.c
   rmc_read_elem_status.c
   send2rmc.c
+  spectra_like_libs.c
   smc.c)
 add_executable(cta-smc ${SMC_SRC_FILES})
 target_link_libraries(cta-smc ctarmccommon)
diff --git a/mediachanger/castorrmc/rmc/rmc_procreq.c b/mediachanger/castorrmc/rmc/rmc_procreq.c
index aa8298fae4..8f058f3e8b 100644
--- a/mediachanger/castorrmc/rmc/rmc_procreq.c
+++ b/mediachanger/castorrmc/rmc/rmc_procreq.c
@@ -137,7 +137,7 @@ int rmc_srv_findcart(const struct rmc_srv_rqst_context *const rqst_context) {
 	}
 	c = smc_find_cartridge (extended_robot_info.smc_fd,
 	    extended_robot_info.smc_ldr, template, type, startaddr,
-	    nbelem, element_info);
+	    nbelem, element_info, &extended_robot_info.robot_info);
 	if (c < 0) {
 		c = smc_lasterror (&smc_status, &msgaddr);
 		free (element_info);
diff --git a/mediachanger/castorrmc/rmc/rmc_smcsubr.c b/mediachanger/castorrmc/rmc/rmc_smcsubr.c
index 0d8d5b8740..95cfec32b5 100644
--- a/mediachanger/castorrmc/rmc/rmc_smcsubr.c
+++ b/mediachanger/castorrmc/rmc/rmc_smcsubr.c
@@ -34,9 +34,9 @@
 #include "scsictl.h"
 #include "serrno.h"
 #include "smc_constants.h"
+#include "spectra_like_libs.h"
 
 #define	RBT_XTRA_PROC 10
-#define PATH_CONF "/etc/cta/cta-smc.conf"
 static struct smc_status smc_status;
 static const char *smc_msgaddr;
 
@@ -437,7 +437,8 @@ int smc_find_cartridge(
 	const int type,
 	const int start,
 	const int nbelem,
-	struct smc_element_info element_info[])
+	struct smc_element_info element_info[],
+	struct robot_info *const robot_info)
 {
 	unsigned char cdb[12];
 	char func[16];
@@ -448,15 +449,12 @@ int smc_find_cartridge(
 	char sense[MAXSENSE];
         int pause_mode = 1;
         int nretries = 0;
-        char *smcLibraryType;
 
 	strncpy(func, "findWithVT", sizeof(func));
 	func[sizeof(func) - 1] = '\0';
 
         /* Skip the 0xB6 cdb command if the tape library is Spectra like */
-        smcLibraryType = getconfent_fromfile(PATH_CONF,"SMC","LIBRARY_TYPE",0);
-        if (NULL != smcLibraryType &&
-            0 == strcasecmp(smcLibraryType,"SPECTRA")) {
+        if (is_library_spectra_like(robot_info)) {
           rc = smc_find_cartridgeWithoutSendVolumeTag (fd, rbtdev, find_template, type, start, nbelem,
                                     element_info);
           if (rc >= 0)
@@ -757,7 +755,7 @@ int smc_dismount (
     /* check that the vid is in a slot before returning */
     while (1) {
           struct smc_element_info vol_element_info;
-          if (0 > smc_find_cartridge (fd, loader, drive_element_info.name, 0, 0, 1, &vol_element_info)) {
+          if (0 > smc_find_cartridge (fd, loader, drive_element_info.name, 0, 0, 1, &vol_element_info, robot_info)) {
               const int smc_error = smc_lasterror (&smc_status, &msgaddr);
               rmc_usrmsg ( rpfd, func, SR017, "find_cartridge", drive_element_info.name, msgaddr);
               return (smc_error);
@@ -791,7 +789,7 @@ int smc_export (
 	func[sizeof(func) - 1] = '\0';
 
 	{
-		const int smc_find_cartridge_rc = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info);
+		const int smc_find_cartridge_rc = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info, robot_info);
 		if (0 > smc_find_cartridge_rc) {
 			const int smc_lasterror_rc = smc_lasterror (&smc_status, &msgaddr);
 			rmc_usrmsg ( rpfd, func, SR017, "find_cartridge", vid, msgaddr);
@@ -958,7 +956,7 @@ int smc_mount (
 	strncpy (func, "smc_mount", sizeof(func));
 	func[sizeof(func) - 1] = '\0';
 
-	if ((c = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info)) < 0) {
+	if ((c = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info, robot_info)) < 0) {
 		c = smc_lasterror (&smc_status, &msgaddr);
 		rmc_usrmsg ( rpfd, func, SR017, "find_cartridge", vid, msgaddr);
 		return (c);
diff --git a/mediachanger/castorrmc/rmc/smc.c b/mediachanger/castorrmc/rmc/smc.c
index 2058a6dbf8..949e8e9175 100644
--- a/mediachanger/castorrmc/rmc/smc.c
+++ b/mediachanger/castorrmc/rmc/smc.c
@@ -27,12 +27,12 @@
 #include "smc_constants.h"
 #include "getconfent.h"
 #include "getopt.h"
+#include "spectra_like_libs.h"
 
 #include <ctype.h>
 			/* exit codes */
 
 #define	USERR	1
-#define PATH_CONF "/etc/cta/cta-smc.conf"
 #define TEXT_RED    "\x1b[31;1m"
 #define TEXT_NORMAL "\x1b[0m"
 
@@ -122,7 +122,6 @@ static int smc_qdrive (
         int c;
         struct smc_element_info *element_info;
 	int nbelem;
-        char *smcLibraryType;
         char useSpectraLib;
 
 	if (drvord < 0) {
@@ -140,10 +139,7 @@ static int smc_qdrive (
 		free (element_info);
 		return (c);
 	}
-        useSpectraLib=0;
-        smcLibraryType = getconfent_fromfile(PATH_CONF,"SMC","LIBRARY_TYPE",0);
-        if (NULL != smcLibraryType &&
-            0 == strcasecmp(smcLibraryType,"SPECTRA")) {
+        if (is_library_spectra_like(robot_info)) {
           useSpectraLib = 1;
         }
         if (isJsonEnabled) {
diff --git a/mediachanger/castorrmc/rmc/spectra_like_libs.c b/mediachanger/castorrmc/rmc/spectra_like_libs.c
new file mode 100644
index 0000000000..04d5ddefc3
--- /dev/null
+++ b/mediachanger/castorrmc/rmc/spectra_like_libs.c
@@ -0,0 +1,72 @@
+/*
+ * @project        The CERN Tape Archive (CTA)
+ * @copyright      Copyright(C) 1998-2021 CERN
+ * @license        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 3 of the License, 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.
+ *
+ *                 You should have received a copy of the GNU General Public License
+ *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include "spectra_like_libs.h"
+
+#define N_LIBS (sizeof(spectra_like_libs) / sizeof(spectra_like_libs[0]))
+
+struct vendor_product_id_pair {
+  char vendor_id[9];
+  char product_id[17];
+};
+
+static struct vendor_product_id_pair const spectra_like_libs[] = {
+  /* To match all products of a specific vendor, set the product_id as empty string */
+  {"SPECTRA", ""       }, /*Match all SPECTRA libraries */
+  {"IBM"    , "3573-TL"}  /*Match IBM libraries, model 3573-TL*/
+};
+
+void trim_trailing_spaces(char * str) {
+    int pos;
+    pos = strlen(str) - 1;
+    for (; pos >= 0 && isspace(str[pos]); pos--) {
+        str[pos] = '\0';
+    }
+}
+
+int is_library_spectra_like(const struct robot_info *const robot_info) {
+    int isSpectraLike;
+    char vendorId[9];
+    char productId[17];
+    unsigned int i;
+
+    memcpy (vendorId, robot_info->inquiry, 8);
+    memcpy (productId, robot_info->inquiry + 8, 16);
+    vendorId[8] = '\0';
+    productId[16] = '\0';
+    
+    /* Trim any whitespaces in excess */
+    trim_trailing_spaces(vendorId);
+    trim_trailing_spaces(productId);
+
+    /* find if the vendor (and product) are in the list 'spectra_like_libs' */
+    isSpectraLike = 0;
+    for (i=0; i < N_LIBS && !isSpectraLike; i++) {
+        if (strcasecmp(vendorId, spectra_like_libs[i].vendor_id) == 0) {
+            if (
+                spectra_like_libs[i].product_id[0] == '\0'
+                || strcasecmp(productId, spectra_like_libs[i].product_id) == 0
+            ) {
+                isSpectraLike = 1;
+            }
+        }
+    }
+    
+    return isSpectraLike;
+}
-- 
GitLab