xref: /illumos-gate/usr/src/cmd/rmdir/rmdir.c (revision 4bc0a2ef)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /*
34  * Rmdir(1) removes directory.
35  * If -p option is used, rmdir(1) tries to remove the directory
36  * and it's parent directories.  It exits with code 0 if the WHOLE
37  * given path is removed and 2 if part of path remains.
38  * Results are printed except when -s is used.
39  */
40 
41 #include <stdio.h>
42 #include <libgen.h>
43 #include <errno.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <locale.h>
48 
49 
50 int
51 main(int argc, char **argv)
52 {
53 
54 	char	*prog;
55 	int c, pflag, sflag, errflg, rc;
56 	char *ptr, *remain, *msg, *path;
57 	unsigned int pathlen;
58 
59 	prog = argv[0];
60 	pflag = sflag = 0;
61 	errflg = 0;
62 	/* set effective uid, euid, to be same as real	*/
63 	/* uid, ruid.  Rmdir(2) checks search & write	*/
64 	/* permissions for euid, but for compatibility	*/
65 	/* the check must be done using ruid.		*/
66 
67 	(void) setlocale(LC_ALL, "");
68 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
69 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it wasn't */
70 #endif
71 	(void) textdomain(TEXT_DOMAIN);
72 
73 	if (setuid(getuid()) == -1) {
74 		char	buf[80];
75 
76 		(void) sprintf(buf, gettext("%s: setuid(2) failed"), prog);
77 		perror(buf);
78 		exit(1);
79 	}
80 
81 	while ((c = getopt(argc, argv, "ps")) != EOF)
82 		switch (c) {
83 			case 'p':
84 				pflag++;
85 				break;
86 			case 's':
87 				sflag++;
88 				break;
89 			case '?':
90 				errflg++;
91 				break;
92 		}
93 	if (argc < 2 || errflg) {
94 		(void) fprintf(stderr, gettext("Usage: %s [-ps] dirname ...\n"),
95 		    prog);
96 		exit(2);
97 	}
98 	errno = 0;
99 	argc -= optind;
100 	argv = &argv[optind];
101 	while (argc--) {
102 		ptr = *argv++;
103 		/*
104 		 * -p option. Remove directory and parents.
105 		 * Prints results of removing
106 		 */
107 		if (pflag) {
108 			pathlen = (unsigned)strlen(ptr);
109 			if ((path = (char *)malloc(pathlen + 4)) == NULL ||
110 			    (remain = (char *)malloc(pathlen + 4)) == NULL) {
111 				perror(prog);
112 				exit(2);
113 			}
114 			(void) strcpy(path, ptr);
115 
116 			/*
117 			 * rmdirp removes directory and parents
118 			 * rc != 0 implies only part of path removed
119 			 */
120 
121 			if (((rc = rmdirp(path, remain)) != 0) && !sflag) {
122 				switch (rc) {
123 				case -1:
124 					if (errno == EEXIST)
125 						msg = gettext(
126 						    "Directory not empty");
127 					else
128 						msg = strerror(errno);
129 					break;
130 				case -2:
131 					errno = EINVAL;
132 					msg = gettext("Can not remove . or ..");
133 					break;
134 				case -3:
135 					errno = EINVAL;
136 					msg = gettext(
137 					    "Can not remove current directory");
138 					break;
139 				}
140 				(void) fprintf(stderr, gettext("%s: directory"
141 				    " \"%s\": %s not removed; %s\n"),
142 				    prog, ptr, remain, msg);
143 			}
144 			free(path);
145 			free(remain);
146 			continue;
147 		}
148 
149 		/* No -p option. Remove only one directory */
150 
151 		if (rmdir(ptr) == -1) {
152 			switch (errno) {
153 			case EEXIST:
154 				msg = gettext("Directory not empty");
155 				break;
156 			case ENOTDIR:
157 				msg = gettext("Path component not a directory");
158 				break;
159 			case ENOENT:
160 				msg = gettext("Directory does not exist");
161 				break;
162 			case EACCES:
163 				msg = gettext(
164 				    "Search or write permission needed");
165 				break;
166 			case EBUSY:
167 				msg = gettext(
168 				    "Directory is a mount point or in use");
169 				break;
170 			case EROFS:
171 				msg = gettext("Read-only file system");
172 				break;
173 			case EIO:
174 				msg = gettext(
175 				    "I/O error accessing file system");
176 				break;
177 			case EINVAL:
178 				msg = gettext(
179 				    "Can't remove current directory or ..");
180 				break;
181 			case EFAULT:
182 			default:
183 				msg = strerror(errno);
184 				break;
185 			}
186 			(void) fprintf(stderr,
187 			    gettext("%s: directory \"%s\": %s\n"),
188 			    prog, ptr, msg);
189 			continue;
190 		}
191 	}
192 	return (errno ? 2 : 0);
193 }
194