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  *


 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)