Remove Unixware and openserver support
[oweals/cde.git] / cde / lib / tt / bin / shell / mover.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
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 $                                                      
28 /*
29  * mover.cc - Link Service/ToolTalk wrapper for mv(1).
30  *
31  * Copyright (c) 1990 by Sun Microsystems, Inc.
32  *
33  */
34
35 #include "tt_options.h"
36 #include <errno.h>
37 #include <string.h>
38 #if defined(__osf__) || defined(linux) || defined(CSRG_BASED)
39 #include <unistd.h>
40 #else
41 #if !defined(sun)
42 #include <osfcn.h>
43 #endif
44 #endif
45 #include <stdlib.h>
46 #include <errno.h>
47 #if defined(ultrix)
48 #include <sys/inode.h>
49 #define S_ISLNK(m)     (((m)&IFMT) == IFLNK)
50 #endif
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include "api/c/tt_c.h"
54 #include "util/tt_gettext.h"
55 #include "util/copyright.h"
56 #include "mover.h"
57
58 /*
59  * External variables
60  */
61
62 /*
63  * mover::mover()
64  */
65 mover::
66 mover( char *arg0 )
67 {
68         if (arg0 != NULL) {
69                 char *base = strrchr( arg0, '/' );
70                 if (base == NULL) {
71                         base = arg0;
72                 } else {
73                         base++; // Don't want the '/'
74                 }
75                 _prog_name = base;
76                 _process_name = _prog_name;
77         }
78         _args = new _Tt_string_list();
79         _from_paths = new _Tt_string_list();
80         _should_mv = TRUE;
81         _force = FALSE;
82         _tt_opened = FALSE;
83         _to_path_is_dir = FALSE;
84 }
85
86 mover::
87 ~mover()
88 {
89 }
90
91 /*
92  * mover::do_mv() - Use system() to invoke mv(1), and return its exit status.
93  *      We can just use _args, since we never get here when our one
94  *      mv-incompatible option (-L) has been given.
95  */
96 int mover::
97 do_mv()
98 {
99         _Tt_string              cmd( "mv" );
100         _Tt_string_list_cursor  arg_cursor( _args );
101
102         while (arg_cursor.next()) {
103                 cmd = cmd.cat( " " ).cat( *arg_cursor );
104         }
105         //printf( "Invoking: %s\n", (char *)cmd );
106         int sys_status = system( (char *)cmd );
107         if (WIFEXITED(sys_status)) {
108                 return WEXITSTATUS(sys_status);
109         } else {
110                 if (! _force) {
111                         fprintf(stderr, "%s: system(\"%s\"): %d\n",
112                                 (char *)_process_name, (char *)cmd, sys_status);
113                 }
114                 return 1;
115         }
116 }
117
118 /*
119  * mover::do_ttmv() - Use tt_file_move() on the things to move.
120  */
121 Tt_status mover::
122 do_ttmv()
123 {
124         Tt_status       worst_err = TT_OK;
125         Tt_status       err;
126         _Tt_string      full_to_path;
127         bool_t          abort = FALSE;
128         bool_t          are_more;
129
130         full_to_path = _to_path;
131         _Tt_string_list_cursor from_path_cursor( _from_paths );
132         /*
133          * call to next() must be first, so that are_more will be valid
134          * if we abort.  Why does the next() method wrap around?
135          */
136         while ((are_more = from_path_cursor.next()) && (! abort)) {
137                 if (! this->can_mv( *from_path_cursor )) {
138                         continue;
139                 }
140                 /*
141                  * tt_file_destroy() any path that mv(1) will delete
142                  */
143                 if (_to_path_is_dir) {
144                         full_to_path = _to_path.cat("/").
145                                        cat(*from_path_cursor);
146                 }
147                 /*
148                  * mv(1) will overwrite any entry in _to_path that
149                  * has the same name as a _from_path.
150                  */
151                 err = tt_file_destroy( (char *)full_to_path );
152                 if ((err > TT_WRN_LAST) && (! _force)) {
153                         fprintf( stderr,
154                                  catgets(_ttcatd, 8, 2,
155                                          "%s: Could not remove "
156                                          "ToolTalk objects of %s "
157                                          "because %s\n"),
158                                  (char *)_process_name,
159                                  (char *)full_to_path,
160                                  tt_status_message(err) );
161                 }
162                 err = tt_file_move( (char *)*from_path_cursor,
163                                     (char *)full_to_path );
164                 if (err > TT_WRN_LAST) {
165                         worst_err = err;
166                         if (! _force) {
167                                 fprintf( stderr,
168                                          catgets(_ttcatd, 8, 3,
169                                                  "%s: Could not move ToolTalk "
170                                                  "objects of \"%s\" to \"%s\" "
171                                                  "because %s\n"),
172                                          (char *)_process_name,
173                                          (char *)*from_path_cursor,
174                                          (char *)full_to_path,
175                                          tt_status_message( err ));
176                         }
177                         switch (err) {
178                             case TT_ERR_DBAVAIL:
179                             case TT_ERR_PATH:
180                                 break;
181                             case TT_ERR_NOMP:
182                             case TT_ERR_DBEXIST:
183                             default:
184                                 abort = TRUE;
185                                 break;
186                         }
187                 }
188         }
189         if (are_more && (! _force)) {
190                 from_path_cursor.prev();
191                 fprintf( stderr,
192                          catgets(_ttcatd, 8, 4,
193                                  "%s: Will not attempt to move the ToolTalk "
194                                  "objects of:\n"),
195                          (char *)_process_name );
196                 while (from_path_cursor.next()) {
197                         fprintf( stderr, "\t%s\n", (char *)*from_path_cursor );
198                 }
199         }
200         /*
201          * TO_DO: This should be uncommented if you think that warning them
202          * about hygiene is more important than obeying the -f flag.
203          *
204         if ((worst_err > TT_WRN_LAST) && _should_mv && _force) {
205                 fprintf( stderr, "%s: The ToolTalk objects of some files were "
206                          "not moved.\nSince you've told us to move the files "
207                          "anyway, you will need to\nuse %s -L to move "
208                          "the ToolTalk objects of the problem files.\n",
209                          (char *)_process_name, (char *)_prog_name );
210         }
211         */
212         return worst_err;
213
214 } /* do_ttmv() */
215
216 /*
217  * mover::can_mv() - Can we move this path to _to_path?
218  *
219  *      TO_DO: Judging by mv.c, can_mv() can be as tricky as you like.
220  *      I'll count on tt_file_move() to Do The Right Thing.
221  */
222 bool_t mover::
223 can_mv( _Tt_string from_path )
224 {
225         struct stat lstat_buf;
226         if (lstat( (char *)from_path, &lstat_buf) == 0) {
227                 if (S_ISLNK(lstat_buf.st_mode)) {
228                         /*
229                          * Don't tt_file_move() a symlink, or TT will
230                          * tt_file_move() the linked file.
231                          */
232                         return FALSE;
233                 } else {
234                         return TRUE;
235                 }
236         } else {
237                 /*
238                  * If we're trying to mv a file that doesn't exist,
239                  * let's not tt_file_move() the associated pathname.
240                  * But if we're trying to ttmv -L a file that doesn't
241                  * exist, we should probably tt_file_move() it anyway.
242                  */
243                 if (_should_mv) {
244                         return FALSE;
245                 } else {
246                         return TRUE;
247                 }
248         }
249 }
250
251 /*
252  * mover::open_tt()
253  */
254 Tt_status mover::
255 open_tt()
256 {
257         char *process_id = tt_open();
258         Tt_status err = tt_ptr_error( process_id );
259         if (err == TT_OK) {
260                 _process_id = process_id;
261                 _tt_opened = TRUE;
262         } else if (err > TT_WRN_LAST) {
263                 fprintf( stderr,
264                          "%s: tt_open(): %s\n",
265                          (char *)_process_name, tt_status_message(err) );
266         }
267         return err;
268 }
269
270 /*
271  * mover::close_tt()
272  */
273 Tt_status mover::
274 close_tt()
275 {
276         if (! _tt_opened) {
277                 return TT_OK;
278         }
279         Tt_status err = tt_close();
280         if (err > TT_WRN_LAST) {
281                 fprintf( stderr,
282                          "%s: tt_close(): %s\n",
283                          (char *)_process_name, tt_status_message(err) );
284         }
285         return err;
286 }
287
288 /*
289  * mover::parse_args()
290  */
291 void mover::
292 parse_args( int argc, char **argv )
293 {
294         bool_t no_more_options = FALSE;
295
296         for ( int arg_num = 1; arg_num < argc; arg_num++ ) {
297                 _Tt_string arg( argv[arg_num] );
298                 _args->append( arg );
299                 if ((arg[0] == '-') && (! no_more_options)) {
300                         if (arg[1] == '\0') {
301                                 /*
302                                  * The bare option "-" means take the
303                                  * subsequent arguments to be pathnames.
304                                  */
305                                 no_more_options = TRUE;
306                         } else {
307                                 for (int n = 1; n < arg.len(); n++) {
308                                         switch (arg[n]) {
309                                             case 'f':
310                                                 _force = TRUE;
311                                                 break;
312                                             case 'L':
313                                                 _should_mv = FALSE;
314                                                 break;
315                                             case 'v':
316                                                 _TT_PRINT_VERSIONS((char *)_prog_name)
317                                                 exit(0);
318                                                 break;
319                                             case 'h':
320                                             default:
321                                                 this->usage();
322                                                 exit(1);
323                                         }
324                                 }
325                         }
326                 } else {
327                         if (arg_num == argc - 1) {
328                                 _to_path = arg;
329                         } else {
330                                 _from_paths->append( arg );
331                         }
332                 }
333         }
334         if ((_to_path.len() <= 0) || (_from_paths->count() <= 0)) {
335                 this->usage();
336                 exit(1);
337         }
338         if (_from_paths->count() > 1) {
339                 /*
340                  * If multiple things to move, the place we're moving them to
341                  * must be a directory.
342                  */
343                 struct stat stat_buf;
344
345                 if (stat( (char *)_to_path, &stat_buf) != 0) {
346                         fprintf( stderr, "%s: \"%s\": ", (char *)_process_name,
347                                  (char *)_to_path );
348                         perror(NULL);
349                         exit(2);
350                 }
351                 if (! S_ISDIR(stat_buf.st_mode)) {
352                         fprintf( stderr, "%s: \"%s\": %s\n",
353                                  (char *)_process_name, (char *)_to_path,
354                                  strerror(ENOTDIR) );
355                         this->usage();
356                         exit(2);
357                 }
358                 _to_path_is_dir = TRUE;
359         } else {
360                 struct stat stat_buf;
361
362                 _to_path_is_dir = FALSE;
363                 if (stat( (char *)_to_path, &stat_buf) == 0) {
364                         _to_path_is_dir = S_ISDIR(stat_buf.st_mode);
365                 }
366         }
367 }
368
369 /*
370  * mover::usage()
371  */
372 void mover::
373 usage(FILE *fs) const
374 {
375         fprintf( fs,
376                  catgets(_ttcatd, 8, 5,
377                          "Usage: %s [-] [-fL] path1 path2\n"
378                          "       %s [-] [-fL] path1 [path2 ...] dir\n"
379                          "       %s -v\n"
380                          "       %s -h\n"),
381                  (char *)_prog_name, (char *)_prog_name, (char *)_prog_name,
382                  (char *)_prog_name );
383         fprintf( fs, "%s",
384                  catgets(_ttcatd, 8, 6,
385                          "\t-L      do not perform a mv(1)\n"
386                          "\t-v      print the version number and quit\n"
387                          "\t-h      print this message\n" ));
388 }