2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
24 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
25 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
26 //%% (c) Copyright 1993, 1994 Novell, Inc.
27 //%% $XConsortium: mover.C /main/4 1995/10/20 16:36:15 rswiston $
29 * mover.cc - Link Service/ToolTalk wrapper for mv(1).
31 * Copyright (c) 1990 by Sun Microsystems, Inc.
35 #include "tt_options.h"
41 #if !defined(USL) && !defined(__uxp__)
48 #include <sys/inode.h>
49 #define S_ISLNK(m) (((m)&IFMT) == IFLNK)
52 #if defined(OPT_BUG_USL) || defined(OPT_BUG_UXP)
53 #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
56 #include "api/c/tt_c.h"
57 #include "util/tt_gettext.h"
58 #include "util/copyright.h"
72 char *base = strrchr( arg0, '/' );
76 base++; // Don't want the '/'
79 _process_name = _prog_name;
81 _args = new _Tt_string_list();
82 _from_paths = new _Tt_string_list();
94 * mover::do_mv() - Use system() to invoke mv(1), and return its exit status.
95 * We can just use _args, since we never get here when our one
96 * mv-incompatible option (-L) has been given.
101 _Tt_string cmd( "mv" );
102 _Tt_string_list_cursor arg_cursor( _args );
104 while (arg_cursor.next()) {
105 cmd = cmd.cat( " " ).cat( *arg_cursor );
107 //printf( "Invoking: %s\n", (char *)cmd );
108 int sys_status = system( (char *)cmd );
109 if (WIFEXITED(sys_status)) {
110 return WEXITSTATUS(sys_status);
113 fprintf(stderr, "%s: system(\"%s\"): %d\n",
114 (char *)_process_name, (char *)cmd, sys_status);
121 * mover::do_ttmv() - Use tt_file_move() on the things to move.
126 Tt_status worst_err = TT_OK;
128 _Tt_string full_to_path;
129 bool_t abort = FALSE;
132 full_to_path = _to_path;
133 _Tt_string_list_cursor from_path_cursor( _from_paths );
135 * call to next() must be first, so that are_more will be valid
136 * if we abort. Why does the next() method wrap around?
138 while ((are_more = from_path_cursor.next()) && (! abort)) {
139 if (! this->can_mv( *from_path_cursor )) {
143 * tt_file_destroy() any path that mv(1) will delete
145 if (_to_path_is_dir) {
146 full_to_path = _to_path.cat("/").
147 cat(*from_path_cursor);
150 * mv(1) will overwrite any entry in _to_path that
151 * has the same name as a _from_path.
153 err = tt_file_destroy( (char *)full_to_path );
154 if ((err > TT_WRN_LAST) && (! _force)) {
156 catgets(_ttcatd, 8, 2,
157 "%s: Could not remove "
158 "ToolTalk objects of %s "
160 (char *)_process_name,
161 (char *)full_to_path,
162 tt_status_message(err) );
164 err = tt_file_move( (char *)*from_path_cursor,
165 (char *)full_to_path );
166 if (err > TT_WRN_LAST) {
170 catgets(_ttcatd, 8, 3,
171 "%s: Could not move ToolTalk "
172 "objects of \"%s\" to \"%s\" "
174 (char *)_process_name,
175 (char *)*from_path_cursor,
176 (char *)full_to_path,
177 tt_status_message( err ));
191 if (are_more && (! _force)) {
192 from_path_cursor.prev();
194 catgets(_ttcatd, 8, 4,
195 "%s: Will not attempt to move the ToolTalk "
197 (char *)_process_name );
198 while (from_path_cursor.next()) {
199 fprintf( stderr, "\t%s\n", (char *)*from_path_cursor );
203 * TO_DO: This should be uncommented if you think that warning them
204 * about hygiene is more important than obeying the -f flag.
206 if ((worst_err > TT_WRN_LAST) && _should_mv && _force) {
207 fprintf( stderr, "%s: The ToolTalk objects of some files were "
208 "not moved.\nSince you've told us to move the files "
209 "anyway, you will need to\nuse %s -L to move "
210 "the ToolTalk objects of the problem files.\n",
211 (char *)_process_name, (char *)_prog_name );
219 * mover::can_mv() - Can we move this path to _to_path?
221 * TO_DO: Judging by mv.c, can_mv() can be as tricky as you like.
222 * I'll count on tt_file_move() to Do The Right Thing.
225 can_mv( _Tt_string from_path )
227 struct stat lstat_buf;
228 if (lstat( (char *)from_path, &lstat_buf) == 0) {
229 if (S_ISLNK(lstat_buf.st_mode)) {
231 * Don't tt_file_move() a symlink, or TT will
232 * tt_file_move() the linked file.
240 * If we're trying to mv a file that doesn't exist,
241 * let's not tt_file_move() the associated pathname.
242 * But if we're trying to ttmv -L a file that doesn't
243 * exist, we should probably tt_file_move() it anyway.
259 char *process_id = tt_open();
260 Tt_status err = tt_ptr_error( process_id );
262 _process_id = process_id;
264 } else if (err > TT_WRN_LAST) {
266 "%s: tt_open(): %s\n",
267 (char *)_process_name, tt_status_message(err) );
281 Tt_status err = tt_close();
282 if (err > TT_WRN_LAST) {
284 "%s: tt_close(): %s\n",
285 (char *)_process_name, tt_status_message(err) );
291 * mover::parse_args()
294 parse_args( int argc, char **argv )
296 bool_t no_more_options = FALSE;
298 for ( int arg_num = 1; arg_num < argc; arg_num++ ) {
299 _Tt_string arg( argv[arg_num] );
300 _args->append( arg );
301 if ((arg[0] == '-') && (! no_more_options)) {
302 if (arg[1] == '\0') {
304 * The bare option "-" means take the
305 * subsequent arguments to be pathnames.
307 no_more_options = TRUE;
309 for (int n = 1; n < arg.len(); n++) {
318 _TT_PRINT_VERSIONS((char *)_prog_name)
329 if (arg_num == argc - 1) {
332 _from_paths->append( arg );
336 if ((_to_path.len() <= 0) || (_from_paths->count() <= 0)) {
340 if (_from_paths->count() > 1) {
342 * If multiple things to move, the place we're moving them to
343 * must be a directory.
345 struct stat stat_buf;
347 if (stat( (char *)_to_path, &stat_buf) != 0) {
348 fprintf( stderr, "%s: \"%s\": ", (char *)_process_name,
353 if (! S_ISDIR(stat_buf.st_mode)) {
354 fprintf( stderr, "%s: \"%s\": %s\n",
355 (char *)_process_name, (char *)_to_path,
360 _to_path_is_dir = TRUE;
362 struct stat stat_buf;
364 _to_path_is_dir = FALSE;
365 if (stat( (char *)_to_path, &stat_buf) == 0) {
366 _to_path_is_dir = S_ISDIR(stat_buf.st_mode);
375 usage(FILE *fs) const
378 catgets(_ttcatd, 8, 5,
379 "Usage: %s [-] [-fL] path1 path2\n"
380 " %s [-] [-fL] path1 [path2 ...] dir\n"
383 (char *)_prog_name, (char *)_prog_name, (char *)_prog_name,
384 (char *)_prog_name );
386 catgets(_ttcatd, 8, 6,
387 "\t-L do not perform a mv(1)\n"
388 "\t-v print the version number and quit\n"
389 "\t-h print this message\n" ));