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