/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* rm [-fiRr] file ...
*/
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <langinfo.h>
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <values.h>
#include "getresponse.h"
struct dlist {
};
(int)AT_FDCWD,
};
static void memerror(void);
static int errcnt;
static char *pathbuf;
static int nfds;
int
{
int errflg = 0;
int c;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case 'f':
#ifdef XPG4
#endif
break;
case 'i':
#ifdef XPG4
#endif
break;
case 'r':
case 'R':
break;
case '?':
errflg = 1;
break;
}
/*
* For BSD compatibility allow '-' to delimit the end
* of options. However, if options were already explicitly
* terminated with '--', then treat '-' literally: otherwise,
* "rm -- -" won't remove '-'.
*/
optind++;
exit(2);
}
gettext("rm: cannot stat root directory: %s\n"),
exit(2);
}
memerror();
if (init_yes() < 0) {
exit(2);
}
if (p == NULL)
p = *argv;
else
p = p + 1;
errcnt++;
continue;
}
/* Retry when we can't walk back up. */
;
}
return (errcnt != 0 ? 2 : 0);
}
static void
{
char *p;
const char *q = fname;
p = pathbuf;
} else {
*p++ = '/';
}
while (*q != '\0') {
char *np;
pathbuflen += MAXPATHLEN;
memerror();
}
*p++ = *q++;
}
*p = '\0';
}
static void
{
nfds--;
}
}
static int
reclaim(void)
{
return (-1);
return (0);
}
static void
{
}
static int
{
int fd;
(void) reclaim();
if (reclaim() != 0)
return (-1);
}
if (fd < 0)
return (-1);
return (-1);
}
nfds++;
return (0);
}
/*
* Since we never pop the top frame, cur->up can never be NULL.
* If we pop beyond a frame we closed, we try to reopen "..".
*/
static int
{
gettext("rm: cannot reopen %s: %s\n"),
exit(2);
}
"The directory %s was moved or linked to "
"another directory during the execution of rm\n"),
pathbuf);
ret = -1;
} else {
/* If telldir failed, we take it from the top. */
}
return (ret);
}
/*
* The stack frame of this function is minimized so that we can
* recurse quite a bit before we overflow the stack; around
* 30,000-40,000 nested directories can be removed with the default
* stack limit.
*/
static int
{
int flag;
int err;
/*
* Construct the pathname: note that the entry may live in memory
* allocated by readdir and that after return from recursion
* the memory is no longer valid. So after the recursive rm()
* call, we use the global pathbuf instead of the entry argument.
*/
if (!silent) {
errcnt++;
}
return (0);
}
/*
* If "-r" wasn't specified, trying to remove directories
* is an error.
*/
if (!recursive) {
errcnt++;
return (0);
}
errcnt++;
return (0);
}
/*
* TRANSLATION_NOTE - The following message will contain the
* first character of the strings for "yes" and "no" defined
* in the file "nl_langinfo.po". After substitution, the
* message will appear as follows:
* rm: examine files in directory <directoryname> (y/n)?
* where <directoryname> is the directory to be removed
*
*/
gettext("rm: examine files in directory %s (%s/%s)? "),
return (0);
}
flag = AT_REMOVEDIR;
#ifdef XPG4
/*
* XCU4 and POSIX.2: If not interactive, check to see whether
* or not directory is readable or writable and if not,
* prompt user for response.
*/
gettext("rm: examine files in directory %s (%s/%s)? "),
return (0);
}
#endif
if (interactive) {
/*
* Print an error message that
* we could not read the directory
* as the user wanted to examine
* files in the directory. Only
* affect the error status if
* user doesn't want to remove the
* directory as we still may be able
* remove the directory successfully.
*/
"rm: cannot read directory %s: %s\n"),
/*
* TRANSLATION_NOTE - The following message will contain the
* first character of the strings for "yes" and "no" defined
* in the file "nl_langinfo.po". After substitution, the
* message will appear as follows:
* rm: remove <filename> (y/n)?
* For example, in German, this will appear as
* rm: l�schen <filename> (j/n)?
* where j=ja, n=nein, <filename>=the file to be removed
*/
gettext("rm: remove %s (%s/%s)? "),
errcnt++;
return (0);
}
}
/* If it's empty we may still be able to rm it */
return (0);
if (interactive)
gettext("rm: Unable to remove directory %s: %s\n") :
gettext("rm: cannot read directory %s: %s\n"),
errcnt++;
return (0);
}
/*
* There is a race condition here too; if we open a directory
* we have to make sure it's still the same directory we
* stat'ed and checked against root earlier. Let's check.
*/
closeframe(&frame);
errcnt++;
return (0);
}
closeframe(&frame);
goto unlinkit;
}
}
/*
* rm() only returns -1 if popdir failed at some point;
* frame.dp is no longer reliable and we must drop out.
*/
continue;
break;
}
return (-1);
/*
* We recursed and the subdirectory may have set the CANTCLOSE
* flag; we need to clear it except for &top.
* Recursion may have invalidated entry because of closedir().
*/
}
} else {
flag = 0;
}
/*
* If interactive, ask for acknowledgement.
*/
if (interactive) {
return (0);
}
/*
* If not silent, and stdin is a terminal, and there's
* no write access, and the file isn't a symbolic link,
* ask for permission. If flag is set, then we know it's
* a directory so we skip this test as it was done above.
*
* TRANSLATION_NOTE - The following message will contain the
* first character of the strings for "yes" and "no" defined
* in the file "nl_langinfo.po". After substitution, the
* message will appear as follows:
* rm: <filename>: override protection XXX (y/n)?
* where XXX is the permission mode bits of the file in octal
* and <filename> is the file to be removed
*
*/
gettext("rm: %s: override protection %o (%s/%s)? "),
return (0);
}
}
return (0);
if (flag != 0) {
"rm: Cannot remove any directory in the "
"path of the current working directory\n"
"%s\n"), pathbuf);
} else {
gettext("rm: Unable to remove directory %s:"
}
} else {
#ifndef XPG4
if (!silent || interactive) {
#endif
gettext("rm: %s not removed: %s\n"),
#ifndef XPG4
}
#endif
}
errcnt++;
}
return (0);
}
static int
{
return (yes());
}
static void
memerror(void)
{
exit(1);
}
/*
* If we can't stat "..", it's either not there or we can't search
* the current directory; in that case we can't return back through
* "..", so we need to keep the parent open.
* Check that we came from "..", if not then this directory entry is an
* additional link and there is risk of a filesystem cycle and we also
* can't go back up through ".." and we keep the directory open.
*/
static int
{
return (0);
return (0);
}
/* Directory hard link, check cycle */
errcnt++;
return (-1);
}
}
return (0);
}