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 *
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 *
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 /*
913 * Return the input filename appended to each component of the path
914 * or the filename itself if it is absolute.
915 * Parameters: path string, file name, output string.
916 */
917 /* Copied almost verbatim from libtnfctl/prb_findexec.c */
918 static const char *
919 exec_cat(const char *s1, const char *s2, char *si)
920 {
921 char *s;
922 /* Number of remaining characters in s */
923 int cnt = PATH_MAX + 1;
924
925 s = si;
926 while (*s1 && *s1 != ':') { /* Copy first component of path to si */
927 if (cnt > 0) {
928 *s++ = *s1++;
929 cnt--;
930 } else {
931 s1++;
932 }
933 }
934 if (si != s && cnt > 0) { /* Add slash if s2 is not absolute */
935 *s++ = '/';
936 cnt--;
937 }
938 while (*s2 && cnt > 0) { /* Copy s2 to si */
939 *s++ = *s2++;
940 cnt--;
941 }
942 *s = '\0'; /* Terminate the output string */
943 return (*s1 ? ++s1 : NULL); /* Return next path component or NULL */
944 }
945
946 /* Determine that a name exists in PATH */
947 /* Copied with changes from libtnfctl/prb_findexec.c */
948 static int
949 path_find(const char *name)
950 {
951 const char *pathstr;
952 char fname[PATH_MAX + 2];
953 const char *cp;
954 struct stat stat_buf;
955
956 if ((pathstr = getenv("PATH")) == NULL) {
957 if (geteuid() == 0 || getuid() == 0)
958 pathstr = "/usr/sbin:/usr/bin";
959 else
960 pathstr = "/usr/bin:";
961 }
962 cp = strchr(name, '/') ? (const char *) "" : pathstr;
963
964 do {
965 cp = exec_cat(cp, name, fname);
966 if (stat(fname, &stat_buf) != -1) {
967 /* successful find of the file */
968 return (0);
969 }
970 } while (cp != NULL);
971
972 return (-1);
973 }
974
975 static FILE *
976 pager_open(void) {
977 FILE *newfp;
978 char *pager, *space;
979
980 pager = getenv("PAGER");
981 if (pager == NULL || *pager == '\0')
982 pager = PAGER;
983
984 space = strchr(pager, ' ');
985 if (space)
986 *space = '\0';
987 if (path_find(pager) == 0) {
988 if (space)
989 *space = ' ';
990 if ((newfp = popen(pager, "w")) == NULL)
991 zerr(gettext("PAGER open failed (%s)."),
992 strerror(errno));
993 return (newfp);
994 } else {
995 zerr(gettext("PAGER %s does not exist (%s)."),
996 pager, strerror(errno));
997 }
998 return (NULL);
999 }
1000
1001 static void
1002 pager_close(FILE *fp) {
1003 int status;
1004
1005 status = pclose(fp);
1006 if (status == -1)
1007 zerr(gettext("PAGER close failed (%s)."),
1008 strerror(errno));
1009 }
1010
1011 /*
1012 * Called with verbose TRUE when help is explicitly requested, FALSE for
1013 * unexpected errors.
1014 */
1015
1016 void
1017 usage(boolean_t verbose, uint_t flags)
1018 {
1019 FILE *fp = verbose ? stdout : stderr;
1020 FILE *newfp;
1021 boolean_t need_to_close = B_FALSE;
1022 int i;
1023
1024 /* don't page error output */
1025 if (verbose && interactive_mode) {
1026 if ((newfp = pager_open()) != NULL) {
1027 need_to_close = B_TRUE;
1028 fp = newfp;
1029 }
1030 }
1031
1032 if (flags & HELP_META) {
1033 (void) fprintf(fp, gettext("More help is available for the "
1034 "following:\n"));
1035 (void) fprintf(fp, "\n\tcommands ('%s commands')\n",
1036 cmd_to_str(CMD_HELP));
1037 (void) fprintf(fp, "\tsyntax ('%s syntax')\n",
1038 cmd_to_str(CMD_HELP));
1039 (void) fprintf(fp, "\tusage ('%s usage')\n\n",
1040 cmd_to_str(CMD_HELP));
1041 (void) fprintf(fp, gettext("You may also obtain help on any "
1042 "command by typing '%s <command-name>.'\n"),
1043 cmd_to_str(CMD_HELP));
1044 }
1045 if (flags & HELP_RES_SCOPE) {
1046 switch (resource_scope) {
1047 case RT_FS:
1048 (void) fprintf(fp, gettext("The '%s' resource scope is "
1049 "used to configure a file-system.\n"),
1050 rt_to_str(resource_scope));
1342 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
1343 pt_to_str(PT_MATCH));
1344 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
1345 pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
1346 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
1347 pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
1348 pt_to_str(PT_VALUE));
1349 (void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DATASET),
1350 pt_to_str(PT_NAME));
1351 (void) fprintf(fp, "\t%s\t%s, %s\n", rt_to_str(RT_DCPU),
1352 pt_to_str(PT_NCPUS), pt_to_str(PT_IMPORTANCE));
1353 (void) fprintf(fp, "\t%s\t%s\n", rt_to_str(RT_PCAP),
1354 pt_to_str(PT_NCPUS));
1355 (void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
1356 pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
1357 pt_to_str(PT_LOCKED));
1358 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
1359 pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
1360 }
1361 if (need_to_close)
1362 (void) pager_close(fp);
1363 }
1364
1365 static void
1366 zone_perror(char *prefix, int err, boolean_t set_saw)
1367 {
1368 zerr("%s: %s", prefix, zonecfg_strerror(err));
1369 if (set_saw)
1370 saw_error = B_TRUE;
1371 }
1372
1373 /*
1374 * zone_perror() expects a single string, but for remove and select
1375 * we have both the command and the resource type, so this wrapper
1376 * function serves the same purpose in a slightly different way.
1377 */
1378
1379 static void
1380 z_cmd_rt_perror(int cmd_num, int res_num, int err, boolean_t set_saw)
1381 {
1382 zerr("%s %s: %s", cmd_to_str(cmd_num), rt_to_str(res_num),
5411 strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5412 continue; /* no match */
5413 output_auth(fp, &lookup);
5414 output = B_TRUE;
5415 }
5416 (void) zonecfg_endadminent(handle);
5417 /*
5418 * If a property n/v pair was specified, warn the user if there was
5419 * nothing to output.
5420 */
5421 if (!output && cmd->cmd_prop_nv_pairs > 0)
5422 (void) printf(gettext("No such %s resource.\n"),
5423 rt_to_str(RT_ADMIN));
5424 }
5425
5426 void
5427 info_func(cmd_t *cmd)
5428 {
5429 FILE *fp = stdout;
5430 boolean_t need_to_close = B_FALSE;
5431 int type;
5432 int res1, res2;
5433 uint64_t swap_limit;
5434 uint64_t locked_limit;
5435
5436 assert(cmd != NULL);
5437
5438 if (initialize(B_TRUE) != Z_OK)
5439 return;
5440
5441 /* don't page error output */
5442 if (interactive_mode) {
5443 if ((fp = pager_open()) != NULL)
5444 need_to_close = B_TRUE;
5445 else
5446 fp = stdout;
5447
5448 setbuf(fp, NULL);
5449 }
5450
5451 if (!global_scope) {
5452 switch (resource_scope) {
5453 case RT_FS:
5454 output_fs(fp, &in_progress_fstab);
5455 break;
5456 case RT_NET:
5457 output_net(fp, &in_progress_nwiftab);
5458 break;
5459 case RT_DEVICE:
5460 output_dev(fp, &in_progress_devtab);
5461 break;
5462 case RT_RCTL:
5463 output_rctl(fp, &in_progress_rctltab);
5464 break;
5465 case RT_ATTR:
5466 output_attr(fp, &in_progress_attrtab);
5616 break;
5617 case RT_MCAP:
5618 info_mcap(handle, fp);
5619 break;
5620 case RT_HOSTID:
5621 info_hostid(handle, fp);
5622 break;
5623 case RT_ADMIN:
5624 info_auth(handle, fp, cmd);
5625 break;
5626 case RT_FS_ALLOWED:
5627 info_fs_allowed(handle, fp);
5628 break;
5629 default:
5630 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5631 B_TRUE);
5632 }
5633
5634 cleanup:
5635 if (need_to_close)
5636 (void) pager_close(fp);
5637 }
5638
5639 /*
5640 * Helper function for verify-- checks that a required string property
5641 * exists.
5642 */
5643 static void
5644 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5645 {
5646 if (strlen(attr) == 0) {
5647 zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5648 pt_to_str(pt));
5649 saw_error = B_TRUE;
5650 if (*ret_val == Z_OK)
5651 *ret_val = Z_REQD_PROPERTY_MISSING;
5652 }
5653 }
5654
5655 static int
5656 do_subproc(char *cmdbuf)
|