remove ultrix support
[oweals/cde.git] / cde / lib / tt / bin / shell / remover.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 //%%  $TOG: remover.C /main/5 1999/10/14 18:37:42 mgreess $                                                     
28 /*
29  * remover.cc - ToolTalk wrapper for rm(1) and rmdir(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(__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 #include <sys/stat.h>
48 #include <sys/wait.h>
49 #include "api/c/tt_c.h"
50 #include "util/tt_path.h"
51 #include "util/tt_gettext.h"
52 #include "util/copyright.h"
53 #include "remover.h"
54
55 /*
56  * External variables
57  */
58
59 /*
60  * remover::remover()
61  */
62 remover::
63 remover( char *arg0 )
64 {
65         if (arg0 != NULL) {
66                 char *base = strrchr( arg0, '/' );
67                 if (base == NULL) {
68                         base = arg0;
69                 } else {
70                         base++;
71                 }
72                 _prog_name = base;
73                 _process_name = _prog_name;
74         }
75         _am_rmdir = (_prog_name == "ttrmdir");
76         _args = new _Tt_string_list();
77         _paths = new _Tt_string_list();
78         _should_rm = TRUE;
79         _force = FALSE;
80         _recurse = FALSE;
81         _tt_opened = FALSE;
82 }
83
84 remover::
85 ~remover()
86 {
87 }
88
89 /*
90  * remover::do_rm() - Invoke rm[dir](1), and return its exit status.
91  *      We can just use _args, since we never get here when our one
92  *      incompatible option (-L) has been given.
93  */
94 int remover::
95 do_rm()
96 {
97         _Tt_string              cmd;
98         _Tt_string_list_cursor  arg_cursor( _args );
99
100         if (_am_rmdir) {
101                 cmd = "rmdir";
102         } else {
103                 cmd = "rm";
104         }
105         while (arg_cursor.next()) {
106                 cmd = cmd.cat( " " ).cat( *arg_cursor );
107         }
108         //printf( "Invoking: %s\n", (char *)cmd );
109         int sys_status = system( (char *)cmd );
110         if (WIFEXITED(sys_status)) {
111                 return WEXITSTATUS(sys_status);
112         } else {
113                 fprintf( stderr,
114                          "%s: system(\"%s\"): %d\n",
115                          (char *)_process_name, (char *)cmd, sys_status );
116                 return 1;
117         }
118 }
119
120 /*
121  * remover::do_ttrm() - Use tt_file_destroy() on the paths to destroy.
122  */
123 Tt_status remover::
124 do_ttrm()
125 {
126         return this->_ttrm_paths( _paths );
127 }
128
129 /*
130  * remover::ttrm_path() - tt_file_destroy() this path.
131  */
132 Tt_status remover::
133 _ttrm_paths( _Tt_string_list_ptr paths )
134 {
135         Tt_status       worst_err = TT_OK;
136         Tt_status       err;
137         bool_t          abort = FALSE;
138
139         while ((! paths->is_empty()) && (! abort)) {
140                 _Tt_string              path     = paths->top();
141                 _Tt_string_list_ptr     children;
142
143                 paths->pop();
144                 if (! this->can_rm( path )) {
145                         continue;
146                 }
147                 if (_recurse) {
148                         _Tt_string_list_ptr children = _tt_dir_entries(path,
149                                                                        FALSE);
150                         err = this->_ttrm_paths( children );
151                         if (err > TT_WRN_LAST) {
152                                 switch (err) {
153                                     case TT_ERR_DBAVAIL:
154                                     case TT_ERR_PATH:
155                                         break;
156                                     case TT_ERR_NOMP:
157                                     case TT_ERR_DBEXIST:
158                                     default:
159                                         abort = TRUE;
160                                         break;
161                                 }
162                         }
163                 }
164                 if (! abort) {
165                         err = tt_file_destroy( (char *)path );
166                         if (err > TT_WRN_LAST) {
167                                 worst_err = err;
168                                 if (! _force) {
169                                         fprintf( stderr,
170                                                  catgets(_ttcatd, 8, 7,
171                                                          "%s: Could not remove "
172                                                          "ToolTalk objects of "
173                                                          "%s because %s\n"),
174                                                  (char *)_process_name,
175                                                  (char *)path,
176                                                  tt_status_message(err) );
177                                 }
178                                 switch (err) {
179                                     case TT_ERR_DBAVAIL:
180                                     case TT_ERR_PATH:
181                                         break;
182                                     case TT_ERR_NOMP:
183                                     case TT_ERR_DBEXIST:
184                                     default:
185                                         abort = TRUE;
186                                         break;
187                                 }
188                         }
189                 }
190         }
191         return worst_err;
192
193 } /* ttrm_paths() */
194
195 /*
196  * remover::can_rm() - Can we remove this path?
197  *
198  *      TO_DO: For now I'll count on tt_file_destroy() not to let me
199  *      destroy the specs in files I can't remove.
200  */
201 bool_t remover::
202 can_rm( _Tt_string path )
203 {
204         if (_am_rmdir) {
205         } else {
206                 if (! _recurse) {
207                         struct stat lstat_buf;
208
209                         if (lstat( (char *)path, &lstat_buf) == 0) {
210                                 if (S_ISDIR(lstat_buf.st_mode)) {
211                                         /*
212                                          * rm(1) without the -r flag
213                                          * won't remove directories,
214                                          * but tt_file_destroy() will,
215                                          * so we make sure not to ask
216                                          * it to.
217                                          */
218                                         if (! _force) {
219                                                 fprintf( stderr, "%s: %s: %s\n",
220                                                          (char *)_prog_name,
221                                                          (char *)path,
222                                                          strerror(EISDIR) );
223                                         }
224                                         return FALSE;
225                                 } else if (S_ISLNK(lstat_buf.st_mode)) {
226                                         /*
227                                          * Don't tt_file_destroy() a symlink,
228                                          * or TT will tt_file_destroy() the
229                                          * linked file.
230                                          */
231                                         return FALSE;
232                                 } else {
233                                         return TRUE;
234                                 }
235                         } else {
236                                 return FALSE;
237                         }
238                 }
239         }
240         return FALSE;
241 }
242
243 /*
244  * remover::open_tt()
245  */
246 Tt_status remover::
247 open_tt()
248 {
249         char *process_id = tt_open();
250         Tt_status err = tt_ptr_error( process_id );
251         if (err == TT_OK) {
252                 _process_id = process_id;
253                 _tt_opened = TRUE;
254         } else if (err > TT_WRN_LAST) {
255                 fprintf( stderr,
256                          "%s: tt_open(): %s\n",
257                          (char *)_process_name, tt_status_message(err) );
258         }
259         return err;
260 }
261
262 /*
263  * remover::close_tt()
264  */
265 Tt_status remover::
266 close_tt()
267 {
268         if (! _tt_opened) {
269                 return TT_OK;
270         }
271         Tt_status err = tt_close();
272         if (err > TT_WRN_LAST) {
273                 fprintf( stderr,
274                          "%s: tt_close(): %s\n",
275                          (char *)_process_name, tt_status_message(err) );
276         }
277         return err;
278 }
279
280 /*
281  * remover::parse_args()
282  */
283 void remover::
284 parse_args( int argc, char **argv )
285 {
286         bool_t no_more_options = FALSE;
287
288         for ( int arg_num = 1; arg_num < argc; arg_num++ ) {
289                 _Tt_string arg( argv[arg_num] );
290                 _args->append( arg );
291                 if (_am_rmdir) {
292                         if (arg[0] == '-') {
293                                 this->_parse_arg( (char *)arg );
294                         } else {
295                                 _paths->append( arg );
296                         }
297                 } else {
298                         if ((arg[0] != '-') || no_more_options) {
299                                 _paths->append( arg );
300                         } else {
301                                 if (arg[1] == '\0') {
302                                         /*
303                                          * The bare option "-" means take the
304                                          * subsequent arguments to be paths.
305                                          */
306                                         no_more_options = TRUE;
307                                 } else {
308                                         this->_parse_arg( (char *)arg );
309                                 }
310                         }
311                 }
312         }
313         if (_paths->count() <= 0) {
314                 this->usage();
315                 exit(1);
316         }
317 }
318
319 /*
320  * remover::_parse_arg() - Parse an option 
321  */
322 void remover::
323 _parse_arg( char *arg )
324 {
325         if (arg == NULL) {
326                 return;
327         }
328         int n = -1;
329         while (arg[++n] != '\0') {
330                 switch (arg[n]) {
331                     case '-':
332                         if (n != 0) {
333                                 this->usage();
334                                 exit(1);
335                         }
336                         break;
337                     case 'f':
338                         if (_am_rmdir) {
339                                 this->usage();
340                                 exit(1);
341                         } else {
342                                 _force = TRUE;
343                         }
344                         break;
345                     case 'r':
346                     case 'R':
347                         if (_am_rmdir) {
348                                 this->usage();
349                                 exit(1);
350                         } else {
351                                 _recurse = TRUE;
352                         }
353                         break;
354                     case 'L':
355                         _should_rm = FALSE;
356                         break;
357                     case 'v':
358                         _TT_PRINT_VERSIONS((char *)_prog_name)
359                         exit(0);
360                         break;
361                     case 'h':
362                     default:
363                         this->usage();
364                         exit(1);
365                 }
366         }
367 }
368
369 /*
370  * remover::usage()
371  */
372 void remover::
373 usage(FILE *fs) const
374 {
375         fprintf( fs,
376                  catgets(_ttcatd, 8, 8,
377                          "Usage: %s [-] [-%s] %s ...\n"
378                          "       %s -v\n"
379                          "       %s -h\n"),
380                  (char *)_prog_name,
381                  (_am_rmdir ? "L" : "fLrR"),
382                  (_am_rmdir ? catgets(_ttcatd, 8, 9, "file")
383                         : catgets(_ttcatd, 8, 10, "dir") ),
384                  (char *)_prog_name, (char *)_prog_name );
385         fprintf( fs,
386                  catgets(_ttcatd, 8, 11,
387                          "\t-L      do not perform a %s(1)\n"
388                          "\t-v      print the version number and quit\n"
389                          "\t-h[elp] print this message\n" ),
390                  (_am_rmdir ? "rmdir" : "rm"));
391 }