Changeset 37952 in vbox
- Timestamp:
- Jul 14, 2011 10:14:52 AM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 72865
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp
r37921 r37952 73 73 * Structures and Typedefs * 74 74 *******************************************************************************/ 75 /** Pointer to a handler function. */ 76 typedef RTEXITCODE (*PFNHANDLER)(int , char **); 77 75 78 /** 76 79 * An file/directory entry. Used to cache … … 126 129 127 130 /** 128 * Displays an error message because of syntax error.129 *130 * @return VERR_INVALID_PARAMETER131 * @param pszFormat132 */133 static int VBoxServiceToolboxErrorSyntax(const char *pszFormat, ...)134 {135 va_list args;136 137 va_start(args, pszFormat);138 RTPrintf("\n"139 "Syntax error: %N\n", pszFormat, &args);140 va_end(args);141 return VERR_INVALID_PARAMETER;142 }143 144 /**145 131 * Prints a parseable stream header which contains the actual tool 146 132 * which was called/used along with its stream version. … … 234 220 rc = RTFileFromNative(&hInput, RTFILE_NATIVE_STDIN); 235 221 if (RT_FAILURE(rc)) 236 RTMsgError(" cat:Could not translate input file to native handle, rc=%Rrc\n", rc);222 RTMsgError("Could not translate input file to native handle, rc=%Rrc\n", rc); 237 223 } 238 224 … … 241 227 rc = RTFileFromNative(&hOutput, RTFILE_NATIVE_STDOUT); 242 228 if (RT_FAILURE(rc)) 243 RTMsgError(" cat:Could not translate output file to native handle, rc=%Rrc\n", rc);229 RTMsgError("Could not translate output file to native handle, rc=%Rrc\n", rc); 244 230 } 245 231 … … 261 247 rc = VINF_SUCCESS; 262 248 else if (RT_FAILURE(rc)) 263 RTMsgError(" cat:Error while reading input, rc=%Rrc\n", rc);249 RTMsgError("Error while reading input, rc=%Rrc\n", rc); 264 250 break; 265 251 } … … 333 319 case 'T': 334 320 case 'v': 335 RTMsgError(" cat:Sorry, option '%s' is not implemented yet!\n",321 RTMsgError("Sorry, option '%s' is not implemented yet!\n", 336 322 ValueUnion.pDef->pszLong); 337 323 rc = VERR_INVALID_PARAMETER; … … 382 368 rc = RTFileOpen(&hOutput, szOutput, fFlags); 383 369 if (RT_FAILURE(rc)) 384 RTMsgError(" cat:Could not create output file '%s', rc=%Rrc\n",370 RTMsgError("Could not create output file '%s', rc=%Rrc\n", 385 371 szOutput, rc); 386 372 } … … 404 390 PCRTSTATUSMSG pMsg = RTErrGet(rc); 405 391 if (pMsg) 406 RTMsgError(" cat:Could not open input file '%s': %s\n",392 RTMsgError("Could not open input file '%s': %s\n", 407 393 pNodeIt->pszName, pMsg->pszMsgFull); 408 394 else 409 RTMsgError(" cat:Could not open input file '%s', rc=%Rrc\n", pNodeIt->pszName, rc);395 RTMsgError("Could not open input file '%s', rc=%Rrc\n", pNodeIt->pszName, rc); 410 396 } 411 397 … … 607 593 if (RT_FAILURE(rc)) 608 594 { 609 RTMsgError(" ls:Failed to retrieve absolute path of '%s', rc=%Rrc\n", pszDir, rc);595 RTMsgError("Failed to retrieve absolute path of '%s', rc=%Rrc\n", pszDir, rc); 610 596 return rc; 611 597 } … … 615 601 if (RT_FAILURE(rc)) 616 602 { 617 RTMsgError(" ls:Failed to open directory '%s', rc=%Rrc\n", szPathAbs, rc);603 RTMsgError("Failed to open directory '%s', rc=%Rrc\n", szPathAbs, rc); 618 604 return rc; 619 605 } … … 649 635 if (RT_FAILURE(rc2)) 650 636 { 651 RTMsgError(" ls:Failed to close dir '%s', rc=%Rrc\n",637 RTMsgError("Failed to close dir '%s', rc=%Rrc\n", 652 638 pszDir, rc2); 653 639 if (RT_SUCCESS(rc)) … … 741 727 RTGETOPTUNION ValueUnion; 742 728 RTGETOPTSTATE GetState; 743 RTGetOptInit(&GetState, argc, argv,744 s_aOptions, RT_ELEMENTS(s_aOptions),745 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);746 747 int rc = VINF_SUCCESS; 748 bool fVerbose= false;749 uint32_t fFlags = VBOXSERVICETOOLBOXLSFLAG_NONE;729 int rc = RTGetOptInit(&GetState, argc, argv, 730 s_aOptions, RT_ELEMENTS(s_aOptions), 731 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST); 732 AssertRCReturn(rc, RTEXITCODE_INIT); 733 734 bool fVerbose = false; 735 uint32_t fFlags = VBOXSERVICETOOLBOXLSFLAG_NONE; 750 736 uint32_t fOutputFlags = VBOXSERVICETOOLBOXOUTPUTFLAG_NONE; 751 737 … … 780 766 break; 781 767 782 case 'v': 768 case 'v': /** @todo r=bird: "man ls" -> "-v natural sort of (version) numbers within text" */ 783 769 fVerbose = true; 784 770 break; … … 817 803 rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, szDirCur); 818 804 if (RT_FAILURE(rc)) 819 RTMsgError(" ls:Adding current directory failed, rc=%Rrc\n", rc);805 RTMsgError("Adding current directory failed, rc=%Rrc\n", rc); 820 806 } 821 807 else 822 RTMsgError(" ls:Getting current directory failed, rc=%Rrc\n", rc);808 RTMsgError("Getting current directory failed, rc=%Rrc\n", rc); 823 809 } 824 810 … … 857 843 } 858 844 else 859 RTMsgError(" ls:Unable to query information for '%s', rc=%Rrc\n",845 RTMsgError("Unable to query information for '%s', rc=%Rrc\n", 860 846 pNodeIt->pszName, rc); 861 847 RTFileClose(file); 862 848 } 863 849 else 864 RTMsgError(" ls:Failed opening '%s', rc=%Rrc\n",850 RTMsgError("Failed opening '%s', rc=%Rrc\n", 865 851 pNodeIt->pszName, rc); 866 852 } … … 869 855 fFlags, fOutputFlags); 870 856 if (RT_FAILURE(rc)) 871 RTMsgError(" ls:Failed while enumerating '%s', rc=%Rrc\n",857 RTMsgError("Failed while enumerating '%s', rc=%Rrc\n", 872 858 pNodeIt->pszName, rc); 873 859 } … … 877 863 } 878 864 else if (fVerbose) 879 RTMsgError(" ls:Failed with rc=%Rrc\n", rc);865 RTMsgError("Failed with rc=%Rrc\n", rc); 880 866 881 867 VBoxServiceToolboxPathBufDestroy(&fileList); … … 898 884 { "--parents", 'p', RTGETOPT_REQ_NOTHING}, 899 885 { "--verbose", 'v', RTGETOPT_REQ_NOTHING} 886 }; 887 888 int ch; 889 RTGETOPTUNION ValueUnion; 890 RTGETOPTSTATE GetState; 891 int rc = RTGetOptInit(&GetState, argc, argv, 892 s_aOptions, RT_ELEMENTS(s_aOptions), 893 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST); 894 AssertRCReturn(rc, RTEXITCODE_INIT); 895 896 bool fMakeParentDirs = false; 897 bool fVerbose = false; 898 RTFMODE fDirMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO; 899 int cDirsCreated = 0; 900 901 while ((ch = RTGetOpt(&GetState, &ValueUnion))) 902 { 903 /* For options that require an argument, ValueUnion has received the value. */ 904 switch (ch) 905 { 906 case 'p': 907 fMakeParentDirs = true; 908 #ifndef RT_OS_WINDOWS 909 umask(0); /* RTDirCreate workaround */ 910 #endif 911 break; 912 913 case 'm': 914 rc = RTStrToUInt32Ex(ValueUnion.psz, NULL, 8 /* Base */, &fDirMode); 915 if (RT_FAILURE(rc)) /* Only octet based values supported right now! */ 916 return RTMsgErrorExit(RTEXITCODE_SYNTAX, 917 "Mode flag strings not implemented yet! Use octal numbers instead. (%s)\n", 918 ValueUnion.psz); 919 #ifndef RT_OS_WINDOWS 920 umask(0); /* RTDirCreate workaround */ 921 #endif 922 break; 923 924 case 'v': 925 fVerbose = true; 926 break; 927 928 case 'h': 929 RTPrintf("Usage: %s [options] dir1 [dir2...]\n" 930 "\n" 931 "Options:\n" 932 " -m,--mode=<mode> The file mode to set (chmod) on the created\n" 933 " directories. Default: a=rwx & umask.\n" 934 " -p,--parents Create parent directories as needed, no\n" 935 " error if the directory already exists.\n" 936 " -v,--verbose Display a message for each created directory.\n" 937 " -V,--version Display the version and exit\n" 938 " -h,--help Display this help text and exit.\n" 939 , argv[0]); 940 return RTEXITCODE_SUCCESS; 941 942 case 'V': 943 VBoxServiceToolboxShowVersion(); 944 return RTEXITCODE_SUCCESS; 945 946 case VINF_GETOPT_NOT_OPTION: 947 if (fMakeParentDirs) 948 /** @todo r=bird: If fVerbose is set, we should also show 949 * which directories that get created, parents as well as 950 * omitting existing final dirs. Annoying, but check any 951 * mkdir implementation (try "mkdir -pv asdf/1/2/3/4" 952 * twice). */ 953 rc = RTDirCreateFullPath(ValueUnion.psz, fDirMode); 954 else 955 rc = RTDirCreate(ValueUnion.psz, fDirMode); 956 if (RT_FAILURE(rc)) 957 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Could not create directory '%s': %Rra\n", 958 ValueUnion.psz, rc); 959 if (fVerbose) 960 RTMsgInfo("Created directory 's', mode %#RTfmode\n", ValueUnion.psz, fDirMode); 961 cDirsCreated++; 962 break; 963 964 default: 965 return RTGetOptPrintError(ch, &ValueUnion); 966 } 967 } 968 AssertRC(rc); 969 970 if (cDirsCreated == 0) 971 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No directory argument."); 972 973 return RTEXITCODE_SUCCESS; 974 } 975 976 977 /** 978 * Main function for tool "vbox_stat". 979 * 980 * @return RTEXITCODE. 981 * @param argc Number of arguments. 982 * @param argv Pointer to argument array. 983 */ 984 static RTEXITCODE VBoxServiceToolboxStat(int argc, char **argv) 985 { 986 static const RTGETOPTDEF s_aOptions[] = 987 { 988 { "--file-system", 'f', RTGETOPT_REQ_NOTHING }, 989 { "--dereference", 'L', RTGETOPT_REQ_NOTHING }, 990 { "--machinereadable", STAT_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING }, 991 { "--terse", 't', RTGETOPT_REQ_NOTHING }, 992 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 900 993 }; 901 994 … … 908 1001 909 1002 int rc = VINF_SUCCESS; 910 bool fMakeParentDirs = false;911 1003 bool fVerbose = false; 912 913 RTFMODE newMode = 0; 914 RTFMODE dirMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO; 915 916 /* Init directory list. */ 917 RTLISTNODE dirList; 918 RTListInit(&dirList); 1004 uint32_t fOutputFlags = VBOXSERVICETOOLBOXOUTPUTFLAG_LONG; /* Use long mode by default. */ 1005 1006 /* Init file list. */ 1007 RTLISTNODE fileList; 1008 RTListInit(&fileList); 919 1009 920 1010 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) … … 924 1014 switch (ch) 925 1015 { 1016 case 'f': 1017 case 'L': 1018 RTMsgError("Sorry, option '%s' is not implemented yet!\n", ValueUnion.pDef->pszLong); 1019 rc = VERR_INVALID_PARAMETER; 1020 break; 1021 1022 case LS_OPT_MACHINE_READABLE: 1023 fOutputFlags |= VBOXSERVICETOOLBOXOUTPUTFLAG_PARSEABLE; 1024 break; 1025 1026 case 'v': /** @todo r=bird: There is no verbose option for stat. */ 1027 fVerbose = true; 1028 break; 1029 926 1030 case 'h': 927 1031 VBoxServiceToolboxShowUsage(); 928 1032 return RTEXITCODE_SUCCESS; 929 930 case 'p':931 fMakeParentDirs = true;932 break;933 934 case 'm':935 rc = RTStrToUInt32Ex(ValueUnion.psz, NULL, 8 /* Base */, &newMode);936 if (RT_FAILURE(rc)) /* Only octet based values supported right now! */937 {938 RTMsgError("mkdir: Mode flag strings not implemented yet! Use octal numbers instead.\n");939 return RTEXITCODE_SYNTAX;940 }941 break;942 943 case 'v':944 fVerbose = true;945 break;946 947 case 'V':948 VBoxServiceToolboxShowVersion();949 return RTEXITCODE_SUCCESS;950 951 case VINF_GETOPT_NOT_OPTION:952 /* Add path(s) to buffer. This enables processing multiple paths953 * at once.954 *955 * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when956 * processing this loop it's safe to immediately exit on syntax errors957 * or showing the help text (see above). */958 rc = VBoxServiceToolboxPathBufAddPathEntry(&dirList, ValueUnion.psz);959 break;960 961 962 default:963 return RTGetOptPrintError(ch, &ValueUnion);964 }965 }966 967 if (RT_SUCCESS(rc))968 {969 if (fMakeParentDirs || newMode)970 {971 #ifndef RT_OS_WINDOWS972 mode_t umaskMode = umask(0); /* Get current umask. */973 if (newMode)974 dirMode = newMode;975 #endif976 }977 978 PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;979 RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)980 {981 rc = fMakeParentDirs982 ? RTDirCreateFullPath(pNodeIt->pszName, dirMode)983 : RTDirCreate(pNodeIt->pszName, dirMode);984 985 if (RT_SUCCESS(rc) && fVerbose)986 RTMsgError("mkdir: Created directory 's', mode %#RTfmode\n", pNodeIt->pszName, dirMode);987 else if (RT_FAILURE(rc)) /** @todo Add a switch with more helpful error texts! */988 {989 RTMsgError("mkdir: Could not create directory '%s': %Rra\n", pNodeIt->pszName, rc);990 break;991 }992 }993 }994 else if (fVerbose)995 RTMsgError("mkdir: Failed with rc=%Rrc\n", rc);996 997 VBoxServiceToolboxPathBufDestroy(&dirList);998 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;999 }1000 1001 1002 /**1003 * Main function for tool "vbox_stat".1004 *1005 * @return RTEXITCODE.1006 * @param argc Number of arguments.1007 * @param argv Pointer to argument array.1008 */1009 static RTEXITCODE VBoxServiceToolboxStat(int argc, char **argv)1010 {1011 static const RTGETOPTDEF s_aOptions[] =1012 {1013 { "--file-system", 'f', RTGETOPT_REQ_NOTHING },1014 { "--dereference", 'L', RTGETOPT_REQ_NOTHING },1015 { "--machinereadable", STAT_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING },1016 { "--terse", 't', RTGETOPT_REQ_NOTHING },1017 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }1018 };1019 1020 int ch;1021 RTGETOPTUNION ValueUnion;1022 RTGETOPTSTATE GetState;1023 RTGetOptInit(&GetState, argc, argv,1024 s_aOptions, RT_ELEMENTS(s_aOptions),1025 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);1026 1027 int rc = VINF_SUCCESS;1028 bool fVerbose = false;1029 uint32_t fOutputFlags = VBOXSERVICETOOLBOXOUTPUTFLAG_LONG; /* Use long mode by default. */1030 1031 /* Init file list. */1032 RTLISTNODE fileList;1033 RTListInit(&fileList);1034 1035 while ( (ch = RTGetOpt(&GetState, &ValueUnion))1036 && RT_SUCCESS(rc))1037 {1038 /* For options that require an argument, ValueUnion has received the value. */1039 switch (ch)1040 {1041 case 'h':1042 VBoxServiceToolboxShowUsage();1043 return RTEXITCODE_SUCCESS;1044 1045 case 'f':1046 case 'L':1047 RTMsgError("stat: Sorry, option '%s' is not implemented yet!\n",1048 ValueUnion.pDef->pszLong);1049 rc = VERR_INVALID_PARAMETER;1050 break;1051 1052 case LS_OPT_MACHINE_READABLE:1053 fOutputFlags |= VBOXSERVICETOOLBOXOUTPUTFLAG_PARSEABLE;1054 break;1055 1056 case 'v':1057 fVerbose = true;1058 break;1059 1033 1060 1034 case 'V': … … 1103 1077 rc2 = RTFileQueryInfo(file, &objInfo, RTFSOBJATTRADD_UNIX); 1104 1078 if (RT_FAILURE(rc2)) 1105 RTMsgError(" stat:Unable to query information for '%s', rc=%Rrc\n",1079 RTMsgError("Unable to query information for '%s', rc=%Rrc\n", 1106 1080 pNodeIt->pszName, rc2); 1107 1081 RTFileClose(file); 1108 1082 } 1109 1083 else 1110 RTMsgError(" stat:Failed opening '%s', rc=%Rrc\n",1084 RTMsgError("Failed opening '%s', rc=%Rrc\n", 1111 1085 pNodeIt->pszName, rc2); 1112 1086 … … 1126 1100 else 1127 1101 { 1128 RTMsgError(" stat:Cannot stat for '%s': No such file or directory\n",1102 RTMsgError("Cannot stat for '%s': No such file or directory\n", 1129 1103 pNodeIt->pszName); 1130 1104 rc = VERR_FILE_NOT_FOUND; … … 1150 1124 1151 1125 if (RTListIsEmpty(&fileList)) 1152 RTMsgError(" stat:Missing operand\n");1126 RTMsgError("Missing operand\n"); 1153 1127 } 1154 1128 else if (fVerbose) 1155 RTMsgError(" stat:Failed with rc=%Rrc\n", rc);1129 RTMsgError("Failed with rc=%Rrc\n", rc); 1156 1130 1157 1131 VBoxServiceToolboxPathBufDestroy(&fileList); … … 1160 1134 1161 1135 1162 /** 1163 * Entry point for internal toolbox. 1164 * 1165 * @return True if an internal tool was handled, false if not. 1166 * @param argc Number of arguments. 1167 * @param argv Pointer to argument array. 1168 * @param prcExit Where to store the exit code when an 1169 * internal toolbox command was handled. 1170 */ 1171 bool VBoxServiceToolboxMain(int argc, char **argv, RTEXITCODE *prcExit) 1136 1137 /** 1138 * Looks up the handler for the tool give by @a pszTool. 1139 * 1140 * @returns Pointer to handler function. NULL if not found. 1141 * @param pszTool The name of the tool. 1142 */ 1143 static PFNHANDLER vboxServiceToolboxLookUpHandler(const char *pszTool) 1172 1144 { 1173 1145 static struct … … 1184 1156 }; 1185 1157 1186 /*1187 * Check if the file named in argv[0] is one of the toolbox programs.1188 */1189 AssertReturn(argc > 0, false);1190 const char *pszTool = RTPathFilename(argv[0]);1191 1158 /* Skip optional 'vbox_' prefix. */ 1192 1159 if ( pszTool[0] == 'v' … … 1197 1164 pszTool += 5; 1198 1165 1166 /* Do a linear search, since we don't have that much stuff in the table. */ 1199 1167 for (unsigned i = 0; i < RT_ELEMENTS(s_aTools); i++) 1200 1168 if (!strcmp(s_aTools[i].pszName, pszTool)) 1201 { 1202 *prcExit = s_aTools[i].pfnHandler(argc, argv); 1203 return true; 1204 } 1169 return s_aTools[i].pfnHandler; 1170 1171 return NULL; 1172 } 1173 1174 1175 /** 1176 * Entry point for internal toolbox. 1177 * 1178 * @return True if an internal tool was handled, false if not. 1179 * @param argc Number of arguments. 1180 * @param argv Pointer to argument array. 1181 * @param prcExit Where to store the exit code when an 1182 * internal toolbox command was handled. 1183 */ 1184 bool VBoxServiceToolboxMain(int argc, char **argv, RTEXITCODE *prcExit) 1185 { 1205 1186 1206 1187 /* 1207 * For debugging and testing purposes we also allow toolbox program access 1208 * when the first VBoxService argument is --use-toolbox. 1188 * Check if the file named in argv[0] is one of the toolbox programs. 1209 1189 */ 1210 if (argc >= 3 && !strcmp(argv[1], "--use-toolbox")) 1211 { 1212 pszTool = argv[2]; 1213 for (unsigned i = 0; i < RT_ELEMENTS(s_aTools); i++) 1214 if (!strcmp(s_aTools[i].pszName, pszTool)) 1215 { 1216 *prcExit = s_aTools[i].pfnHandler(argc - 2, argv + 2); 1217 return true; 1218 } 1219 1220 *prcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "Toolbox program '%s' does not exist", pszTool); 1221 return true; 1222 } 1223 1224 return false; 1225 } 1226 1190 AssertReturn(argc > 0, false); 1191 const char *pszTool = RTPathFilename(argv[0]); 1192 PFNHANDLER pfnHandler = vboxServiceToolboxLookUpHandler(pszTool); 1193 if (!pfnHandler) 1194 { 1195 /* 1196 * For debugging and testing purposes we also allow toolbox program access 1197 * when the first VBoxService argument is --use-toolbox. 1198 */ 1199 if (argc < 3 || strcmp(argv[1], "--use-toolbox")) 1200 return false; 1201 argc -= 2; 1202 argv += 2; 1203 pszTool = argv[0]; 1204 pfnHandler = vboxServiceToolboxLookUpHandler(pszTool); 1205 if (!pfnHandler) 1206 { 1207 *prcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "Toolbox program '%s' does not exist", pszTool); 1208 return true; 1209 } 1210 } 1211 1212 /* 1213 * Invoke the handler. 1214 */ 1215 RTMsgSetProgName("VBoxService/%s", pszTool); 1216 *prcExit = pfnHandler(argc, argv); 1217 return true; 1218 1219 } 1220
Note:
See TracChangeset
for help on using the changeset viewer.