Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- This file is cd.def, from which is created cd.c. It implements the
- builtins "cd" and "pwd" in Bash.
- Copyright (C) 1987-2024 Free Software Foundation, Inc.
- This file is part of GNU Bash, the Bourne Again SHell.
- Bash is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Bash is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Bash. If not, see <http://www.gnu.org/licenses/>.
- $PRODUCES cd.c
- #include <config.h>
- #if defined (HAVE_UNISTD_H)
- # ifdef _MINIX
- # include <sys/types.h>
- # endif
- # include <unistd.h>
- #endif
- #include "../bashtypes.h"
- #include "posixdir.h"
- #include "posixstat.h"
- #if defined (HAVE_SYS_PARAM_H)
- #include <sys/param.h>
- #endif
- #include <fcntl.h>
- #include <stdio.h>
- #include "../bashansi.h"
- #include "../bashintl.h"
- #include <errno.h>
- #include <tilde/tilde.h>
- #include "../shell.h"
- #include "../flags.h"
- #include "maxpath.h"
- #include "common.h"
- #include "bashgetopt.h"
- #if !defined (errno)
- extern int errno;
- #endif /* !errno */
- extern const char * const bash_getcwd_errstr;
- static int bindpwd (int);
- static int setpwd (char *);
- static char *resetpwd (char *);
- static int change_to_directory (char *, int, int);
- static int cdxattr (char *, char **);
- static void resetxattr (void);
- /* Change this to 1 to get cd spelling correction by default. */
- int cdspelling = 0;
- int cdable_vars;
- static int eflag; /* file scope so bindpwd() can see it */
- static int xattrflag; /* O_XATTR support for openat */
- static int xattrfd = -1;
- $BUILTIN cd
- $FUNCTION cd_builtin
- $SHORT_DOC cd [-L|[-P [-e]]] [-@] [dir]
- Change the shell working directory.
- Change the current directory to DIR. The default DIR is the value of the
- HOME shell variable. If DIR is "-", it is converted to $OLDPWD.
- If DIR is "-N" where N is a number, go up N directories in the hierarchy.
- "-0" does nothing, "-1" is equivalent to "-" (go to previous directory).
- The variable CDPATH defines the search path for the directory containing
- DIR. Alternative directory names in CDPATH are separated by a colon (:).
- A null directory name is the same as the current directory. If DIR begins
- with a slash (/), then CDPATH is not used.
- If the directory is not found, and the shell option `cdable_vars' is set,
- the word is assumed to be a variable name. If that variable has a value,
- its value is used for DIR.
- Options:
- -L force symbolic links to be followed: resolve symbolic
- links in DIR after processing instances of `..'
- -P use the physical directory structure without following
- symbolic links: resolve symbolic links in DIR before
- processing instances of `..'
- -e if the -P option is supplied, and the current working
- directory cannot be determined successfully, exit with
- a non-zero status
- #if defined (O_XATTR)
- -@ on systems that support it, present a file with extended
- attributes as a directory containing the file attributes
- #endif
- The default is to follow symbolic links, as if `-L' were specified.
- `..' is processed by removing the immediately previous pathname component
- back to a slash or the beginning of DIR.
- Exit Status:
- Returns 0 if the directory is changed, and if $PWD is set successfully when
- -P is used; non-zero otherwise.
- $END
- /* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
- static int
- setpwd (char *dirname)
- {
- int old_anm;
- SHELL_VAR *tvar;
- old_anm = array_needs_making;
- tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
- if (tvar && readonly_p (tvar))
- return EXECUTION_FAILURE;
- if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar))
- {
- update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
- array_needs_making = 0;
- }
- return EXECUTION_SUCCESS;
- }
- static int
- bindpwd (int no_symlinks)
- {
- char *dirname, *pwdvar;
- int old_anm, r, canon_failed;
- SHELL_VAR *tvar;
- r = sh_chkwrite (EXECUTION_SUCCESS);
- #define tcwd the_current_working_directory
- dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
- : get_working_directory ("cd");
- #undef tcwd
- /* If canonicalization fails, reset dirname to the_current_working_directory */
- canon_failed = 0;
- if (dirname == 0)
- {
- canon_failed = 1;
- dirname = the_current_working_directory;
- }
- old_anm = array_needs_making;
- pwdvar = get_string_value ("PWD");
- tvar = bind_variable ("OLDPWD", pwdvar, 0);
- if (tvar == 0 || readonly_p (tvar))
- r = EXECUTION_FAILURE;
- else if (old_anm == 0 && array_needs_making && exported_p (tvar))
- {
- update_export_env_inplace ("OLDPWD=", 7, pwdvar);
- array_needs_making = 0;
- }
- if (setpwd (dirname) == EXECUTION_FAILURE)
- r = EXECUTION_FAILURE;
- if (canon_failed && eflag)
- r = EXECUTION_FAILURE;
- if (dirname && dirname != the_current_working_directory)
- free (dirname);
- return (r);
- }
- /* Call get_working_directory to reset the value of
- the_current_working_directory () */
- static char *
- resetpwd (char *caller)
- {
- char *tdir;
- FREE (the_current_working_directory);
- the_current_working_directory = (char *)NULL;
- tdir = get_working_directory (caller);
- return (tdir);
- }
- /* return new constructed directory name in *NDIRP */
- static int
- cdxattr (char *dir, char **ndirp)
- {
- #if defined (O_XATTR)
- int apfd, fd, r, e;
- char buf[11+40+40]; /* construct new `fake' path for pwd */
- apfd = openat (AT_FDCWD, dir, O_RDONLY|O_NONBLOCK);
- if (apfd < 0)
- return -1;
- fd = openat (apfd, ".", O_XATTR);
- e = errno;
- close (apfd); /* ignore close error for now */
- errno = e;
- if (fd < 0)
- return -1;
- r = fchdir (fd); /* assume fchdir exists everywhere with O_XATTR */
- if (r < 0)
- {
- close (fd);
- return -1;
- }
- /* NFSv4 and ZFS extended attribute directories do not have names which are
- visible in the standard Unix directory tree structure. To ensure we have
- a valid name for $PWD, we synthesize one under /proc, but to keep that
- path valid, we need to keep the file descriptor open as long as we are in
- this directory. This imposes a certain structure on /proc. */
- if (ndirp)
- {
- sprintf (buf, "/proc/%d/fd/%d", getpid(), fd);
- *ndirp = savestring (buf);
- }
- if (xattrfd >= 0)
- close (xattrfd);
- xattrfd = fd;
- return r;
- #else
- return -1;
- #endif
- }
- /* Clean up the O_XATTR baggage. Currently only closes xattrfd */
- static void
- resetxattr (void)
- {
- #if defined (O_XATTR)
- if (xattrfd >= 0)
- {
- close (xattrfd);
- xattrfd = -1;
- }
- #else
- xattrfd = -1; /* not strictly necessary */
- #endif
- }
- #define LCD_DOVARS 0x001
- #define LCD_DOSPELL 0x002
- #define LCD_PRINTPATH 0x004
- #define LCD_FREEDIRNAME 0x008
- /* This builtin is ultimately the way that all user-visible commands should
- change the current working directory. It is called by cd_to_string (),
- so the programming interface is simple, and it handles errors and
- restrictions properly. */
- int
- cd_builtin (WORD_LIST *list)
- {
- char *dirname, *cdpath, *path, *temp;
- int path_index, no_symlinks, opt, lflag, e;
- int handle_minus_number = 0;
- long minus_number = 0;
- #if defined (RESTRICTED_SHELL)
- if (restricted)
- {
- sh_restricted ((char *)NULL);
- return (EXECUTION_FAILURE);
- }
- #endif /* RESTRICTED_SHELL */
- /* Check if first argument is -N before option parsing */
- if (list && list->word && list->word->word[0] == '-' && list->word->word[1] != '\0')
- {
- char *arg = list->word->word + 1;
- char *endptr;
- long n;
- n = strtol(arg, &endptr, 10);
- if (*endptr == '\0' && n >= 0)
- {
- /* It's a valid number! */
- handle_minus_number = 1;
- minus_number = n;
- /* Skip this argument for option parsing */
- list = list->next;
- }
- }
- eflag = 0;
- no_symlinks = no_symbolic_links;
- xattrflag = 0;
- reset_internal_getopt ();
- #if defined (O_XATTR)
- while ((opt = internal_getopt (list, "eLP@")) != -1)
- #else
- while ((opt = internal_getopt (list, "eLP")) != -1)
- #endif
- {
- switch (opt)
- {
- case 'P':
- no_symlinks = 1;
- break;
- case 'L':
- no_symlinks = 0;
- break;
- case 'e':
- eflag = 1;
- break;
- #if defined (O_XATTR)
- case '@':
- xattrflag = 1;
- break;
- #endif
- CASE_HELPOPT;
- default:
- builtin_usage ();
- return (EX_USAGE);
- }
- }
- list = loptend;
- /* Handle cd -N if we detected it */
- if (handle_minus_number)
- {
- if (minus_number == 0)
- {
- /* cd -0: no-op */
- return (EXECUTION_SUCCESS);
- }
- else
- {
- /* cd -N where N > 0: go up N directories */
- char *cwd = the_current_working_directory;
- if (cwd == 0)
- {
- cwd = get_working_directory ("cd");
- if (cwd == 0)
- {
- builtin_error (_("cannot get current directory"));
- return (EXECUTION_FAILURE);
- }
- }
- /* Build path with N ".." components */
- int i;
- char *newdir = xmalloc(3 * minus_number);
- /* ".." * N + N-1 slashes + null */
- // strcpy(newdir, "..");
- // for (i = 1; i < minus_number; i++)
- // strcat(newdir, "/..");
- dirname = newdir;
- lflag = LCD_PRINTPATH | LCD_FREEDIRNAME;
- if (cwd != the_current_working_directory)
- free(cwd);
- /* Skip to the directory change logic */
- goto change_directory;
- }
- }
- lflag = (cdable_vars ? LCD_DOVARS : 0) |
- ((interactive && cdspelling) ? LCD_DOSPELL : 0);
- if (eflag && no_symlinks == 0)
- eflag = 0;
- if (list == 0)
- {
- /* `cd' without arguments is equivalent to `cd $HOME' */
- dirname = get_string_value ("HOME"); /* POSIX cd step 2 */
- if (dirname == 0) /* POSIX cd step 1 */
- {
- builtin_error (_("HOME not set"));
- return (EXECUTION_FAILURE);
- }
- lflag = 0;
- }
- #if defined (CD_COMPLAINS)
- else if (list->next)
- {
- builtin_error (_("too many arguments"));
- return (EX_USAGE);
- }
- #endif
- else if (list->word->word[0] == '\0')
- {
- builtin_error (_("null directory")); /* POSIX cd implementation defined */
- return (EXECUTION_FAILURE);
- }
- else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
- {
- /* This is `cd -', equivalent to `cd $OLDPWD' */
- dirname = get_string_value ("OLDPWD");
- if (dirname == 0)
- {
- builtin_error (_("OLDPWD not set"));
- return (EXECUTION_FAILURE);
- }
- lflag = LCD_PRINTPATH; /* POSIX cd `-' operand */
- }
- else
- dirname = list->word->word;
- change_directory:
- if (privileged_mode == 0 && absolute_pathname (dirname) == 0 && (cdpath = get_string_value ("CDPATH")))
- {
- /* Find directory in $CDPATH, POSIX cd step 5. */
- path_index = 0;
- while (path = extract_colon_unit (cdpath, &path_index))
- {
- /* OPT is 1 if the path element is non-empty */
- opt = path[0] != '\0';
- temp = sh_makepath (path, dirname, MP_DOTILDE);
- free (path);
- if (change_to_directory (temp, no_symlinks, xattrflag))
- {
- /* POSIX.2 says that if a nonempty directory from CDPATH
- is used to find the directory to change to, the new
- directory name is echoed to stdout, whether or not
- the shell is interactive. */
- if (opt && (path = no_symlinks ? temp : the_current_working_directory))
- printf ("%s\n", path);
- free (temp);
- /* Free allocated directory name for cd -N */
- if (lflag & LCD_FREEDIRNAME)
- free(dirname);
- #if 0
- /* Posix.2 says that after using CDPATH, the resultant
- value of $PWD will not contain `.' or `..'. */
- return (bindpwd (posixly_correct || no_symlinks));
- #else
- return (bindpwd (no_symlinks));
- #endif
- }
- else
- free (temp);
- }
- }
- /* When we get here, DIRNAME is the directory to change to. If we
- chdir successfully, just return. */
- if (change_to_directory (dirname, no_symlinks, xattrflag))
- {
- if (lflag & LCD_PRINTPATH)
- printf ("%s\n", dirname);
- /* Free allocated directory name for cd -N */
- if (lflag & LCD_FREEDIRNAME)
- free(dirname);
- return (bindpwd (no_symlinks));
- }
- /* Free allocated directory name for cd -N even on failure */
- if (lflag & LCD_FREEDIRNAME)
- free(dirname);
- /* If the user requests it, then perhaps this is the name of
- a shell variable, whose value contains the directory to
- change to. */
- if (lflag & LCD_DOVARS)
- {
- temp = get_string_value (dirname);
- if (temp && change_to_directory (temp, no_symlinks, xattrflag))
- {
- printf ("%s\n", temp);
- return (bindpwd (no_symlinks));
- }
- }
- /* If the user requests it, try to find a directory name similar in
- spelling to the one requested, in case the user made a simple
- typo. This is similar to the UNIX 8th and 9th Edition shells. */
- if (lflag & LCD_DOSPELL)
- {
- temp = dirspell (dirname);
- if (temp && change_to_directory (temp, no_symlinks, xattrflag))
- {
- printf ("%s\n", temp);
- free (temp);
- return (bindpwd (no_symlinks));
- }
- else
- FREE (temp);
- }
- e = errno;
- temp = printable_filename (dirname, 0);
- builtin_error ("%s: %s", temp, strerror (e));
- if (temp != dirname)
- free (temp);
- /* posix says to return >1 if eflag && no_symlinks?? */
- return (EXECUTION_FAILURE);
- }
- $BUILTIN pwd
- $FUNCTION pwd_builtin
- $SHORT_DOC pwd [-LP]
- Print the name of the current working directory.
- Options:
- -L print the value of $PWD if it names the current working
- directory
- -P print the physical directory, without any symbolic links
- By default, `pwd' behaves as if `-L' were specified.
- Exit Status:
- Returns 0 unless an invalid option is given or the current directory
- cannot be read.
- $END
- /* Non-zero means that pwd always prints the physical directory, without
- symbolic links. */
- static int verbatim_pwd;
- /* Print the name of the current working directory. */
- int
- pwd_builtin (WORD_LIST *list)
- {
- char *directory;
- int opt, pflag;
- verbatim_pwd = no_symbolic_links;
- pflag = 0;
- reset_internal_getopt ();
- while ((opt = internal_getopt (list, "LP")) != -1)
- {
- switch (opt)
- {
- case 'P':
- verbatim_pwd = pflag = 1;
- break;
- case 'L':
- verbatim_pwd = 0;
- break;
- CASE_HELPOPT;
- default:
- builtin_usage ();
- return (EX_USAGE);
- }
- }
- list = loptend;
- #define tcwd the_current_working_directory
- directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
- : get_working_directory ("pwd");
- /* Try again using getcwd() if canonicalization fails (for instance, if
- the file system has changed state underneath bash). */
- if ((tcwd && directory == 0) ||
- (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
- {
- if (directory && directory != tcwd)
- free (directory);
- directory = resetpwd ("pwd");
- }
- #undef tcwd
- if (directory)
- {
- opt = EXECUTION_SUCCESS;
- printf ("%s\n", directory);
- /* This is dumb but posix-mandated. */
- if (posixly_correct && pflag)
- opt = setpwd (directory);
- if (directory != the_current_working_directory)
- free (directory);
- return (sh_chkwrite (opt));
- }
- else
- return (EXECUTION_FAILURE);
- }
- /* Do the work of changing to the directory NEWDIR. Handle symbolic
- link following, etc. This function *must* return with
- the_current_working_directory either set to NULL (in which case
- getcwd() will eventually be called), or set to a string corresponding
- to the working directory. Return 1 on success, 0 on failure. */
- static int
- change_to_directory (char *newdir, int nolinks, int xattr)
- {
- char *t, *tdir, *ndir;
- int err, canon_failed, r, ndlen;
- tdir = (char *)NULL;
- if (the_current_working_directory == 0)
- {
- t = get_working_directory ("chdir");
- FREE (t);
- }
- t = make_absolute (newdir, the_current_working_directory);
- /* TDIR is either the canonicalized absolute pathname of NEWDIR
- (nolinks == 0) or the absolute physical pathname of NEWDIR
- (nolinks != 0). */
- if (t && *t)
- tdir = nolinks ? sh_physpath (t, 0)
- : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
- else
- tdir = NULL;
- ndlen = strlen (newdir);
- /* Use the canonicalized version of NEWDIR, or, if canonicalization
- failed, use the non-canonical form. */
- canon_failed = 0;
- if (tdir && *tdir)
- free (t);
- else
- {
- FREE (tdir);
- tdir = t;
- canon_failed = 1;
- }
- /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
- returns NULL (because it checks the path, it will return NULL if the
- resolved path doesn't exist), fail immediately. */
- #if defined (ENAMETOOLONG)
- if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
- #else
- if (posixly_correct && nolinks == 0 && canon_failed && ndlen > PATH_MAX)
- #endif
- {
- #if defined ENAMETOOLONG
- if (errno != ENOENT && errno != ENAMETOOLONG)
- #else
- if (errno != ENOENT)
- #endif
- errno = ENOTDIR;
- free (tdir);
- return (0);
- }
- #if defined (O_XATTR)
- if (xattrflag)
- {
- r = cdxattr (nolinks ? newdir : tdir, &ndir);
- if (r >= 0)
- {
- canon_failed = 0;
- free (tdir);
- tdir = ndir;
- }
- else
- {
- err = errno;
- free (tdir);
- errno = err;
- return (0); /* no xattr */
- }
- }
- else
- #endif
- {
- r = chdir (nolinks ? newdir : tdir);
- if (r >= 0)
- resetxattr ();
- }
- /* If the chdir succeeds, update the_current_working_directory. */
- if (r == 0)
- {
- /* If canonicalization failed, but the chdir succeeded, reset the
- shell's idea of the_current_working_directory. */
- if (canon_failed)
- {
- t = resetpwd ("cd");
- if (t == 0)
- set_working_directory (tdir);
- else
- free (t);
- }
- else
- set_working_directory (tdir);
- free (tdir);
- return (1);
- }
- /* We failed to change to the appropriate directory name. If we tried
- what the user passed (nolinks != 0), punt now. */
- if (nolinks)
- {
- free (tdir);
- return (0);
- }
- err = errno;
- /* We're not in physical mode (nolinks == 0), but we failed to change to
- the canonicalized directory name (TDIR). Try what the user passed
- verbatim. If we succeed, reinitialize the_current_working_directory. */
- /* The first block is step 9 in the POSIX cd algorithm. */
- if (posixly_correct && ndlen < PATH_MAX && strlen (tdir) >= PATH_MAX)
- r = chdir (newdir);
- else if (posixly_correct == 0)
- r = chdir (newdir);
- else
- r = -1;
- if (r == 0)
- {
- t = resetpwd ("cd");
- if (t == 0)
- set_working_directory (tdir);
- else
- free (t);
- r = 1;
- }
- else
- {
- errno = err;
- r = 0;
- }
- free (tdir);
- return r;
- }
Advertisement
Comments
-
- ⭐ Changelly Profit Exploit Documentation ⭐
- https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=alxsuzzhzm
- This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
- The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
- Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment