6 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7 * Copyright (C) 2009, 2010, 2011, 2012, MinGW.org Project
10 * Initiation stub for command line invocation of mingw-get
13 * This is free software. Permission is granted to copy, modify and
14 * redistribute this software, under the provisions of the GNU General
15 * Public License, Version 3, (or, at your option, any later version),
16 * as published by the Free Software Foundation; see the file COPYING
17 * for licensing details.
19 * Note, in particular, that this software is provided "as is", in the
20 * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
21 * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
22 * PARTICULAR PURPOSE. Under no circumstances will the author, or the
23 * MinGW Project, accept liability for any damages, however caused,
24 * arising from the use of this software.
27 #define _WIN32_WINNT 0x500
28 #define WIN32_LEAN_AND_MEAN
41 #define EXIT_FATAL EXIT_FAILURE + 1
43 static const char *progname;
44 extern const char *version_identification;
46 static const char *help_text =
47 "Manage MinGW and MSYS installations (command line user interface).\n\n"
50 " mingw-get [OPTIONS] ACTION [package-spec[version-bounds] ...]\n\n"
53 " mingw-get [OPTIONS] {install | upgrade | remove} package-spec ...\n"
54 " mingw-get [OPTIONS] {show | list} [package-spec ...]\n\n"
57 " --help, -h Show this help text\n"
59 " --version, -V Show version and licence information\n"
61 " --verbose, -v Increase verbosity of diagnostic or\n"
62 " progress reporting output; repeat up\n"
63 " to three times for maximum verbosity\n"
64 " --verbose=N Set verbosity level to N; (0 <= N <= 3)\n"
67 /* The "--trace" option is available only when dynamic tracing
68 * debugging support is compiled in; don't advertise it otherwise.
70 #if DEBUG_ENABLED( DEBUG_TRACE_DYNAMIC )
71 " --trace=N Enable tracing feature N; (debugging aid)\n"
75 /* The following are always available...
77 " --reinstall When performing an install or upgrade\n"
78 " operation, reinstall any named package\n"
79 " for which the most recent release is\n"
80 " already installed\n"
82 " --recursive Extend the scope of \"install --reinstall\"\n"
83 " or of \"upgrade\", such that the operation\n"
84 " is applied recursively to all prerequisites\n"
85 " of all packages named on the command line\n"
87 " --download-only Download the package archive files which\n"
88 " would be required to complete the specified\n"
89 " install, upgrade, or source operation, but\n"
90 " do not unpack them, or otherwise proceed\n"
91 " to complete the operation\n"
93 " --print-uris Display the repository URIs from which\n"
94 " package archive files would be retrieved\n"
95 " prior to performing the specified install,\n"
96 " upgrade, or source operation, but do not\n"
97 " download any package file, or otherwise\n"
98 " proceed with the operation\n"
100 " --all-related When performing source or licence operations,\n"
101 " causes mingw-get to retrieve, and optionally to\n"
102 " unpack the source or licence archives for all\n"
103 " runtime prerequisites of, and in addition to,\n"
104 " the nominated package\n"
106 " --desktop[=all-users]\n"
107 " Enable the creation of desktop shortcuts, for\n"
108 " packages which provide the capability via pre-\n"
109 " or post-install scripts; the optional 'all-users'\n"
110 " qualifier requests that all such shortcuts are\n"
111 " to be made available to all users; without it\n"
112 " shortcuts will be created for current user only\n"
114 " Note that specification of this option does not\n"
115 " guarantee that shortcuts will be created; the\n"
116 " onus lies with individual package maintainers\n"
117 " to provide scripting to support this capability\n"
119 " --start-menu[=all-users]\n"
120 " Enable the creation of start menu shortcuts, for\n"
121 " packages which provide the capability via pre-\n"
122 " or post-install scripts; the optional 'all-users'\n"
123 " qualifier requests that all such shortcuts are\n"
124 " to be made available to all users; without it\n"
125 " shortcuts will be created for current user only\n"
127 " Note that specification of this option does not\n"
128 " guarantee that shortcuts will be created; the\n"
129 " onus lies with individual package maintainers\n"
130 " to provide scripting to support this capability\n"
133 " update Update local copy of repository catalogues\n"
134 " list, show List and show details of available packages\n"
135 " source Download and optionally unpack package sources\n"
136 " licence Download and optionally unpack licence packages,\n"
137 " handling them as if they are source packages\n"
138 " install Install new packages\n"
139 " upgrade Upgrade previously installed packages\n"
140 " remove Remove previously installed packages\n\n"
142 "Package Specifications:\n"
143 " [subsystem-]name[-component]:\n"
144 " msys-bash-doc The 'doc' component of the bash package for MSYS\n"
145 " mingw32-gdb All components of the gdb package for MinGW\n\n"
147 "Version Bounds (for install or upgrade actions):\n"
148 " {>|>=|=|<=|<}major[.minor[.rev]][-subsystem-major[.minor[.rev]]]:\n"
149 " \"gcc=4.5.*\" Latest available release of GCC version 4.5.x\n"
150 " \"gcc<4.6\" Alternative representation for GCC version 4.5.x\n\n"
152 "Use 'mingw-get list' to identify possible package names, and the\n"
153 "components associated with each.\n\n"
155 "Quote package names with attached version bounds specifications, to\n"
156 "avoid possible misinterpretation of shell operators. Do NOT insert\n"
157 "white space at any point within any \"package-spec[version-bounds]\"\n"
158 "specification string.\n\n"
161 #define IMPLEMENT_INITIATION_RITES PHASE_ONE_RITES
164 static __inline__ __attribute__((__always_inline__))
165 char **cli_setargv( HMODULE my_dll, struct pkgopts *opts, char **argv )
167 /* A local wrapper function to facilitate passing pre-parsed
168 * command line options while performing the "climain()" call
169 * into mingw-get-0.dll
171 * Note that this requires a version of mingw-get-0.dll which
172 * provides the "cli_setopts()" hook...
174 typedef void (*dll_hook)(struct pkgopts *);
175 dll_hook cli_setopts = (dll_hook)(GetProcAddress( my_dll, "cli_setopts" ));
176 if( cli_setopts != NULL )
178 * ...which allows us to pass the pre-parsed options.
182 /* In any case, we always return the argument vector which is
183 * to be passed in the "climain()" call itself.
188 static int xatoi( const char *input )
190 /* A replacement for the standard atoi() function; this implementation
191 * directs the call to strtol(), and so supports conversion of octal or
192 * hexadecimal representations, in addition to the decimal representation
193 * required by standard atoi(), while also protecting against the adverse
194 * effect of passing a NULL input pointer.
196 return (input != NULL) ? strtol( input, NULL, 0 ) : 0;
199 #define atmost( lim, val ) ((lim) < (val)) ? (lim) : (val)
201 /* Disable command line globbing; we don't need it, and case-insensitive
202 * glob matches on files such as INSTALL may interfere with case-sensitive
203 * specification of the mingw-get action keywords.
207 int main( int argc, char **argv )
209 /* Provide storage for interpretation of any parsed command line options.
210 * Note that we could also initialise them here, but then we would need to
211 * give attention to the number of initialisers required; to save us that
212 * concern we will defer to an initialisation loop, below.
214 struct pkgopts parsed_options;
216 /* Make a note of this program's name, and where it's installed.
219 progname = basename( *argv );
223 /* The user specified arguments on the command line...
224 * Interpret any which specify processing options for this application,
225 * (these are all specified in GNU `long only' style).
228 struct option options[] =
230 /* Option Name Argument Category Store To Return Value
231 * -------------- ------------------ -------- ------------------
233 { "version", no_argument, NULL, 'V' },
234 { "help", no_argument, NULL, 'h' },
235 { "verbose", optional_argument, NULL, OPTION_VERBOSE },
237 { "recursive", no_argument, &optref, OPTION_RECURSIVE },
238 { "reinstall", no_argument, &optref, OPTION_REINSTALL },
239 { "download-only", no_argument, &optref, OPTION_DNLOAD_ONLY },
240 { "print-uris", no_argument, &optref, OPTION_PRINT_URIS },
242 { "all-related", no_argument, &optref, OPTION_ALL_RELATED },
244 { "desktop", optional_argument, &optref, OPTION_DESKTOP },
245 { "start-menu", optional_argument, &optref, OPTION_START_MENU },
247 # if DEBUG_ENABLED( DEBUG_TRACE_DYNAMIC )
248 /* The "--trace" option is supported only when dynamic tracing
249 * debugging support has been compiled in.
251 { "trace", required_argument, &optref, OPTION_TRACE },
254 /* This list must be terminated by a null definition...
260 for( opt = OPTION_FLAGS; opt < OPTION_TABLE_SIZE; ++opt )
262 * Ensure that all entries within the options table are initialised
263 * to zero, (equivalent to NULL for pointer entries)...
265 parsed_options.flags[opt].numeric = 0;
267 while( (opt = getopt_long_only( argc, argv, "vVh", options, &offset )) != -1 )
269 * Parse any user specified options from the command line...
274 /* This is a request to display the version of the application;
275 * emit the requisite informational message, and quit.
277 printf( version_identification );
281 /* This is a request to display help text and quit.
287 /* This is a request to set an explicit verbosity level,
288 * (minimum zero, maximum three), or if no explicit argument
289 * is specified, to increment verbosity as does "-v".
293 /* This is the case where an explicit level was specified...
295 parsed_options.flags[OPTION_FLAGS].numeric =
296 (parsed_options.flags[OPTION_FLAGS].numeric & ~OPTION_VERBOSE)
297 | atmost( OPTION_VERBOSE_MAX, xatoi( optarg ));
302 /* This is a request to increment the verbosity level
303 * from its initial zero setting, to a maximum of three.
305 if( (parsed_options.flags[OPTION_FLAGS].numeric & OPTION_VERBOSE) < 3 )
306 ++parsed_options.flags[OPTION_FLAGS].numeric;
310 switch( optref & OPTION_STORAGE_CLASS )
312 /* This represents a generic option specification,
313 * allowing for storage of a option argument of the
314 * specified class into a specified option slot...
318 case OPTION_STORE_STRING:
319 /* This is a simple store of a option argument
320 * which represents a character string.
322 mark_option_as_set( parsed_options, optref );
323 parsed_options.flags[optref & 0xfff].string = optarg;
326 case OPTION_STORE_NUMBER:
327 /* This is also a simple store of the argument value,
328 * in this case interpreted as a number.
330 mark_option_as_set( parsed_options, optref );
331 parsed_options.flags[optref & 0xfff].numeric = xatoi( optarg );
334 case OPTION_MERGE_NUMBER:
335 /* In this case, we combine the value of the argument,
336 * again interpreted as a number, with the original value
337 * stored in the option slot, forming the bitwise logical
338 * .OR. of the pair of values.
340 mark_option_as_set( parsed_options, optref );
341 parsed_options.flags[optref & 0xfff].numeric |= xatoi( optarg );
345 /* This is a mask and store operation for a specified
346 * bit-field within the first pair of flags slots; in
347 * this case, the optref value itself specifies a 12-bit
348 * value, a 12-bit combining mask, and an alignment shift
349 * count between 0 and 52, in 4-bit increments.
351 if( (shift = (optref & OPTION_SHIFT_MASK) >> 22) < 53 )
353 uint64_t value = optref & 0xfff;
354 uint64_t mask = (optref & 0xfff000) >> 12;
355 *(uint64_t *)(parsed_options.flags) &= ~(mask << shift);
356 *(uint64_t *)(parsed_options.flags) |= value << shift;
362 /* User specified an invalid or unsupported option...
365 fprintf( stderr, "%s: option '-%s' not yet supported\n",
366 progname, options[offset].name
372 /* Establish the installation path for the mingw-get application...
374 if( (approot = AppPathNameW( NULL )) != NULL )
376 /* ...and set up the APPROOT environment variable to refer to
377 * the associated installation prefix, (ensuring that it ends
378 * with a directory name separator)...
380 const char *approot_fmt = "APPROOT=%S\\";
381 char approot_setup[1 + snprintf( NULL, 0, approot_fmt, approot )];
382 snprintf( approot_setup, sizeof( approot_setup ), approot_fmt, approot );
383 putenv( approot_setup );
388 /* The user specified arguments on the command line...
389 * we load the supporting DLL into the current process context,
390 * then, remaining in command line mode, we jump to its main
391 * command line processing routine...
394 char *argv_base = *argv;
395 typedef int (*dll_entry)( int, char ** );
396 HMODULE my_dll = LoadLibraryW( AppPathNameW( MINGW_GET_DLL ) );
397 dll_entry climain = (dll_entry)(GetProcAddress( my_dll, "climain" ));
398 if( climain == NULL )
400 /* ...bailing out, on failure to load the DLL.
402 fprintf( stderr, "%s: %S: shared library load failed\n",
403 progname, MINGW_GET_DLL
408 /* Adjust argc and argv to discount parsed options...
413 * ...while preserving the original argv[0] reference within
414 * the first remaining argument to be passed to climain().
418 /* We want only one mingw-get process accessing the XML database
419 * at any time; attempt to acquire an exclusive access lock...
421 if( (lock = pkgInitRites( progname )) >= 0 )
423 /* ...and proceed, only if successful.
424 * A non-zero return value indicates that a fatal error occurred.
426 int rc = climain( argc, cli_setargv( my_dll, &parsed_options, argv ) );
428 /* We must release the mingw-get DLL code, BEFORE we invoke
429 * last rites processing, (otherwise the last rites clean-up
430 * handler exhibits abnormal behaviour when it is exec'd).
432 FreeLibrary( my_dll );
434 return pkgLastRites( lock, progname );
437 (void) pkgLastRites( lock, progname );
441 /* If we get to here, then we failed to acquire a lock;
448 { /* No arguments were specified on the command line...
449 * we interpret this as a request to start up in GUI mode...
451 wchar_t *libexec_path = AppPathNameW( MINGW_GET_GUI );
452 char gui_program[1 + snprintf( NULL, 0, "%S", libexec_path )];
453 snprintf( gui_program, sizeof( gui_program ), "%S", libexec_path );
454 int status = execv( gui_program, (const char* const*)(argv) );
456 /* If we get to here, then the GUI could not be started;
457 * first, try the fall-back GUI diagnostic stub...
459 libexec_path = AppPathNameW( MINGW_GET_GFB );
460 snprintf( gui_program, sizeof( gui_program ), "%S", libexec_path );
461 status = execv( gui_program, (const char* const*)(argv) );
463 /* ...before issuing a diagnostic message, and quitting
464 * with an abnormal termination code.
467 "%s: %S: unable to start GUI; helper program not installed\n",
468 progname, MINGW_GET_GUI
474 /* $RCSfile$: end of file */