5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * zonecfg is a lex/yacc based command interpreter used to manage zone
29 * configurations. The lexer (see zonecfg_lex.l) builds up tokens, which
30 * the grammar (see zonecfg_grammar.y) builds up into commands, some of
31 * which takes resources and/or properties as arguments. See the block
32 * comments near the end of zonecfg_grammar.y for how the data structures
33 * which keep track of these resources and properties are built up.
34 *
35 * The resource/property data structures are inserted into a command
36 * structure (see zonecfg.h), which also keeps track of command names,
37 * miscellaneous arguments, and function handlers. The grammar selects
38 * the appropriate function handler, each of which takes a pointer to a
39 * command structure as its sole argument, and invokes it. The grammar
40 * itself is "entered" (a la the Matrix) by yyparse(), which is called
41 * from read_input(), our main driving function. That in turn is called
42 * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each
43 * of which is called from main() depending on how the program was invoked.
44 *
891 "command. This operation is\n\tattempted "
892 "automatically upon completion of a %s "
893 "session."), "zoneadm", cmd_to_str(CMD_REVERT),
894 "zonecfg");
895 return (line);
896 case CMD_REVERT:
897 return (gettext("Reverts configuration back to the "
898 "last committed state. The -F flag\n\tcan be "
899 "used to force the action."));
900 case CMD_CANCEL:
901 return (gettext("Cancels resource/property "
902 "specification."));
903 case CMD_END:
904 return (gettext("Ends resource/property "
905 "specification."));
906 }
907 /* NOTREACHED */
908 return (NULL);
909 }
910
911 /*
912 * Called with verbose TRUE when help is explicitly requested, FALSE for
913 * unexpected errors.
914 */
915
916 void
917 usage(boolean_t verbose, uint_t flags)
918 {
919 FILE *fp = verbose ? stdout : stderr;
920 FILE *newfp;
921 boolean_t need_to_close = B_FALSE;
922 char *pager, *space;
923 int i;
924 struct stat statbuf;
925
926 /* don't page error output */
927 if (verbose && interactive_mode) {
928 if ((pager = getenv("PAGER")) == NULL)
929 pager = PAGER;
930
931 space = strchr(pager, ' ');
932 if (space)
933 *space = '\0';
934 if (stat(pager, &statbuf) == 0) {
935 if (space)
936 *space = ' ';
937 if ((newfp = popen(pager, "w")) != NULL) {
938 need_to_close = B_TRUE;
939 fp = newfp;
940 }
941 } else {
942 zerr(gettext("PAGER %s does not exist (%s)."),
943 pager, strerror(errno));
944 }
945 }
946
947 if (flags & HELP_META) {
948 (void) fprintf(fp, gettext("More help is available for the "
949 "following:\n"));
950 (void) fprintf(fp, "\n\tcommands ('%s commands')\n",
951 cmd_to_str(CMD_HELP));
952 (void) fprintf(fp, "\tsyntax ('%s syntax')\n",
953 cmd_to_str(CMD_HELP));
954 (void) fprintf(fp, "\tusage ('%s usage')\n\n",
955 cmd_to_str(CMD_HELP));
956 (void) fprintf(fp, gettext("You may also obtain help on any "
957 "command by typing '%s <command-name>.'\n"),
958 cmd_to_str(CMD_HELP));
959 }
960 if (flags & HELP_RES_SCOPE) {
961 switch (resource_scope) {
962 case RT_FS:
963 (void) fprintf(fp, gettext("The '%s' resource scope is "
964 "used to configure a file-system.\n"),
965 rt_to_str(resource_scope));
1257 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
1258 pt_to_str(PT_MATCH));
1259 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
1260 pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
1261 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
1262 pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
1263 pt_to_str(PT_VALUE));
1264 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
1265 pt_to_str(PT_NAME));
1266 (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
1267 pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
1268 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
1269 pt_to_str(PT_NCPUS));
1270 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
1271 pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
1272 pt_to_str(PT_LOCKED));
1273 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
1274 pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
1275 }
1276 if (need_to_close)
1277 (void) pclose(fp);
1278 }
1279
1280 static void
1281 zone_perror(char *prefix, int err, boolean_t set_saw)
1282 {
1283 zerr("%s: %s", prefix, zonecfg_strerror(err));
1284 if (set_saw)
1285 saw_error = B_TRUE;
1286 }
1287
1288 /*
1289 * zone_perror() expects a single string, but for remove and select
1290 * we have both the command and the resource type, so this wrapper
1291 * function serves the same purpose in a slightly different way.
1292 */
1293
1294 static void
1295 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
1296 {
1297 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
5326 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5327 continue; /* no match */
5328 output_auth(fp, &lookup);
5329 output = B_TRUE;
5330 }
5331 (void) zonecfg_endadminent(handle);
5332 /*
5333 * If a property n/v pair was specified, warn the user if there was
5334 * nothing to output.
5335 */
5336 if (!output && cmd->cmd_prop_nv_pairs > 0)
5337 (void) printf(gettext("No such %s resource.\n"),
5338 rt_to_str(RT_ADMIN));
5339 }
5340
5341 void
5342 info_func(cmd_t *cmd)
5343 {
5344 FILE *fp = stdout;
5345 boolean_t need_to_close = B_FALSE;
5346 char *pager, *space;
5347 int type;
5348 int res1, res2;
5349 uint64_t swap_limit;
5350 uint64_t locked_limit;
5351 struct stat statbuf;
5352
5353 assert(cmd != NULL);
5354
5355 if (initialize(B_TRUE) != Z_OK)
5356 return;
5357
5358 /* don't page error output */
5359 if (interactive_mode) {
5360 if ((pager = getenv("PAGER")) == NULL)
5361 pager = PAGER;
5362 space = strchr(pager, ' ');
5363 if (space)
5364 *space = '\0';
5365 if (stat(pager, &statbuf) == 0) {
5366 if (space)
5367 *space = ' ';
5368 if ((fp = popen(pager, "w")) != NULL)
5369 need_to_close = B_TRUE;
5370 else
5371 fp = stdout;
5372 } else {
5373 zerr(gettext("PAGER %s does not exist (%s)."),
5374 pager, strerror(errno));
5375 }
5376
5377 setbuf(fp, NULL);
5378 }
5379
5380 if (!global_scope) {
5381 switch (resource_scope) {
5382 case RT_FS:
5383 output_fs(fp, &in_progress_fstab);
5384 break;
5385 case RT_NET:
5386 output_net(fp, &in_progress_nwiftab);
5387 break;
5388 case RT_DEVICE:
5389 output_dev(fp, &in_progress_devtab);
5390 break;
5391 case RT_RCTL:
5392 output_rctl(fp, &in_progress_rctltab);
5393 break;
5394 case RT_ATTR:
5395 output_attr(fp, &in_progress_attrtab);
5545 break;
5546 case RT_MCAP:
5547 info_mcap(handle, fp);
5548 break;
5549 case RT_HOSTID:
5550 info_hostid(handle, fp);
5551 break;
5552 case RT_ADMIN:
5553 info_auth(handle, fp, cmd);
5554 break;
5555 case RT_FS_ALLOWED:
5556 info_fs_allowed(handle, fp);
5557 break;
5558 default:
5559 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5560 B_TRUE);
5561 }
5562
5563 cleanup:
5564 if (need_to_close)
5565 (void) pclose(fp);
5566 }
5567
5568 /*
5569 * Helper function for verify-- checks that a required string property
5570 * exists.
5571 */
5572 static void
5573 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5574 {
5575 if (strlen(attr) == 0) {
5576 zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5577 pt_to_str(pt));
5578 saw_error = B_TRUE;
5579 if (*ret_val == Z_OK)
5580 *ret_val = Z_REQD_PROPERTY_MISSING;
5581 }
5582 }
5583
5584 static int
5585 do_subproc(char *cmdbuf)
|
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2014 Gary Mills
26 */
27
28 /*
29 * zonecfg is a lex/yacc based command interpreter used to manage zone
30 * configurations. The lexer (see zonecfg_lex.l) builds up tokens, which
31 * the grammar (see zonecfg_grammar.y) builds up into commands, some of
32 * which takes resources and/or properties as arguments. See the block
33 * comments near the end of zonecfg_grammar.y for how the data structures
34 * which keep track of these resources and properties are built up.
35 *
36 * The resource/property data structures are inserted into a command
37 * structure (see zonecfg.h), which also keeps track of command names,
38 * miscellaneous arguments, and function handlers. The grammar selects
39 * the appropriate function handler, each of which takes a pointer to a
40 * command structure as its sole argument, and invokes it. The grammar
41 * itself is "entered" (a la the Matrix) by yyparse(), which is called
42 * from read_input(), our main driving function. That in turn is called
43 * by one of do_interactive(), cmd_file() or one_command_at_a_time(), each
44 * of which is called from main() depending on how the program was invoked.
45 *
892 "command. This operation is\n\tattempted "
893 "automatically upon completion of a %s "
894 "session."), "zoneadm", cmd_to_str(CMD_REVERT),
895 "zonecfg");
896 return (line);
897 case CMD_REVERT:
898 return (gettext("Reverts configuration back to the "
899 "last committed state. The -F flag\n\tcan be "
900 "used to force the action."));
901 case CMD_CANCEL:
902 return (gettext("Cancels resource/property "
903 "specification."));
904 case CMD_END:
905 return (gettext("Ends resource/property "
906 "specification."));
907 }
908 /* NOTREACHED */
909 return (NULL);
910 }
911
912 /* Copied almost verbatim from libtnfctl/prb_findexec.c */
913 static const char *
914 exec_cat(const char *s1, const char *s2, char *si)
915 {
916 char *s;
917 /* number of characters in s2 */
918 int cnt = PATH_MAX + 1;
919
920 s = si;
921 while (*s1 && *s1 != ':') {
922 if (cnt > 0) {
923 *s++ = *s1++;
924 cnt--;
925 } else
926 s1++;
927 }
928 if (si != s && cnt > 0) {
929 *s++ = '/';
930 cnt--;
931 }
932 while (*s2 && cnt > 0) {
933 *s++ = *s2++;
934 cnt--;
935 }
936 *s = '\0';
937 return (*s1 ? ++s1 : NULL);
938 }
939
940 /* Determine that a name exists in PATH */
941 /* Copied with changes from libtnfctl/prb_findexec.c */
942 static int
943 path_find(const char *name, char *ret_path)
944 {
945 const char *pathstr;
946 char fname[PATH_MAX + 2];
947 const char *cp;
948 struct stat stat_buf;
949
950 if (*name == '\0') {
951 return (-1);
952 }
953 if ((pathstr = getenv("PATH")) == NULL) {
954 if (geteuid() == 0 || getuid() == 0)
955 pathstr = "/usr/sbin:/usr/bin";
956 else
957 pathstr = "/usr/bin:";
958 }
959 cp = strchr(name, '/') ? (const char *) "" : pathstr;
960
961 do {
962 cp = exec_cat(cp, name, fname);
963 if (stat(fname, &stat_buf) != -1) {
964 /* successful find of the file */
965 if (ret_path != NULL)
966 (void) strncpy(ret_path, fname, PATH_MAX + 2);
967 return (0);
968 }
969 } while (cp != NULL);
970
971 return (-1);
972 }
973
974 static FILE *
975 pager_open(void) {
976 FILE *newfp;
977 char *pager, *space;
978
979 if ((pager = getenv("PAGER")) == NULL)
980 pager = PAGER;
981
982 space = strchr(pager, ' ');
983 if (space)
984 *space = '\0';
985 if (path_find(pager, NULL) == 0) {
986 if (space)
987 *space = ' ';
988 if ((newfp = popen(pager, "w")) == NULL)
989 zerr(gettext("PAGER open failed (%s)."),
990 strerror(errno));
991 return (newfp);
992 } else {
993 zerr(gettext("PAGER %s does not exist (%s)."),
994 pager, strerror(errno));
995 }
996 return (NULL);
997 }
998
999 static void
1000 pager_close(FILE *fp) {
1001 int status;
1002
1003 status = pclose(fp);
1004 if (status == -1)
1005 zerr(gettext("PAGER close failed (%s)."),
1006 strerror(errno));
1007 }
1008
1009 /*
1010 * Called with verbose TRUE when help is explicitly requested, FALSE for
1011 * unexpected errors.
1012 */
1013
1014 void
1015 usage(boolean_t verbose, uint_t flags)
1016 {
1017 FILE *fp = verbose ? stdout : stderr;
1018 FILE *newfp;
1019 boolean_t need_to_close = B_FALSE;
1020 int i;
1021
1022 /* don't page error output */
1023 if (verbose && interactive_mode) {
1024 if ((newfp = pager_open()) != NULL) {
1025 need_to_close = B_TRUE;
1026 fp = newfp;
1027 }
1028 }
1029
1030 if (flags & HELP_META) {
1031 (void) fprintf(fp, gettext("More help is available for the "
1032 "following:\n"));
1033 (void) fprintf(fp, "\n\tcommands ('%s commands')\n",
1034 cmd_to_str(CMD_HELP));
1035 (void) fprintf(fp, "\tsyntax ('%s syntax')\n",
1036 cmd_to_str(CMD_HELP));
1037 (void) fprintf(fp, "\tusage ('%s usage')\n\n",
1038 cmd_to_str(CMD_HELP));
1039 (void) fprintf(fp, gettext("You may also obtain help on any "
1040 "command by typing '%s <command-name>.'\n"),
1041 cmd_to_str(CMD_HELP));
1042 }
1043 if (flags & HELP_RES_SCOPE) {
1044 switch (resource_scope) {
1045 case RT_FS:
1046 (void) fprintf(fp, gettext("The '%s' resource scope is "
1047 "used to configure a file-system.\n"),
1048 rt_to_str(resource_scope));
1340 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
1341 pt_to_str(PT_MATCH));
1342 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
1343 pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
1344 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
1345 pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
1346 pt_to_str(PT_VALUE));
1347 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
1348 pt_to_str(PT_NAME));
1349 (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
1350 pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
1351 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
1352 pt_to_str(PT_NCPUS));
1353 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
1354 pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
1355 pt_to_str(PT_LOCKED));
1356 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
1357 pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
1358 }
1359 if (need_to_close)
1360 (void) pager_close(fp);
1361 }
1362
1363 static void
1364 zone_perror(char *prefix, int err, boolean_t set_saw)
1365 {
1366 zerr("%s: %s", prefix, zonecfg_strerror(err));
1367 if (set_saw)
1368 saw_error = B_TRUE;
1369 }
1370
1371 /*
1372 * zone_perror() expects a single string, but for remove and select
1373 * we have both the command and the resource type, so this wrapper
1374 * function serves the same purpose in a slightly different way.
1375 */
1376
1377 static void
1378 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
1379 {
1380 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
5409 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5410 continue; /* no match */
5411 output_auth(fp, &lookup);
5412 output = B_TRUE;
5413 }
5414 (void) zonecfg_endadminent(handle);
5415 /*
5416 * If a property n/v pair was specified, warn the user if there was
5417 * nothing to output.
5418 */
5419 if (!output && cmd->cmd_prop_nv_pairs > 0)
5420 (void) printf(gettext("No such %s resource.\n"),
5421 rt_to_str(RT_ADMIN));
5422 }
5423
5424 void
5425 info_func(cmd_t *cmd)
5426 {
5427 FILE *fp = stdout;
5428 boolean_t need_to_close = B_FALSE;
5429 int type;
5430 int res1, res2;
5431 uint64_t swap_limit;
5432 uint64_t locked_limit;
5433
5434 assert(cmd != NULL);
5435
5436 if (initialize(B_TRUE) != Z_OK)
5437 return;
5438
5439 /* don't page error output */
5440 if (interactive_mode) {
5441 if ((fp = pager_open()) != NULL)
5442 need_to_close = B_TRUE;
5443 else
5444 fp = stdout;
5445
5446 setbuf(fp, NULL);
5447 }
5448
5449 if (!global_scope) {
5450 switch (resource_scope) {
5451 case RT_FS:
5452 output_fs(fp, &in_progress_fstab);
5453 break;
5454 case RT_NET:
5455 output_net(fp, &in_progress_nwiftab);
5456 break;
5457 case RT_DEVICE:
5458 output_dev(fp, &in_progress_devtab);
5459 break;
5460 case RT_RCTL:
5461 output_rctl(fp, &in_progress_rctltab);
5462 break;
5463 case RT_ATTR:
5464 output_attr(fp, &in_progress_attrtab);
5614 break;
5615 case RT_MCAP:
5616 info_mcap(handle, fp);
5617 break;
5618 case RT_HOSTID:
5619 info_hostid(handle, fp);
5620 break;
5621 case RT_ADMIN:
5622 info_auth(handle, fp, cmd);
5623 break;
5624 case RT_FS_ALLOWED:
5625 info_fs_allowed(handle, fp);
5626 break;
5627 default:
5628 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5629 B_TRUE);
5630 }
5631
5632 cleanup:
5633 if (need_to_close)
5634 (void) pager_close(fp);
5635 }
5636
5637 /*
5638 * Helper function for verify-- checks that a required string property
5639 * exists.
5640 */
5641 static void
5642 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5643 {
5644 if (strlen(attr) == 0) {
5645 zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5646 pt_to_str(pt));
5647 saw_error = B_TRUE;
5648 if (*ret_val == Z_OK)
5649 *ret_val = Z_REQD_PROPERTY_MISSING;
5650 }
5651 }
5652
5653 static int
5654 do_subproc(char *cmdbuf)
|