Print this page
4956 zonecfg won't use a valid pager


   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)