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