From 6b93af26a97b9edd97ae7906b0769a623730cf3d Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 6 Jul 2013 21:59:03 -0700 Subject: [PATCH] Add utility to get/set the software write protect flag --- Makefile.am | 12 ++- doc/iscsi-swp.1.xml | 146 ++++++++++++++++++++++++++ src/iscsi-swp.c | 251 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 406 insertions(+), 3 deletions(-) create mode 100644 doc/iscsi-swp.1.xml create mode 100644 src/iscsi-swp.c diff --git a/Makefile.am b/Makefile.am index 4d861ea..61cfaba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,11 +9,11 @@ LDADD = lib/libiscsi.la XSLTPROC = /usr/bin/xsltproc # Manpages -man1_MANS = doc/iscsi-inq.1 doc/iscsi-ls.1 +man1_MANS = doc/iscsi-inq.1 doc/iscsi-ls.1 doc/iscsi-swp.1 EXTRA_DIST = autogen.sh COPYING LICENCE-GPL-2.txt LICENCE-LGPL-2.1.txt \ packaging/RPM/libiscsi.spec.in packaging/RPM/makerpms.sh \ - doc/iscsi-inq.1.xml doc/iscsi-ls.1.xml + doc/iscsi-inq.1.xml doc/iscsi-ls.1.xml doc/iscsi-swp.1.xml # Simplify conditions below by declaring variables as empty @@ -50,9 +50,11 @@ lib_libiscsi_la_LDFLAGS = \ # libiscsi utilities -bin_PROGRAMS += bin/iscsi-inq bin/iscsi-ls bin/iscsi-readcapacity16 +bin_PROGRAMS += bin/iscsi-inq bin/iscsi-ls bin/iscsi-readcapacity16 \ + bin/iscsi-swp bin_iscsi_inq_SOURCES = src/iscsi-inq.c bin_iscsi_ls_SOURCES = src/iscsi-ls.c +bin_iscsi_swp_SOURCES = src/iscsi-swp.c bin_iscsi_readcapacity16_SOURCES = src/iscsi-readcapacity16.c # Other examples @@ -387,3 +389,7 @@ doc/iscsi-ls.1: doc/iscsi-ls.1.xml doc/iscsi-inq.1: doc/iscsi-inq.1.xml -test -z "$(XSLTPROC)" || $(XSLTPROC) -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< + +doc/iscsi-swp.1: doc/iscsi-swp.1.xml + -test -z "$(XSLTPROC)" || $(XSLTPROC) -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< + diff --git a/doc/iscsi-swp.1.xml b/doc/iscsi-swp.1.xml new file mode 100644 index 0000000..ec1c683 --- /dev/null +++ b/doc/iscsi-swp.1.xml @@ -0,0 +1,146 @@ + + + + + + iscsi-swp + 1 + iscsi-swp + iscsi-swp: get/set software write protect + + + + + iscsi-swp + Utility to get/set software write protect on an iSCSI LUN + + + + + iscsi-swp [ OPTIONS ] <ISCSI-PORTAL> + + + + iscsi-ls + -i --initiator-name=<IQN> + -s --swp {on|off} + -d --debug=<INTEGER> + -? --help + --usage + + + + + DESCRIPTION + + iscsi-swp is a utility to get or set the software write protect on an iSCSI LUN. + + + + ISCSI PORTAL URL FORMAT + + iSCSI portal format is 'iscsi://[<username>[%<password>]@]<host>[:<port>]' + + + + Username and password are only required if the target requires CHAP + authentication. Optionally you can specify the username and password via + the environment variables LIBISCSI_CHAP_USERNAME and + LIBISCSI_CHAP_PASSWORD. + + + + Host can be specified either as a hostname, an IPv4 address or an + IPv6 address. + + Examples: + + iscsi://192.0.2.1 + iscsi://[2001:DB8::1]:3261 + iscsi://ronnie%password@iscsi.example.com + + + + + Port is the TCP port on the target to connect to. Default is 3260. + + + + + OPTIONS + + + + -i --initiator-name=<IQN> + + + This specifies the initiator-name that iscsi-ls will use when + logging in to the target. + + + The default name is + 'iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-ls' but you can use + this argument to override this. This is mainly needed for cases + where the target is configured with access-control to only + allow discovery logins from known initiator-names. + + + + + -s --swp {on|off} + + + By default iscsi-swp will only print the current setting of + the software write protect bit. By using this argument + iscsi-swp will also try to set/clear the flag on the target LUN. + + +iscsi-swp iscsi://127.0.0.1/iqn.ronnie.test/1 +SWP:0 + +iscsi-swp iscsi://127.0.0.1/iqn.ronnie.test/1 --swp on +SWP:0 +Turning SWP ON + +iscsi-swp iscsi://127.0.0.1/iqn.ronnie.test/1 --swp off +SWP:0 +Turning SWP OFF + + + + + -d --debug=<INTEGER> + + + Debug level. + + + + + -? --help + + + Display basic help text. + + + + + --usage + + + Display basic usage text. + + + + + + + + SEE ALSO + + iscsi-inq(1), iscsi-ls(1) + + + + + diff --git a/src/iscsi-swp.c b/src/iscsi-swp.c new file mode 100644 index 0000000..e118c82 --- /dev/null +++ b/src/iscsi-swp.c @@ -0,0 +1,251 @@ +/* + Copyright (C) 2013 by Ronnie Sahlberg + + 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 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 . +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_POLL_H +#include +#endif + +#include +#include +#include +#include +#include +#include "iscsi.h" +#include "scsi-lowlevel.h" + +#ifndef discard_const +#define discard_const(ptr) ((void *)((intptr_t)(ptr))) +#endif + +const char *initiator = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-swp"; + + +void print_usage(void) +{ + fprintf(stderr, "Usage: iscsi-swp [-?] [-?|--help] [--usage] [-i|--initiator-name=iqn-name]\n" + "\t\t[-s|--swp {on|off}] \n"); +} + +void print_help(void) +{ + fprintf(stderr, "Usage: iscsi-swp [OPTION...] \n"); + fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); + fprintf(stderr, " -s, --swp={on|off} Turn software write protect on/off\n"); + fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Help options:\n"); + fprintf(stderr, " -?, --help Show this help message\n"); + fprintf(stderr, " --usage Display brief usage message\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "iSCSI URL format : %s\n", ISCSI_URL_SYNTAX); + fprintf(stderr, "\n"); + fprintf(stderr, " is either of:\n"); + fprintf(stderr, " \"hostname\" iscsi.example\n"); + fprintf(stderr, " \"ipv4-address\" 10.1.1.27\n"); + fprintf(stderr, " \"ipv6-address\" [fce0::1]\n"); +} + +int main(int argc, char *argv[]) +{ + struct iscsi_context *iscsi; + const char *url = NULL; + struct iscsi_url *iscsi_url = NULL; + int show_help = 0, show_usage = 0, debug = 0; + int c; + int ret = 0; + int swp = 0; + struct scsi_task *sense_task = NULL; + struct scsi_task *select_task = NULL; + struct scsi_mode_sense *ms; + struct scsi_mode_page *mp; + + static struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"usage", no_argument, NULL, 'u'}, + {"debug", no_argument, NULL, 'd'}, + {"initiator_name", required_argument, NULL, 'i'}, + {"swp", required_argument, NULL, 's'}, + {0, 0, 0, 0} + }; + int option_index; + + while ((c = getopt_long(argc, argv, "h?udi:s:", long_options, + &option_index)) != -1) { + switch (c) { + case 'h': + case '?': + show_help = 1; + break; + case 'u': + show_usage = 1; + break; + case 'd': + debug = 1; + break; + case 'i': + initiator = optarg; + break; + case 's': + if (!strcmp(optarg, "on") || !strcmp(optarg, "ON")) { + swp = 1; + } + if (!strcmp(optarg, "off") || !strcmp(optarg, "OFF")) { + swp = 2; + } + break; + default: + fprintf(stderr, "Unrecognized option '%c'\n\n", c); + print_help(); + exit(0); + } + } + + if (show_help != 0) { + print_help(); + exit(0); + } + + if (show_usage != 0) { + print_usage(); + exit(0); + } + + iscsi = iscsi_create_context(initiator); + if (iscsi == NULL) { + fprintf(stderr, "Failed to create context\n"); + exit(10); + } + + if (debug > 0) { + iscsi_set_log_level(iscsi, debug); + iscsi_set_log_fn(iscsi, iscsi_log_to_stderr); + } + + url = strdup(argv[optind]); + if (url == NULL) { + fprintf(stderr, "You must specify the URL\n"); + print_usage(); + ret = 10; + goto finished; + } + iscsi_url = iscsi_parse_full_url(iscsi, url); + + free(discard_const(url)); + + if (iscsi_url == NULL) { + fprintf(stderr, "Failed to parse URL: %s\n", + iscsi_get_error(iscsi)); + ret = 10; + goto finished; + } + + iscsi_set_targetname(iscsi, iscsi_url->target); + iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); + iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); + + if (iscsi_url->user != NULL) { + if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { + fprintf(stderr, "Failed to set initiator username and password\n"); + ret = 10; + goto finished; + } + } + + if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { + fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi)); + ret = 10; + goto finished; + } + + + sense_task = iscsi_modesense6_sync(iscsi, iscsi_url->lun, + 0, SCSI_MODESENSE_PC_CURRENT, + SCSI_MODESENSE_PAGECODE_CONTROL, + 0, 255); + if (sense_task == NULL) { + printf("Failed to send MODE_SENSE6 command: %s\n", + iscsi_get_error(iscsi)); + ret = 10; + goto finished; + } + if (sense_task->status != SCSI_STATUS_GOOD) { + printf("MODE_SENSE6 failed: %s\n", + iscsi_get_error(iscsi)); + ret = 10; + goto finished; + } + ms = scsi_datain_unmarshall(sense_task); + if (ms == NULL) { + printf("failed to unmarshall mode sense datain blob\n"); + ret = 10; + goto finished; + } + mp = scsi_modesense_get_page(ms, SCSI_MODESENSE_PAGECODE_CONTROL, 0); + if (mp == NULL) { + printf("failed to read control mode page\n"); + ret = 10; + goto finished; + } + + printf("SWP:%d\n", mp->control.swp); + + switch (swp) { + case 1: + mp->control.swp = 1; + break; + case 2: + mp->control.swp = 0; + break; + default: + goto finished; + } + + printf("Turning SWP %s\n", (swp == 1) ? "ON" : "OFF"); + select_task = iscsi_modeselect6_sync(iscsi, iscsi_url->lun, + 1, 0, mp); + if (select_task == NULL) { + printf("Failed to send MODE_SELECT6 command: %s\n", + iscsi_get_error(iscsi)); + ret = 10; + goto finished; + } + if (select_task->status != SCSI_STATUS_GOOD) { + printf("MODE_SELECT6 failed: %s\n", + iscsi_get_error(iscsi)); + ret = 10; + goto finished; + } + + +finished: + if (sense_task != NULL) { + scsi_free_scsi_task(sense_task); + } + if (select_task != NULL) { + scsi_free_scsi_task(select_task); + } + if (iscsi_url != NULL) { + iscsi_destroy_url(iscsi_url); + } + iscsi_logout_sync(iscsi); + iscsi_destroy_context(iscsi); + return ret; +} +