640 number_to_scaled_string is duplicated in several commands
[unleashed.git] / usr / src / cmd / ndmpadm / ndmpadm_main.c
blob6cc7cbb7bc764473d1152512bd0b6a49d06b2714
1 /*
2 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
4 */
6 /*
7 * BSD 3 Clause License
9 * Copyright (c) 2007, The Storage Networking Industry Association.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
22 * - Neither the name of The Storage Networking Industry Association (SNIA)
23 * nor the names of its contributors may be used to endorse or promote
24 * products derived from this software without specific prior written
25 * permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
39 #include <assert.h>
40 #include <ctype.h>
41 #include <libgen.h>
42 #include <libintl.h>
43 #include <locale.h>
44 #include <stddef.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <strings.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <sys/stat.h>
51 #include <door.h>
52 #include <sys/mman.h>
53 #include <libndmp.h>
54 #include "ndmpadm.h"
56 typedef enum {
57 HELP_GET_CONFIG,
58 HELP_SET_CONFIG,
59 HELP_SHOW_DEVICES,
60 HELP_SHOW_SESSIONS,
61 HELP_KILL_SESSIONS,
62 HELP_ENABLE_AUTH,
63 HELP_DISABLE_AUTH
64 } ndmp_help_t;
66 typedef struct ndmp_command {
67 const char *nc_name;
68 int (*func)(int argc, char **argv,
69 struct ndmp_command *cur_cmd);
70 ndmp_help_t nc_usage;
71 } ndmp_command_t;
73 static int ndmp_get_config(int, char **, ndmp_command_t *);
74 static int ndmp_set_config(int, char **, ndmp_command_t *);
75 static int ndmp_show_devices(int, char **, ndmp_command_t *);
76 static int ndmp_show_sessions(int, char **, ndmp_command_t *);
77 static int ndmp_kill_sessions(int, char **, ndmp_command_t *);
78 static int ndmp_enable_auth(int, char **, ndmp_command_t *);
79 static int ndmp_disable_auth(int, char **, ndmp_command_t *);
80 static void ndmp_get_config_process(char *);
81 static void ndmp_set_config_process(char *arg);
82 static int ndmp_get_password(char **);
84 static ndmp_command_t command_table[] = {
85 { "get", ndmp_get_config, HELP_GET_CONFIG },
86 { "set", ndmp_set_config, HELP_SET_CONFIG },
87 { "show-devices", ndmp_show_devices, HELP_SHOW_DEVICES },
88 { "show-sessions", ndmp_show_sessions, HELP_SHOW_SESSIONS },
89 { "kill-sessions", ndmp_kill_sessions, HELP_KILL_SESSIONS },
90 { "enable", ndmp_enable_auth, HELP_ENABLE_AUTH },
91 { "disable", ndmp_disable_auth, HELP_DISABLE_AUTH }
94 #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
96 static char *prop_table[] = {
97 "debug-path",
98 "dump-pathnode",
99 "tar-pathnode",
100 "ignore-ctime",
101 "token-maxseq",
102 "version",
103 "dar-support",
104 "tcp-port",
105 "backup-quarantine",
106 "restore-quarantine",
107 "overwrite-quarantine",
108 "zfs-force-override",
109 "drive-type",
110 "debug-mode"
113 #define NDMPADM_NPROP (sizeof (prop_table) / sizeof (prop_table[0]))
115 typedef struct ndmp_auth {
116 const char *auth_type;
117 const char *username;
118 const char *password;
119 } ndmp_auth_t;
121 static ndmp_auth_t ndmp_auth_table[] = {
122 { "cram-md5", "cram-md5-username", "cram-md5-password" },
123 { "cleartext", "cleartext-username", "cleartext-password" }
125 #define NAUTH (sizeof (ndmp_auth_table) / sizeof (ndmp_auth_table[0]))
126 #define NDMP_PASSWORD_RETRIES 3
128 #if !defined(TEXT_DOMAIN)
129 #define TEXT_DOMAIN "SYS_TEST"
130 #endif
132 static const char *
133 get_usage(ndmp_help_t idx)
135 switch (idx) {
136 case HELP_SET_CONFIG:
137 return ("\tset [-p] <property=value> [[-p] property=value] "
138 "...\n");
139 case HELP_GET_CONFIG:
140 return ("\tget [-p] [property] [[-p] property] ...\n");
141 case HELP_SHOW_DEVICES:
142 return ("\tshow-devices\n");
143 case HELP_SHOW_SESSIONS:
144 return ("\tshow-sessions [-i tape,scsi,data,mover] [id] ...\n");
145 case HELP_KILL_SESSIONS:
146 return ("\tkill-sessions <id ...>\n");
147 case HELP_ENABLE_AUTH:
148 return ("\tenable <-a auth-type> <-u username>\n");
149 case HELP_DISABLE_AUTH:
150 return ("\tdisable <-a auth-type>\n");
153 return (NULL);
157 * Display usage message. If we're inside a command, display only the usage for
158 * that command. Otherwise, iterate over the entire command table and display
159 * a complete usage message.
161 static void
162 usage(boolean_t requested, ndmp_command_t *current_command)
164 int i;
165 boolean_t show_properties = B_FALSE;
166 FILE *fp = requested ? stdout : stderr;
168 if (current_command == NULL) {
169 (void) fprintf(fp,
170 gettext("Usage: ndmpadm subcommand args ...\n"));
171 (void) fprintf(fp,
172 gettext("where 'command' is one of the following:\n\n"));
174 for (i = 0; i < NCOMMAND; i++) {
175 (void) fprintf(fp, "%s",
176 get_usage(command_table[i].nc_usage));
178 (void) fprintf(fp, gettext("\t\twhere %s can be either "
179 "%s or %s\n"), "'auth-type'", "'cram-md5'", "'cleartext'");
180 } else {
181 (void) fprintf(fp, gettext("Usage:\n"));
182 (void) fprintf(fp, "%s", get_usage(current_command->nc_usage));
183 if ((current_command->nc_usage == HELP_ENABLE_AUTH) ||
184 (current_command->nc_usage == HELP_DISABLE_AUTH))
185 (void) fprintf(fp, gettext("\t\twhere %s can be either "
186 "%s or %s\n"),
187 "'auth-type'", "'cram-md5'", "'cleartext'");
190 if (current_command != NULL &&
191 (strcmp(current_command->nc_name, "set") == 0))
192 show_properties = B_TRUE;
194 if (show_properties) {
195 (void) fprintf(fp,
196 gettext("\nThe following properties are supported:\n"));
198 (void) fprintf(fp, gettext("\n\tPROPERTY"));
199 (void) fprintf(fp, "\n\t%s", "-------------");
200 for (i = 0; i < NDMPADM_NPROP; i++)
201 (void) fprintf(fp, "\n\t%s", prop_table[i]);
202 (void) fprintf(fp, "\n");
205 exit(requested ? 0 : 2);
208 /*ARGSUSED*/
209 static int
210 ndmp_get_config(int argc, char **argv, ndmp_command_t *cur_cmd)
212 char *propval;
213 int i, c;
215 if (argc == 1) {
217 * Get all the properties and variables ndmpadm is allowed
218 * to see.
220 for (i = 0; i < NDMPADM_NPROP; i++) {
221 if (ndmp_get_prop(prop_table[i], &propval)) {
222 (void) fprintf(stdout, "\t%s=\n",
223 prop_table[i]);
224 } else {
225 (void) fprintf(stdout, "\t%s=%s\n",
226 prop_table[i], propval);
227 free(propval);
230 } else if (argc > 1) {
231 while ((c = getopt(argc, argv, ":p:")) != -1) {
232 switch (c) {
233 case 'p':
234 ndmp_get_config_process(optarg);
235 break;
236 case ':':
237 (void) fprintf(stderr, gettext("Option -%c "
238 "requires an operand\n"), optopt);
239 break;
240 case '?':
241 (void) fprintf(stderr, gettext("Unrecognized "
242 "option: -%c\n"), optopt);
246 * optind is initialized to 1 if the -p option is not used,
247 * otherwise index to argv.
249 argc -= optind;
250 argv += optind;
252 for (i = 0; i < argc; i++) {
253 if (strncmp(argv[i], "-p", 2) == 0)
254 continue;
256 ndmp_get_config_process(argv[i]);
259 return (0);
262 static void
263 ndmp_get_config_process(char *arg)
265 int j;
266 char *propval;
268 for (j = 0; j < NDMPADM_NPROP; j++) {
269 if (strcmp(arg, prop_table[j]) == 0) {
270 if (ndmp_get_prop(arg, &propval)) {
271 (void) fprintf(stdout, "\t%s=\n", arg);
272 } else {
273 (void) fprintf(stdout, "\t%s=%s\n",
274 arg, propval);
275 free(propval);
277 break;
280 if (j == NDMPADM_NPROP) {
281 (void) fprintf(stdout, gettext("\t%s is invalid property "
282 "or variable\n"), arg);
286 /*ARGSUSED*/
287 static int
288 ndmp_set_config(int argc, char **argv, ndmp_command_t *cur_cmd)
290 int c, i;
292 if (argc < 2) {
293 (void) fprintf(stderr, gettext("Missing property=value "
294 "argument\n"));
295 usage(B_FALSE, cur_cmd);
297 while ((c = getopt(argc, argv, ":p:")) != -1) {
298 switch (c) {
299 case 'p':
300 ndmp_set_config_process(optarg);
301 break;
302 case ':':
303 (void) fprintf(stderr, gettext("Option -%c "
304 "requires an operand\n"), optopt);
305 break;
306 case '?':
307 (void) fprintf(stderr, gettext("Unrecognized "
308 "option: -%c\n"), optopt);
312 * optind is initialized to 1 if the -p option is not used,
313 * otherwise index to argv.
315 argc -= optind;
316 argv += optind;
318 for (i = 0; i < argc; i++) {
319 if (strncmp(argv[i], "-p", 2) == 0)
320 continue;
322 ndmp_set_config_process(argv[i]);
324 return (0);
327 static void
328 ndmp_set_config_process(char *propname)
330 char *propvalue;
331 int ret, j;
333 if ((propvalue = strchr(propname, '=')) == NULL) {
334 (void) fprintf(stderr, gettext("Missing value in "
335 "property=value argument for %s\n"), propname);
336 return;
338 *propvalue = '\0';
339 propvalue++;
341 if (*propname == '\0') {
342 (void) fprintf(stderr, gettext("Missing property in "
343 "property=value argument for %s\n"), propname);
344 return;
346 for (j = 0; j < NDMPADM_NPROP; j++) {
347 if (strcmp(propname, prop_table[j]) == 0)
348 break;
350 if (j == NDMPADM_NPROP) {
351 (void) fprintf(stdout, gettext("%s is invalid property or "
352 "variable\n"), propname);
353 return;
355 ret = ndmp_set_prop(propname, propvalue);
356 if (ret != -1) {
357 if (!ndmp_door_status()) {
358 if (ndmp_service_refresh() != 0)
359 (void) fprintf(stdout, gettext("Could not "
360 "refesh property of service ndmpd\n"));
362 } else {
363 (void) fprintf(stdout, gettext("Could not set property for "
364 "%s - %s\n"), propname, ndmp_strerror(ndmp_errno));
368 /*ARGSUSED*/
369 static int
370 ndmp_show_devices(int argc, char **argv, ndmp_command_t *cur_cmd)
372 int ret;
373 ndmp_devinfo_t *dip = NULL;
374 size_t size;
376 if (ndmp_door_status()) {
377 (void) fprintf(stdout,
378 gettext("Service ndmpd not running\n"));
379 return (-1);
382 ret = ndmp_get_devinfo(&dip, &size);
384 if (ret == -1)
385 (void) fprintf(stdout,
386 gettext("Could not get device information\n"));
387 else
388 ndmp_devinfo_print(dip, size);
390 ndmp_get_devinfo_free(dip, size);
391 return (0);
394 static int
395 ndmp_show_sessions(int argc, char **argv, ndmp_command_t *cur_cmd)
397 ndmp_session_info_t *sinfo = NULL;
398 ndmp_session_info_t *sp = NULL;
399 uint_t num;
400 int c, ret, i, j;
401 int statarg = 0;
402 char *value;
403 char *type_subopts[] = { "tape", "scsi", "data", "mover", NULL };
405 if (ndmp_door_status()) {
406 (void) fprintf(stdout,
407 gettext("Service ndmpd not running\n"));
408 return (-1);
411 /* Detail output if no option is specified */
412 if (argc == 1) {
413 statarg = NDMP_CAT_ALL;
414 } else {
415 statarg = 0;
416 while ((c = getopt(argc, argv, ":i:")) != -1) {
417 switch (c) {
418 case 'i':
419 while (*optarg != '\0') {
420 switch (getsubopt(&optarg, type_subopts,
421 &value)) {
422 case 0:
423 statarg |= NDMP_CAT_TAPE;
424 break;
425 case 1:
426 statarg |= NDMP_CAT_SCSI;
427 break;
428 case 2:
429 statarg |= NDMP_CAT_DATA;
430 break;
431 case 3:
432 statarg |= NDMP_CAT_MOVER;
433 break;
434 default:
435 (void) fprintf(stderr,
436 gettext("Invalid object "
437 "type '%s'\n"), value);
438 usage(B_FALSE, cur_cmd);
441 break;
442 case ':':
443 (void) fprintf(stderr,
444 gettext("Missing argument for "
445 "'%c' option\n"), optopt);
446 usage(B_FALSE, cur_cmd);
447 break;
448 case '?':
449 (void) fprintf(stderr,
450 gettext("Invalid option '%c'\n"), optopt);
451 usage(B_FALSE, cur_cmd);
454 /* if -i and its argument are not specified, display all */
455 if (statarg == 0)
456 statarg = NDMP_CAT_ALL;
459 * optind is initialized to 1 if the -i option is not used, otherwise
460 * index to argv.
462 argc -= optind;
463 argv += optind;
465 ret = ndmp_get_session_info(&sinfo, &num);
466 if (ret == -1) {
467 (void) fprintf(stdout,
468 gettext("Could not get session information\n"));
469 } else {
470 if (argc == 0) {
471 ndmp_session_all_print(statarg, sinfo, num);
472 } else {
473 for (i = 0; i < argc; i++) {
474 sp = sinfo;
475 for (j = 0; j < num; j++, sp++) {
476 if (sp->nsi_sid == atoi(argv[i])) {
477 ndmp_session_print(statarg, sp);
478 (void) fprintf(stdout, "\n");
479 break;
482 if (j == num) {
483 (void) fprintf(stdout,
484 gettext("Session %d not "
485 "found\n"), atoi(argv[i]));
489 ndmp_get_session_info_free(sinfo, num);
491 return (0);
494 /*ARGSUSED*/
495 static int
496 ndmp_kill_sessions(int argc, char **argv, ndmp_command_t *cur_cmd)
498 int ret, i;
500 if (ndmp_door_status()) {
501 (void) fprintf(stdout,
502 gettext("Service ndmpd not running.\n"));
503 return (-1);
506 /* If no arg is specified, print the usage and exit */
507 if (argc == 1)
508 usage(B_FALSE, cur_cmd);
510 for (i = 1; i < argc; i++) {
511 if (atoi(argv[i]) > 0) {
512 ret = ndmp_terminate_session(atoi(argv[i]));
513 } else {
514 (void) fprintf(stderr,
515 gettext("Invalid argument %s\n"), argv[i]);
516 continue;
518 if (ret == -1)
519 (void) fprintf(stdout,
520 gettext("Session id %d not found.\n"),
521 atoi(argv[i]));
523 return (0);
526 static int
527 ndmp_get_password(char **password)
529 char *pw1, pw2[257];
530 int i;
532 for (i = 0; i < NDMP_PASSWORD_RETRIES; i++) {
534 * getpassphrase use the same buffer to return password, so
535 * copy the result in different buffer, before calling the
536 * getpassphrase again.
538 if ((pw1 =
539 getpassphrase(gettext("Enter new password: "))) != NULL) {
540 (void) strlcpy(pw2, pw1, sizeof (pw2));
541 if ((pw1 =
542 getpassphrase(gettext("Re-enter password: ")))
543 != NULL) {
544 if (strncmp(pw1, pw2, strlen(pw1)) == 0) {
545 *password = pw1;
546 return (0);
547 } else {
548 (void) fprintf(stderr,
549 gettext("Both password did not "
550 "match.\n"));
555 return (-1);
558 static int
559 ndmp_enable_auth(int argc, char **argv, ndmp_command_t *cur_cmd)
561 char *auth_type, *username, *password;
562 int c, i, auth_type_flag = 0;
563 char *enc_password;
565 /* enable <-a auth-type> <-u username> */
566 if (argc != 5) {
567 usage(B_FALSE, cur_cmd);
570 while ((c = getopt(argc, argv, ":a:u:")) != -1) {
571 switch (c) {
572 case 'a':
573 auth_type = strdup(optarg);
574 break;
575 case 'u':
576 username = strdup(optarg);
577 break;
578 case ':':
579 (void) fprintf(stderr, gettext("Option -%c "
580 "requires an operand\n"), optopt);
581 usage(B_FALSE, cur_cmd);
582 break;
583 case '?':
584 (void) fprintf(stderr, gettext("Unrecognized "
585 "option: -%c\n"), optopt);
586 usage(B_FALSE, cur_cmd);
590 if ((auth_type) && (username)) {
591 if (ndmp_get_password(&password)) {
592 (void) fprintf(stderr, gettext("Could not get correct "
593 "password, exiting..."));
594 free(auth_type);
595 free(username);
596 exit(-1);
598 } else {
599 (void) fprintf(stderr, gettext("%s or %s can not be blank"),
600 "'auth-type'", "'username'");
601 free(auth_type);
602 free(username);
603 exit(-1);
606 if ((enc_password = ndmp_base64_encode(password)) == NULL) {
607 (void) fprintf(stdout,
608 gettext("Could not encode password - %s\n"),
609 ndmp_strerror(ndmp_errno));
610 free(auth_type);
611 free(username);
612 exit(-1);
615 for (i = 0; i < NAUTH; i++) {
616 if (strncmp(auth_type, ndmp_auth_table[i].auth_type,
617 strlen(ndmp_auth_table[i].auth_type)) == 0) {
618 auth_type_flag = 1;
619 if ((ndmp_set_prop(ndmp_auth_table[i].username,
620 username)) == -1) {
621 (void) fprintf(stdout,
622 gettext("Could not set username - %s\n"),
623 ndmp_strerror(ndmp_errno));
624 continue;
626 if ((ndmp_set_prop(ndmp_auth_table[i].password,
627 enc_password)) == -1) {
628 (void) fprintf(stdout,
629 gettext("Could not set password - %s\n"),
630 ndmp_strerror(ndmp_errno));
631 continue;
633 if (!ndmp_door_status() &&
634 (ndmp_service_refresh()) != 0) {
635 (void) fprintf(stdout,
636 gettext("Could not refesh ndmpd service "
637 "properties\n"));
641 free(auth_type);
642 free(username);
643 free(enc_password);
645 if (!auth_type_flag)
646 usage(B_FALSE, cur_cmd);
648 return (0);
651 static int
652 ndmp_disable_auth(int argc, char **argv, ndmp_command_t *cur_cmd)
654 char *auth_type;
655 int c, i, auth_type_flag = 0;
657 /* disable <-a auth-type> */
658 if (argc != 3) {
659 usage(B_FALSE, cur_cmd);
662 while ((c = getopt(argc, argv, ":a:")) != -1) {
663 switch (c) {
664 case 'a':
665 auth_type = strdup(optarg);
666 break;
667 case ':':
668 (void) fprintf(stderr, gettext("Option -%c "
669 "requires an operand\n"), optopt);
670 break;
671 case '?':
672 (void) fprintf(stderr, gettext("Unrecognized "
673 "option: -%c\n"), optopt);
676 for (i = 0; i < NAUTH; i++) {
677 if (strncmp(auth_type, ndmp_auth_table[i].auth_type,
678 strlen(ndmp_auth_table[i].auth_type)) == 0) {
679 auth_type_flag = 1;
680 if ((ndmp_set_prop(ndmp_auth_table[i].username,
681 "")) == -1) {
682 (void) fprintf(stdout,
683 gettext("Could not clear username - %s\n"),
684 ndmp_strerror(ndmp_errno));
685 continue;
687 if ((ndmp_set_prop(ndmp_auth_table[i].password,
688 "")) == -1) {
689 (void) fprintf(stdout,
690 gettext("Could not clear password - %s\n"),
691 ndmp_strerror(ndmp_errno));
692 continue;
694 if (!ndmp_door_status() &&
695 (ndmp_service_refresh()) != 0) {
696 (void) fprintf(stdout, gettext("Could not "
697 "refesh ndmpd service properties\n"));
701 free(auth_type);
703 if (!auth_type_flag)
704 usage(B_FALSE, cur_cmd);
706 return (0);
710 main(int argc, char **argv)
712 int ret;
713 int i;
714 char *cmdname;
715 ndmp_command_t *current_command = NULL;
717 (void) setlocale(LC_ALL, "");
718 (void) textdomain(TEXT_DOMAIN);
720 opterr = 0;
722 /* Make sure the user has specified some command. */
723 if (argc < 2) {
724 (void) fprintf(stderr, gettext("Missing command.\n"));
725 usage(B_FALSE, current_command);
728 cmdname = argv[1];
731 * Special case '-?'
733 if (strcmp(cmdname, "-?") == 0)
734 usage(B_TRUE, current_command);
737 * Run the appropriate sub-command.
739 for (i = 0; i < NCOMMAND; i++) {
740 if (strcmp(cmdname, command_table[i].nc_name) == 0) {
741 current_command = &command_table[i];
742 ret = command_table[i].func(argc - 1, argv + 1,
743 current_command);
744 break;
748 if (i == NCOMMAND) {
749 (void) fprintf(stderr, gettext("Unrecognized "
750 "command '%s'\n"), cmdname);
751 usage(B_FALSE, current_command);
754 return (ret);