1 /*
2  * Shows information obtained from a VMware Virtual Disk (VMDK) file
3  *
4  * Copyright (C) 2009-2021, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <file_stream.h>
24 #include <memory.h>
25 #include <system_string.h>
26 #include <types.h>
27 
28 #include <stdio.h>
29 
30 #if defined( HAVE_IO_H ) || defined( WINAPI )
31 #include <io.h>
32 #endif
33 
34 #if defined( HAVE_STDLIB_H ) || defined( WINAPI )
35 #include <stdlib.h>
36 #endif
37 
38 #if defined( HAVE_UNISTD_H )
39 #include <unistd.h>
40 #endif
41 
42 #include "info_handle.h"
43 #include "vmdktools_getopt.h"
44 #include "vmdktools_libcerror.h"
45 #include "vmdktools_libclocale.h"
46 #include "vmdktools_libcnotify.h"
47 #include "vmdktools_libvmdk.h"
48 #include "vmdktools_output.h"
49 #include "vmdktools_signal.h"
50 #include "vmdktools_unused.h"
51 
52 info_handle_t *vmdkinfo_info_handle = NULL;
53 int vmdkinfo_abort                  = 0;
54 
55 /* Prints the executable usage information
56  */
usage_fprint(FILE * stream)57 void usage_fprint(
58       FILE *stream )
59 {
60 	if( stream == NULL )
61 	{
62 		return;
63 	}
64 	fprintf( stream, "Use vmdkinfo to determine information about a VMware Virtual Disk (VMDK)\n"
65 	                 "image file.\n\n" );
66 
67 	fprintf( stream, "Usage: vmdkinfo [ -hvV ] source\n\n" );
68 
69 	fprintf( stream, "\tsource: the source file(s)\n\n" );
70 
71 	fprintf( stream, "\t-h:     shows this help\n" );
72 	fprintf( stream, "\t-v:     verbose output to stderr\n" );
73 	fprintf( stream, "\t-V:     print version\n" );
74 }
75 
76 /* Signal handler for vmdkinfo
77  */
vmdkinfo_signal_handler(vmdktools_signal_t signal VMDKTOOLS_ATTRIBUTE_UNUSED)78 void vmdkinfo_signal_handler(
79       vmdktools_signal_t signal VMDKTOOLS_ATTRIBUTE_UNUSED )
80 {
81 	libcerror_error_t *error = NULL;
82 	static char *function   = "vmdkinfo_signal_handler";
83 
84 	VMDKTOOLS_UNREFERENCED_PARAMETER( signal )
85 
86 	vmdkinfo_abort = 1;
87 
88 	if( vmdkinfo_info_handle != NULL )
89 	{
90 		if( info_handle_signal_abort(
91 		     vmdkinfo_info_handle,
92 		     &error ) != 1 )
93 		{
94 			libcnotify_printf(
95 			 "%s: unable to signal info handle to abort.\n",
96 			 function );
97 
98 			libcnotify_print_error_backtrace(
99 			 error );
100 			libcerror_error_free(
101 			 &error );
102 		}
103 	}
104 	/* Force stdin to close otherwise any function reading it will remain blocked
105 	 */
106 #if defined( WINAPI ) && !defined( __CYGWIN__ )
107 	if( _close(
108 	     0 ) != 0 )
109 #else
110 	if( close(
111 	     0 ) != 0 )
112 #endif
113 	{
114 		libcnotify_printf(
115 		 "%s: unable to close stdin.\n",
116 		 function );
117 	}
118 }
119 
120 /* The main program
121  */
122 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
wmain(int argc,wchar_t * const argv[])123 int wmain( int argc, wchar_t * const argv[] )
124 #else
125 int main( int argc, char * const argv[] )
126 #endif
127 {
128 	system_character_t * const *source_filenames = NULL;
129 	libvmdk_error_t *error                       = NULL;
130 	char *program                                = "vmdkinfo";
131 	system_integer_t option                      = 0;
132 	int number_of_source_filenames               = 0;
133 	int verbose                                  = 0;
134 
135 	libcnotify_stream_set(
136 	 stderr,
137 	 NULL );
138 	libcnotify_verbose_set(
139 	 1 );
140 
141 	if( libclocale_initialize(
142              "vmdktools",
143 	     &error ) != 1 )
144 	{
145 		fprintf(
146 		 stderr,
147 		 "Unable to initialize locale values.\n" );
148 
149 		goto on_error;
150 	}
151         if( vmdktools_output_initialize(
152              _IONBF,
153              &error ) != 1 )
154 	{
155 		fprintf(
156 		 stderr,
157 		 "Unable to initialize output settings.\n" );
158 
159 		goto on_error;
160 	}
161 	vmdktools_output_version_fprint(
162 	 stdout,
163 	 program );
164 
165 	while( ( option = vmdktools_getopt(
166 	                   argc,
167 	                   argv,
168 	                   _SYSTEM_STRING( "hvV" ) ) ) != (system_integer_t) -1 )
169 	{
170 		switch( option )
171 		{
172 			case (system_integer_t) '?':
173 			default:
174 				fprintf(
175 				 stderr,
176 				 "Invalid argument: %" PRIs_SYSTEM "\n",
177 				 argv[ optind - 1 ] );
178 
179 				usage_fprint(
180 				 stdout );
181 
182 				return( EXIT_FAILURE );
183 
184 			case (system_integer_t) 'h':
185 				usage_fprint(
186 				 stdout );
187 
188 				return( EXIT_SUCCESS );
189 
190 			case (system_integer_t) 'v':
191 				verbose = 1;
192 
193 				break;
194 
195 			case (system_integer_t) 'V':
196 				vmdktools_output_copyright_fprint(
197 				 stdout );
198 
199 				return( EXIT_SUCCESS );
200 		}
201 	}
202 	if( optind == argc )
203 	{
204 		fprintf(
205 		 stderr,
206 		 "Missing source file(s).\n" );
207 
208 		usage_fprint(
209 		 stdout );
210 
211 		return( EXIT_FAILURE );
212 	}
213 	source_filenames           = &( argv[ optind ] );
214 	number_of_source_filenames = argc - optind;
215 
216 	libcnotify_verbose_set(
217 	 verbose );
218 	libvmdk_notify_set_stream(
219 	 stderr,
220 	 NULL );
221 	libvmdk_notify_set_verbose(
222 	 verbose );
223 
224 	if( info_handle_initialize(
225 	     &vmdkinfo_info_handle,
226 	     &error ) != 1 )
227 	{
228 		fprintf(
229 		 stderr,
230 		 "Unable to initialize info handle.\n" );
231 
232 		goto on_error;
233 	}
234 	if( info_handle_open_input(
235 	     vmdkinfo_info_handle,
236 	     source_filenames,
237 	     number_of_source_filenames,
238 	     &error ) != 1 )
239 	{
240 		fprintf(
241 		 stderr,
242 		 "Unable to open source file(s).\n" );
243 
244 		goto on_error;
245 	}
246 	if( info_handle_file_fprint(
247 	     vmdkinfo_info_handle,
248 	     &error ) != 1 )
249 	{
250 		fprintf(
251 		 stderr,
252 		 "Unable to print file information.\n" );
253 
254 		goto on_error;
255 	}
256 	if( info_handle_close(
257 	     vmdkinfo_info_handle,
258 	     &error ) != 0 )
259 	{
260 		fprintf(
261 		 stderr,
262 		 "Unable to close info handle.\n" );
263 
264 		goto on_error;
265 	}
266 	if( info_handle_free(
267 	     &vmdkinfo_info_handle,
268 	     &error ) != 1 )
269 	{
270 		fprintf(
271 		 stderr,
272 		 "Unable to free info handle.\n" );
273 
274 		goto on_error;
275 	}
276 	return( EXIT_SUCCESS );
277 
278 on_error:
279 	if( error != NULL )
280 	{
281 		libcnotify_print_error_backtrace(
282 		 error );
283 		libcerror_error_free(
284 		 &error );
285 	}
286 	if( vmdkinfo_info_handle != NULL )
287 	{
288 		info_handle_free(
289 		 &vmdkinfo_info_handle,
290 		 NULL );
291 	}
292 	return( EXIT_FAILURE );
293 }
294 
295