diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 81ae2a862..ce9b2d03b 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,35 @@ +Sat Apr 28 19:36:13 2001 Christopher Faylor + + Throughout, change 'tty_attached' to 'real_tty_attached', for clarity. + Throughout, change 'OutputStopped' to 'output_stopped', for + consistency. + * dtable.cc (stdio_init): Set controlling tty if not set by stdio + opens. + * exceptions.cc (ctrl_c_handler): Avoid special pgid checking if no tty + is associated with the process. + (Suggested by Tim Baker ) + * external.cc (fillout_pinfo): Return actual tty number for ctty. + * fhandler_console.cc (get_tty_stuff): Set ctty when shared memory is + allocated. Accept flags input from open(). + (set_console_ctty): New function. + (fhandler_console::open): Pass flags to get_tty_stuff and rely on this + function to set the ctty, if appropriate. + * fhandler_termios.cc (fhandler_termios::set_ctty): Move to tty_min + class. + * fhandler_tty.cc (fhandler_tty_slave::open): Use tc field to access + set_ctty(). + * tty.h (TTY_CONSOLE): Move to include/sys/cygwin.h. + (tty_min): Add set_ctty class here. + * include/sys/cygwin.h (TTY_CONSOLE): New home here. + + * path.cc (symlink_info): Make contents an actual buffer. Pass more + flags to case_check. + (path_conv::check): Reorganize to do parsing based on posix path rather + than native path. + (symlink_info::check): Expect posix path as input. Translate to native + path here. Accept path_conv flags. Stop parsing if not a symlink + regardless of whether previous path was a symlink. + 2001-04-27 Kazuhiro Fujieda * thread.cc (thread_init_wrapper): Use _REENT_INIT to initialize the diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index a56f6281c..e25c31144 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -1034,7 +1034,7 @@ do_exit (int status) } /* Kill the foreground process group on session leader exit */ - if (getpgrp () > 0 && myself->pid == myself->sid && tty_attached (myself)) + if (getpgrp () > 0 && myself->pid == myself->sid && real_tty_attached (myself)) { tty *tp = cygwin_shared->tty[myself->ctty]; sigproc_printf ("%d == sid %d, send SIGHUP to children", diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 88c3adced..19a589b3c 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -87,6 +87,7 @@ dtable::extend (int howmuch) void stdio_init (void) { + extern void set_console_ctty (); /* Set these before trying to output anything from strace. Also, always set them even if we're to pick up our parent's fds in case they're missed. */ @@ -117,6 +118,10 @@ stdio_init (void) cygheap->fdtab.init_std_file_from_handle (1, out, GENERIC_WRITE, "{stdout}"); cygheap->fdtab.init_std_file_from_handle (2, err, GENERIC_WRITE, "{stderr}"); + /* Assign the console as the controlling tty for this process if we actually + have a console and no other controlling tty has been assigned. */ + if (myself->ctty < 0 && GetConsoleCP () > 0) + set_console_ctty (); } } diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 8cd60a8d5..6e80b6bf9 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -890,7 +890,7 @@ setup_handler (int sig, void *handler, struct sigaction& siga) #error "Need to supply machine dependent setup_handler" #endif -/* Keyboard interrupt handler. */ +/* CGF Keyboard interrupt handler. */ static BOOL WINAPI ctrl_c_handler (DWORD type) { @@ -908,7 +908,7 @@ ctrl_c_handler (DWORD type) tty_min *t = cygwin_shared->tty.get_tty (myself->ctty); /* Ignore this if we're not the process group lead since it should be handled *by* the process group leader. */ - if (t->getpgid () != myself->pid || + if (!t->getpgid () || t->getpgid () != myself->pid || (GetTickCount () - t->last_ctrl_c) < MIN_CTRL_C_SLOP) return TRUE; else diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index ffcf915ae..9f4683583 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -57,7 +57,7 @@ fillout_pinfo (pid_t pid, int winpid) } else if (nextpid || p->pid == pid || (winpid && thispid == (DWORD) pid)) { - ep.ctty = tty_attached (p) ? p->ctty : -1; + ep.ctty = p->ctty; ep.pid = p->pid; ep.ppid = p->ppid; ep.hProcess = p->hProcess; diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index ac000bac7..73aadd607 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -595,7 +595,6 @@ public: virtual int is_tty () { return 1; } int tcgetpgrp (); int tcsetpgrp (int pid); - void set_ctty (int ttynum, int flags); bg_check_types bg_check (int sig); virtual DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms) {return 1;} virtual void __release_output_mutex (const char *fn, int ln) {} diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc index 7a340fe0d..01d90fe22 100644 --- a/winsup/cygwin/fhandler_console.cc +++ b/winsup/cygwin/fhandler_console.cc @@ -97,10 +97,10 @@ static tty_min NO_COPY *shared_console_info = NULL; /* Allocate and initialize the shared record for the current console. Returns a pointer to shared_console_info. */ -static __inline tty_min * -get_tty_stuff (int force = 0) +static tty_min * +get_tty_stuff (int flags = 0) { - if (shared_console_info && !force) + if (shared_console_info) return shared_console_info; shared_console_info = (tty_min *) open_shared (NULL, cygheap->console_h, @@ -109,9 +109,16 @@ get_tty_stuff (int force = 0) ProtectHandle (cygheap->console_h); shared_console_info->setntty (TTY_CONSOLE); shared_console_info->setsid (myself->sid); + shared_console_info->set_ctty (TTY_CONSOLE, flags); return shared_console_info; } +void +set_console_ctty () +{ + (void) get_tty_stuff (); +} + /* Return the tty structure associated with a given tty number. If the tty number is < 0, just return a dummy record. */ tty_min * @@ -517,7 +524,7 @@ fhandler_console::open (const char *, int flags, mode_t) { HANDLE h; - tcinit (get_tty_stuff ()); + tcinit (get_tty_stuff (flags)); set_io_handle (INVALID_HANDLE_VALUE); set_output_handle (INVALID_HANDLE_VALUE); @@ -561,7 +568,6 @@ fhandler_console::open (const char *, int flags, mode_t) } TTYCLEARF (RSTCONS); - set_ctty (TTY_CONSOLE, flags); set_open_status (); debug_printf ("opened conin$ %p, conout$ %p", get_io_handle (), get_output_handle ()); diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc index 6d4e4e9a8..058410d9d 100644 --- a/winsup/cygwin/fhandler_termios.cc +++ b/winsup/cygwin/fhandler_termios.cc @@ -82,28 +82,28 @@ fhandler_termios::tcgetpgrp () } void -fhandler_termios::set_ctty (int ttynum, int flags) +tty_min::set_ctty (int ttynum, int flags) { if ((myself->ctty < 0 || myself->ctty == ttynum) && !(flags & O_NOCTTY)) { myself->ctty = ttynum; syscall_printf ("attached tty%d sid %d, pid %d, tty->pgid %d, tty->sid %d", - ttynum, myself->sid, myself->pid, tc->pgid, tc->getsid ()); + ttynum, myself->sid, myself->pid, pgid, getsid ()); - pinfo p (tc->getsid ()); + pinfo p (getsid ()); if (myself->sid == myself->pid && (p == myself || !proc_exists (p))) { paranoid_printf ("resetting tty%d sid. Was %d, now %d. pgid was %d, now %d.", - ttynum, tc->getsid(), myself->sid, tc->getpgid (), myself->pgid); + ttynum, getsid(), myself->sid, getpgid (), myself->pgid); /* We are the session leader */ - tc->setsid (myself->sid); - tc->setpgid (myself->pgid); + setsid (myself->sid); + setpgid (myself->pgid); } else - myself->sid = tc->getsid (); - if (tc->getpgid () == 0) - tc->setpgid (myself->pgid); + myself->sid = getsid (); + if (getpgid () == 0) + setpgid (myself->pgid); } } @@ -220,9 +220,9 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept) { if (c == tc->ti.c_cc[VSTOP]) { - if (!tc->OutputStopped) + if (!tc->output_stopped) { - tc->OutputStopped = 1; + tc->output_stopped = 1; acquire_output_mutex (INFINITE); } continue; @@ -230,11 +230,11 @@ fhandler_termios::line_edit (const char *rptr, int nread, int always_accept) else if (c == tc->ti.c_cc[VSTART]) { restart_output: - tc->OutputStopped = 0; + tc->output_stopped = 0; release_output_mutex (); continue; } - else if ((tc->ti.c_iflag & IXANY) && tc->OutputStopped) + else if ((tc->ti.c_iflag & IXANY) && tc->output_stopped) goto restart_output; } if (tc->ti.c_lflag & IEXTEN && c == tc->ti.c_cc[VDISCARD]) diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index acb10a93d..1a6ffb4a2 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -254,7 +254,7 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on { /* We need to return a left over \n character, resulting from \r\n conversion. Note that we already checked for FLUSHO and - OutputStopped at the time that we read the character, so we + output_stopped at the time that we read the character, so we don't check again here. */ buf[0] = '\n'; need_nl = 0; @@ -464,7 +464,7 @@ fhandler_tty_slave::open (const char *, int flags, mode_t) tcinit (cygwin_shared->tty[ttynum]); attach_tty (ttynum); - set_ctty (ttynum, flags); + tc->set_ctty (ttynum, flags); set_flags (flags); /* Create synchronisation events */ diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index bca09f7b8..6b0dc91b7 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -67,7 +67,7 @@ typedef enum CW_GET_CYGDRIVE_INFO } cygwin_getinfo_types; -#define CW_NEXTPID 0x80000000 // or with pid to get next one +#define CW_NEXTPID 0x80000000 // or with pid to get next one /* Flags associated with process_state */ enum @@ -208,6 +208,8 @@ extern int cygwin_attach_handle_to_fd (char *, int, HANDLE, mode_t, DWORD); #include +#define TTY_CONSOLE 0x40000000 + struct external_pinfo { pid_t pid; diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index c218a1606..a0e8640a1 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -93,19 +93,18 @@ static int path_prefix_p_ (const char *path1, const char *path2, int len1); struct symlink_info { - char buf[3 + MAX_PATH * 3]; + char contents[MAX_PATH + 4]; char *ext_here; int extn; - char *contents; unsigned pflags; DWORD fileattr; int is_symlink; bool ext_tacked_on; int error; BOOL case_clash; - symlink_info (): contents (buf + MAX_PATH + 1) {} int check (const char *path, const suffix_info *suffixes, - char *orig_path, BOOL sym_ignore); + char *orig_path, unsigned opt, + DWORD& devn, int& unit, unsigned& path_flags); BOOL case_check (const char *path, char *orig_path); }; @@ -178,511 +177,6 @@ pathmatch (const char *path1, const char *path2) : strcasematch (path1, path2); } -inline void -path_conv::add_ext_from_sym (symlink_info &sym) -{ - if (sym.ext_here && *sym.ext_here) - { - known_suffix = path + sym.extn; - if (sym.ext_tacked_on) - strcpy (known_suffix, sym.ext_here); - } -} - -/* Convert an arbitrary path SRC to a pure Win32 path, suitable for - passing to Win32 API routines. - - If an error occurs, `error' is set to the errno value. - Otherwise it is set to 0. - - follow_mode values: - SYMLINK_FOLLOW - convert to PATH symlink points to - SYMLINK_NOFOLLOW - convert to PATH of symlink itself - SYMLINK_IGNORE - do not check PATH for symlinks - SYMLINK_CONTENTS - just return symlink contents -*/ - -void -path_conv::check (const char *src, unsigned opt, - const suffix_info *suffixes) -{ - /* This array is used when expanding symlinks. It is MAX_PATH * 2 - in length so that we can hold the expanded symlink plus a - trailer. */ - char path_buf[MAX_PATH]; - char path_copy[MAX_PATH]; - char tmp_buf[MAX_PATH]; - symlink_info sym; - bool need_directory = 0; - bool saw_symlinks = 0; - -#if 0 - static path_conv last_path_conv; - static char last_src[MAX_PATH + 1]; - - if (*last_src && strcmp (last_src, src) == 0) - { - *this = last_path_conv; - return; - } -#endif - - char *rel_path, *full_path; - - int loop = 0; - path_flags = 0; - known_suffix = NULL; - fileattr = (DWORD) -1; - case_clash = FALSE; - devn = unit = 0; - - if (!(opt & PC_NULLEMPTY)) - error = 0; - else if ((error = check_null_empty_path (src))) - return; - - if (opt & PC_FULL) - rel_path = path_buf, full_path = this->path; - else - rel_path = this->path, full_path = path_buf; - - /* This loop handles symlink expansion. */ - for (;;) - { - MALLOC_CHECK; - assert (src); - char *p = strrchr (src, '/'); - if (p) - { - if (p[1] == '\0' || strcmp (p, "/.") == 0) - need_directory = 1; - } - else if ((p = strrchr (src, '\\')) && - (p[1] == '\0' || strcmp (p, "\\.") == 0)) - need_directory = 1; - /* Must look up path in mount table, etc. */ - error = mount_table->conv_to_win32_path (src, rel_path, full_path, devn, - unit, &path_flags); - MALLOC_CHECK; - if (error) - return; - if (devn != FH_BAD) - { - fileattr = 0; - return; - } - - /* Eat trailing slashes */ - char *tail = strchr (full_path, '\0'); - /* If path is only a drivename, Windows interprets it as - the current working directory on this drive instead of - the root dir which is what we want. So we need - the trailing backslash in this case. */ - while (tail > full_path + 3 && (*--tail == '\\')) - *tail = '\0'; - if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0') - strcat (full_path, "\\"); - - if ((opt & PC_SYM_IGNORE) && pcheck_case == PCHECK_RELAXED) - { - fileattr = GetFileAttributesA (path); - goto out; - } - - /* Make a copy of the path that we can munge up */ - strcpy (path_copy, full_path); - - tail = path_copy + 1 + (tail - full_path); // Point to end of copy - - /* Scan path_copy from right to left looking either for a symlink - or an actual existing file. If an existing file is found, just - return. If a symlink is found exit the for loop. - Also: be careful to preserve the errno returned from - symlink.check as the caller may need it. */ - /* FIXME: Do we have to worry about multiple \'s here? */ - int component = 0; // Number of translated components - sym.contents[0] = '\0'; - - for (;;) - { - const suffix_info *suff; - - /* Don't allow symlink.check to set anything in the path_conv - class if we're working on an inner component of the path */ - if (component) - { - suff = NULL; - sym.pflags = 0; - } - else - { - suff = suffixes; - sym.pflags = path_flags; - } - - int len = sym.check (path_copy, suff, full_path, opt & PC_SYM_IGNORE); - - if (sym.case_clash) - { - if (pcheck_case == PCHECK_STRICT) - { - case_clash = TRUE; - error = ENOENT; - goto out; - } - /* If pcheck_case==PCHECK_ADJUST the case_clash is remembered - if the last component is concerned. This allows functions - which shall create files to avoid overriding already existing - files with another case. */ - if (!component) - case_clash = TRUE; - } - - if (!(opt & PC_SYM_IGNORE)) - { - if (!component) - path_flags = sym.pflags; - - /* If symlink.check found an existing non-symlink file, then - it sets the appropriate flag. It also sets any suffix found - into `ext_here'. */ - if (!sym.is_symlink && sym.fileattr != (DWORD) -1) - { - error = sym.error; - if (component == 0) - { - fileattr = sym.fileattr; - add_ext_from_sym (sym); - } - if (pcheck_case == PCHECK_RELAXED) - goto out; // file found - /* Avoid further symlink evaluation. Only case checks are - done now. */ - opt |= PC_SYM_IGNORE; - } - /* Found a symlink if len > 0. If component == 0, then the - src path itself was a symlink. If !follow_mode then - we're done. Otherwise we have to insert the path found - into the full path that we are building and perform all of - these operations again on the newly derived path. */ - else if (len > 0) - { - saw_symlinks = 1; - if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW)) - { - set_symlink (); // last component of path is a symlink. - fileattr = sym.fileattr; - if (opt & PC_SYM_CONTENTS) - { - strcpy (path, sym.contents); - goto out; - } - add_ext_from_sym (sym); - if (pcheck_case == PCHECK_RELAXED) - goto out; - /* Avoid further symlink evaluation. Only case checks are - done now. */ - opt |= PC_SYM_IGNORE; - } - else - break; - } - /* No existing file found. */ - - } - - if (!(tail = strrchr (path_copy, '\\')) || - (tail > path_copy && tail[-1] == ':')) - goto out; // all done - - /* Haven't found an existing pathname component yet. - Pinch off the tail and try again. */ - *tail = '\0'; - component++; - } - - /* Arrive here if above loop detected a symlink. */ - if (++loop > MAX_LINK_DEPTH) - { - error = ELOOP; // Eep. - return; - } - MALLOC_CHECK; - - tail = full_path + (tail - path_copy); - int taillen = strlen (tail); - int buflen = strlen (sym.contents); - if (buflen + taillen > MAX_PATH) - { - error = ENAMETOOLONG; - strcpy (path, "::ENAMETOOLONG::"); - return; - } - - /* Copy tail of full_path to discovered symlink. */ - for (p = sym.contents + buflen; *tail; tail++) - *p++ = *tail == '\\' ? '/' : *tail; - *p = '\0'; - - /* If symlink referred to an absolute path, then we - just use sym.contents and loop. Otherwise tack the head of - path_copy before sym.contents and translate it back from a - Win32-style path to a POSIX-style one. */ - if (isabspath (sym.contents)) - src = sym.contents; - else if (!(tail = strrchr (path_copy, '\\'))) - system_printf ("problem parsing %s - '%s'", src, full_path); - else - { - int headlen = 1 + tail - path_copy; - p = sym.contents - headlen; - memcpy (p, path_copy, headlen); - MALLOC_CHECK; - error = mount_table->conv_to_posix_path (p, tmp_buf, 1); - MALLOC_CHECK; - if (error) - return; - src = tmp_buf; - } - } - -/*fillin:*/ - if (!(opt & PC_SYM_CONTENTS)) - add_ext_from_sym (sym); - -out: - /* Deal with Windows stupidity which considers filename\. to be valid - even when "filename" is not a directory. */ - if (!need_directory || error) - /* nothing to do */; - else if (fileattr & FILE_ATTRIBUTE_DIRECTORY) - path_flags &= ~PATH_SYMLINK; - else - { - debug_printf ("%s is a non-directory", path); - error = ENOTDIR; - return; - } - - DWORD serial, volflags; - char fs_name[16]; - - strcpy (tmp_buf, full_path); - if (!rootdir (tmp_buf) || - !GetVolumeInformation (tmp_buf, NULL, 0, &serial, NULL, - &volflags, fs_name, 16)) - { - debug_printf ("GetVolumeInformation(%s) = ERR, full_path(%s), set_has_acls(FALSE)", - tmp_buf, full_path, GetLastError ()); - set_has_acls (FALSE); - set_has_buggy_open (FALSE); - } - else - { - set_isdisk (); - debug_printf ("GetVolumeInformation(%s) = OK, full_path(%s), set_has_acls(%d)", - tmp_buf, full_path, volflags & FS_PERSISTENT_ACLS); - if (!allow_smbntsec - && ((tmp_buf[0] == '\\' && tmp_buf[1] == '\\') - || GetDriveType (tmp_buf) == DRIVE_REMOTE)) - set_has_acls (FALSE); - else - set_has_acls (volflags & FS_PERSISTENT_ACLS); - /* Known file systems with buggy open calls. Further explanation - in fhandler.cc (fhandler_disk_file::open). */ - set_has_buggy_open (strcmp (fs_name, "SUNWNFS") == 0); - } - - if (saw_symlinks) - set_has_symlinks (); - - if (!error && !(path_flags & (PATH_ALL_EXEC | PATH_NOTEXEC))) - { - const char *p = strchr (path, '\0') - 4; - if (p >= path && - (strcasematch (".exe", p) || - strcasematch (".bat", p) || - strcasematch (".com", p))) - path_flags |= PATH_EXEC; - } - -#if 0 - if (!error) - { - last_path_conv = *this; - strcpy (last_src, src); - } -#endif -} - -#define deveq(s) (strcasematch (name, (s))) -#define deveqn(s, n) (strncasematch (name, (s), (n))) - -static __inline int -digits (const char *name) -{ - char *p; - int n = strtol(name, &p, 10); - - return p > name && !*p ? n : -1; -} - -const char *windows_device_names[] = -{ - NULL, - "\\dev\\console", - "conin", - "conout", - "\\dev\\ttym", - "\\dev\\tty%d", - "\\dev\\ptym", - "\\\\.\\com%d", - "\\dev\\pipe", - "\\dev\\piper", - "\\dev\\pipew", - "\\dev\\socket", - "\\dev\\windows", - - NULL, NULL, NULL, - - "\\dev\\disk", - "\\dev\\fd%d", - "\\dev\\st%d", - "nul", - "\\dev\\zero", - "\\dev\\%srandom", - "\\dev\\mem", - "\\dev\\clipboard", - "\\dev\\dsp" -}; - -static int -get_raw_device_number (const char *uxname, const char *w32path, int &unit) -{ - DWORD devn = FH_BAD; - - if (strncasematch (w32path, "\\\\.\\tape", 8)) - { - devn = FH_TAPE; - unit = digits (w32path + 8); - // norewind tape devices have leading n in name - if (strncasematch (uxname, "/dev/n", 6)) - unit += 128; - } - else if (isdrive (w32path + 4)) - { - devn = FH_FLOPPY; - unit = cyg_tolower (w32path[4]) - 'a'; - } - else if (strncasematch (w32path, "\\\\.\\physicaldrive", 17)) - { - devn = FH_FLOPPY; - unit = digits (w32path + 17) + 128; - } - return devn; -} - -int __stdcall -get_device_number (const char *name, int &unit, BOOL from_conv) -{ - DWORD devn = FH_BAD; - unit = 0; - - if ((*name == '/' && deveqn ("/dev/", 5)) || - (*name == '\\' && deveqn ("\\dev\\", 5))) - { - name += 5; - if (deveq ("tty")) - { - if (tty_attached (myself)) - { - unit = myself->ctty; - devn = FH_TTYS; - } - else if (myself->ctty > 0) - devn = FH_CONSOLE; - } - else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0) - devn = FH_TTYS; - else if (deveq ("ttym")) - devn = FH_TTYM; - else if (deveq ("ptmx")) - devn = FH_PTYM; - else if (deveq ("windows")) - devn = FH_WINDOWS; - else if (deveq ("dsp")) - devn = FH_OSS_DSP; - else if (deveq ("conin")) - devn = FH_CONIN; - else if (deveq ("conout")) - devn = FH_CONOUT; - else if (deveq ("null")) - devn = FH_NULL; - else if (deveq ("zero")) - devn = FH_ZERO; - else if (deveq ("random") || deveq ("urandom")) - { - devn = FH_RANDOM; - unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */ - } - else if (deveq ("mem")) - { - devn = FH_MEM; - unit = 1; - } - else if (deveq ("clipboard")) - devn = FH_CLIPBOARD; - else if (deveq ("port")) - { - devn = FH_MEM; - unit = 4; - } - else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0) - devn = FH_SERIAL; - else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0) - devn = FH_SERIAL; - else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew")) - devn = FH_PIPE; - else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket") - || deveq ("dgsocket")) - devn = FH_SOCKET; - else if (!from_conv) - devn = get_raw_device_number (name - 5, - path_conv (name - 5, - PC_SYM_IGNORE).get_win32 (), - unit); - } - else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0) - devn = FH_SERIAL; - else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0) - devn = FH_SERIAL; - - return devn; -} - -/* Return TRUE if src_path is a Win32 device name, filling out the device - name in win32_path */ - -static BOOL -win32_device_name (const char *src_path, char *win32_path, - DWORD &devn, int &unit) -{ - const char *devfmt; - - devn = get_device_number (src_path, unit, TRUE); - - if (devn == FH_BAD) - return FALSE; - - if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL) - return FALSE; - if (devn == FH_RANDOM) - __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u"); - else - __small_sprintf (win32_path, devfmt, unit); - return TRUE; -} - /* Normalize a POSIX path. \'s are converted to /'s in the process. All duplicate /'s, except for 2 leading /'s, are deleted. @@ -800,6 +294,490 @@ done: return 0; } +inline void +path_conv::add_ext_from_sym (symlink_info &sym) +{ + if (sym.ext_here && *sym.ext_here) + { + known_suffix = path + sym.extn; + if (sym.ext_tacked_on) + strcpy (known_suffix, sym.ext_here); + } +} + +/* Convert an arbitrary path SRC to a pure Win32 path, suitable for + passing to Win32 API routines. + + If an error occurs, `error' is set to the errno value. + Otherwise it is set to 0. + + follow_mode values: + SYMLINK_FOLLOW - convert to PATH symlink points to + SYMLINK_NOFOLLOW - convert to PATH of symlink itself + SYMLINK_IGNORE - do not check PATH for symlinks + SYMLINK_CONTENTS - just return symlink contents +*/ + +void +path_conv::check (const char *src, unsigned opt, + const suffix_info *suffixes) +{ + /* This array is used when expanding symlinks. It is MAX_PATH * 2 + in length so that we can hold the expanded symlink plus a + trailer. */ + char path_copy[MAX_PATH + 3]; + char tmp_buf[2 * MAX_PATH + 3]; + symlink_info sym; + bool need_directory = 0; + bool saw_symlinks = 0; + +#if 0 + static path_conv last_path_conv; + static char last_src[MAX_PATH + 1]; + + if (*last_src && strcmp (last_src, src) == 0) + { + *this = last_path_conv; + return; + } +#endif + + int loop = 0; + path_flags = 0; + known_suffix = NULL; + fileattr = (DWORD) -1; + case_clash = FALSE; + devn = unit = 0; + + if (!(opt & PC_NULLEMPTY)) + error = 0; + else if ((error = check_null_empty_path (src))) + return; + + /* This loop handles symlink expansion. */ + for (;;) + { + MALLOC_CHECK; + assert (src); + char *p = strrchr (src, '/'); + if (p) + { + if (p[1] == '\0' || strcmp (p, "/.") == 0) + need_directory = 1; + } + else if ((p = strrchr (src, '\\')) && + (p[1] == '\0' || strcmp (p, "\\.") == 0)) + need_directory = 1; + + error = normalize_posix_path (src, path_copy); + if (error) + return; + + char *tail = strchr (path_copy, '\0'); // Point to end of copy + char *path_end = tail; + tail[1] = '\0'; + + /* Scan path_copy from right to left looking either for a symlink + or an actual existing file. If an existing file is found, just + return. If a symlink is found exit the for loop. + Also: be careful to preserve the errno returned from + symlink.check as the caller may need it. */ + /* FIXME: Do we have to worry about multiple \'s here? */ + int component = 0; // Number of translated components + sym.contents[0] = '\0'; + + for (;;) + { + const suffix_info *suff; + char pathbuf[MAX_PATH]; + char *full_path; + + /* Don't allow symlink.check to set anything in the path_conv + class if we're working on an inner component of the path */ + if (component) + { + suff = NULL; + sym.pflags = 0; + full_path = pathbuf; + } + else + { + suff = suffixes; + sym.pflags = path_flags; + full_path = this->path; + } + + int len = sym.check (path_copy, suff, full_path, opt, + devn, unit, path_flags); + + if (sym.case_clash) + { + if (pcheck_case == PCHECK_STRICT) + { + case_clash = TRUE; + error = ENOENT; + goto out; + } + /* If pcheck_case==PCHECK_ADJUST the case_clash is remembered + if the last component is concerned. This allows functions + which shall create files to avoid overriding already existing + files with another case. */ + if (!component) + case_clash = TRUE; + } + + if (!(opt & PC_SYM_IGNORE)) + { + if (!component) + path_flags = sym.pflags; + + /* If symlink.check found an existing non-symlink file, then + it sets the appropriate flag. It also sets any suffix found + into `ext_here'. */ + if (!sym.is_symlink && sym.fileattr != (DWORD) -1) + { + error = sym.error; + if (component == 0) + { + fileattr = sym.fileattr; + add_ext_from_sym (sym); + } + if (pcheck_case == PCHECK_RELAXED) + goto out; // file found + /* Avoid further symlink evaluation. Only case checks are + done now. */ + opt |= PC_SYM_IGNORE; + } + /* Found a symlink if len > 0. If component == 0, then the + src path itself was a symlink. If !follow_mode then + we're done. Otherwise we have to insert the path found + into the full path that we are building and perform all of + these operations again on the newly derived path. */ + else if (len > 0) + { + saw_symlinks = 1; + if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW)) + { + set_symlink (); // last component of path is a symlink. + fileattr = sym.fileattr; + if (opt & PC_SYM_CONTENTS) + { + strcpy (path, sym.contents); + goto out; + } + add_ext_from_sym (sym); + if (pcheck_case == PCHECK_RELAXED) + goto out; + /* Avoid further symlink evaluation. Only case checks are + done now. */ + opt |= PC_SYM_IGNORE; + } + else + break; + } + /* No existing file found. */ + + } + + char *newtail = strrchr (path_copy, '/'); + if (tail != path_end) + *tail = '/'; + + if (!newtail) + goto out; // all done + + tail = newtail; + + /* Haven't found an existing pathname component yet. + Pinch off the tail and try again. */ + *tail = '\0'; + component++; + } + + /* Arrive here if above loop detected a symlink. */ + if (++loop > MAX_LINK_DEPTH) + { + error = ELOOP; // Eep. + return; + } + + MALLOC_CHECK; + + int taillen = strlen (tail + 1); + int buflen = strlen (sym.contents); + if (buflen + taillen > MAX_PATH) + { + error = ENAMETOOLONG; + strcpy (path, "::ENAMETOOLONG::"); + return; + } + + if ((p = strrchr (path_copy, '/')) == NULL) + p = path_copy; + *p = '\0'; + + char *headptr; + if (isabspath (sym.contents)) + headptr = tmp_buf; + else + { + strcpy (tmp_buf, path_copy); + headptr = strchr (tmp_buf, '\0'); + } + + if (headptr > tmp_buf && headptr[-1] != '/') + *headptr++ = '/'; + + for (p = sym.contents; *p; p++) + *headptr++ = *p == '\\' ? '/' : *p; + if (tail == path_end) + *headptr = '\0'; + else + { + *headptr++ = '/'; + strcpy (headptr, tail); + } + + src = tmp_buf; + } + +/*fillin:*/ + if (!(opt & PC_SYM_CONTENTS)) + add_ext_from_sym (sym); + +out: + /* Deal with Windows stupidity which considers filename\. to be valid + even when "filename" is not a directory. */ + if (!need_directory || error) + /* nothing to do */; + else if (fileattr & FILE_ATTRIBUTE_DIRECTORY) + path_flags &= ~PATH_SYMLINK; + else + { + debug_printf ("%s is a non-directory", path); + error = ENOTDIR; + return; + } + + DWORD serial, volflags; + char fs_name[16]; + + strcpy (tmp_buf, this->path); + if (!rootdir (tmp_buf) || + !GetVolumeInformation (tmp_buf, NULL, 0, &serial, NULL, + &volflags, fs_name, 16)) + { + debug_printf ("GetVolumeInformation(%s) = ERR, this->path(%s), set_has_acls(FALSE)", + tmp_buf, this->path, GetLastError ()); + set_has_acls (FALSE); + set_has_buggy_open (FALSE); + } + else + { + set_isdisk (); + debug_printf ("GetVolumeInformation(%s) = OK, this->path(%s), set_has_acls(%d)", + tmp_buf, this->path, volflags & FS_PERSISTENT_ACLS); + if (!allow_smbntsec + && ((tmp_buf[0] == '\\' && tmp_buf[1] == '\\') + || GetDriveType (tmp_buf) == DRIVE_REMOTE)) + set_has_acls (FALSE); + else + set_has_acls (volflags & FS_PERSISTENT_ACLS); + /* Known file systems with buggy open calls. Further explanation + in fhandler.cc (fhandler_disk_file::open). */ + set_has_buggy_open (strcmp (fs_name, "SUNWNFS") == 0); + } + + if (saw_symlinks) + set_has_symlinks (); + + if (!error && !(path_flags & (PATH_ALL_EXEC | PATH_NOTEXEC))) + { + const char *p = strchr (path, '\0') - 4; + if (p >= path && + (strcasematch (".exe", p) || + strcasematch (".bat", p) || + strcasematch (".com", p))) + path_flags |= PATH_EXEC; + } + +#if 0 + if (!error) + { + last_path_conv = *this; + strcpy (last_src, src); + } +#endif +} + +#define deveq(s) (strcasematch (name, (s))) +#define deveqn(s, n) (strncasematch (name, (s), (n))) + +static __inline int +digits (const char *name) +{ + char *p; + int n = strtol(name, &p, 10); + + return p > name && !*p ? n : -1; +} + +const char *windows_device_names[] = +{ + NULL, + "\\dev\\console", + "conin", + "conout", + "\\dev\\ttym", + "\\dev\\tty%d", + "\\dev\\ptym", + "\\\\.\\com%d", + "\\dev\\pipe", + "\\dev\\piper", + "\\dev\\pipew", + "\\dev\\socket", + "\\dev\\windows", + + NULL, NULL, NULL, + + "\\dev\\disk", + "\\dev\\fd%d", + "\\dev\\st%d", + "nul", + "\\dev\\zero", + "\\dev\\%srandom", + "\\dev\\mem", + "\\dev\\clipboard", + "\\dev\\dsp" +}; + +static int +get_raw_device_number (const char *uxname, const char *w32path, int &unit) +{ + DWORD devn = FH_BAD; + + if (strncasematch (w32path, "\\\\.\\tape", 8)) + { + devn = FH_TAPE; + unit = digits (w32path + 8); + // norewind tape devices have leading n in name + if (strncasematch (uxname, "/dev/n", 6)) + unit += 128; + } + else if (isdrive (w32path + 4)) + { + devn = FH_FLOPPY; + unit = cyg_tolower (w32path[4]) - 'a'; + } + else if (strncasematch (w32path, "\\\\.\\physicaldrive", 17)) + { + devn = FH_FLOPPY; + unit = digits (w32path + 17) + 128; + } + return devn; +} + +int __stdcall +get_device_number (const char *name, int &unit, BOOL from_conv) +{ + DWORD devn = FH_BAD; + unit = 0; + + if ((*name == '/' && deveqn ("/dev/", 5)) || + (*name == '\\' && deveqn ("\\dev\\", 5))) + { + name += 5; + if (deveq ("tty")) + { + if (real_tty_attached (myself)) + { + unit = myself->ctty; + devn = FH_TTYS; + } + else if (myself->ctty > 0) + devn = FH_CONSOLE; + } + else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0) + devn = FH_TTYS; + else if (deveq ("ttym")) + devn = FH_TTYM; + else if (deveq ("ptmx")) + devn = FH_PTYM; + else if (deveq ("windows")) + devn = FH_WINDOWS; + else if (deveq ("dsp")) + devn = FH_OSS_DSP; + else if (deveq ("conin")) + devn = FH_CONIN; + else if (deveq ("conout")) + devn = FH_CONOUT; + else if (deveq ("null")) + devn = FH_NULL; + else if (deveq ("zero")) + devn = FH_ZERO; + else if (deveq ("random") || deveq ("urandom")) + { + devn = FH_RANDOM; + unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */ + } + else if (deveq ("mem")) + { + devn = FH_MEM; + unit = 1; + } + else if (deveq ("clipboard")) + devn = FH_CLIPBOARD; + else if (deveq ("port")) + { + devn = FH_MEM; + unit = 4; + } + else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0) + devn = FH_SERIAL; + else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0) + devn = FH_SERIAL; + else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew")) + devn = FH_PIPE; + else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket") + || deveq ("dgsocket")) + devn = FH_SOCKET; + else if (!from_conv) + devn = get_raw_device_number (name - 5, + path_conv (name - 5, + PC_SYM_IGNORE).get_win32 (), + unit); + } + else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0) + devn = FH_SERIAL; + else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0) + devn = FH_SERIAL; + + return devn; +} + +/* Return TRUE if src_path is a Win32 device name, filling out the device + name in win32_path */ + +static BOOL +win32_device_name (const char *src_path, char *win32_path, + DWORD &devn, int &unit) +{ + const char *devfmt; + + devn = get_device_number (src_path, unit, TRUE); + + if (devn == FH_BAD) + return FALSE; + + if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL) + return FALSE; + if (devn == FH_RANDOM) + __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u"); + else + __small_sprintf (win32_path, devfmt, unit); + return TRUE; +} + /* Normalize a Win32 path. /'s are converted to \'s in the process. All duplicate \'s, except for 2 leading \'s, are deleted. @@ -2643,15 +2621,45 @@ suffix_scan::next () int symlink_info::check (const char *path, const suffix_info *suffixes, - char *orig_path, BOOL sym_ignore) + char *full_path, unsigned opt, + DWORD& devn, int& unit, unsigned& path_flags) { HANDLE h; int res = 0; suffix_scan suffix; + contents[0] = '\0'; + char *tail; + + error = mount_table->conv_to_win32_path (path, NULL, full_path, devn, + unit, &path_flags); + + if (devn != FH_BAD) + { + fileattr = 0; + goto out; /* Found a device. Stop parsing. */ + } + + /* Eat trailing slashes */ + tail = strchr (full_path, '\0'); + + /* If path is only a drivename, Windows interprets it as the current working + directory on this drive instead of the root dir which is what we want. So + we need the trailing backslash in this case. */ + while (tail > full_path + 3 && (*--tail == '\\')) + *tail = '\0'; + + if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0') + strcat (full_path, "\\"); + + if ((opt & PC_SYM_IGNORE) && pcheck_case == PCHECK_RELAXED) + { + fileattr = GetFileAttributesA (path); + goto out; + } is_symlink = TRUE; - ext_here = suffix.has (path, suffixes); - extn = ext_here - path; + ext_here = suffix.has (full_path, suffixes); + extn = ext_here - full_path; ext_tacked_on = !*ext_here; @@ -2671,8 +2679,8 @@ symlink_info::check (const char *path, const suffix_info *suffixes, continue; } - if (pcheck_case != PCHECK_RELAXED && !case_check (path, orig_path) - || sym_ignore) + if (pcheck_case != PCHECK_RELAXED && !case_check (path, full_path) + || (opt & PC_SYM_IGNORE)) goto file_not_symlink; int sym_check = 0; @@ -2684,13 +2692,13 @@ symlink_info::check (const char *path, const suffix_info *suffixes, if (suffix.lnk_match ()) sym_check = 1; - /* The old Cygwin method creating symlinks: */ + /* This is the old Cygwin method creating symlinks: */ /* A symlink will have the `system' file attribute. */ /* Only files can be symlinks (which can be symlinks to directories). */ if (fileattr & FILE_ATTRIBUTE_SYSTEM) sym_check = 2; - if (!sym_check && !(pflags & PATH_SYMLINK)) + if (!sym_check) goto file_not_symlink; /* Open the file. */ diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index bf2400edd..48ffaf9ec 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1544,7 +1544,7 @@ ctermid (char *str) static NO_COPY char buf[16]; if (str == NULL) str = buf; - if (!tty_attached (myself)) + if (!real_tty_attached (myself)) strcpy (str, "/dev/conin"); else __small_sprintf (str, "/dev/tty%d", myself->ctty); diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index 36ff39cd8..1e4fd3685 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -317,7 +317,7 @@ tty::create_inuse (const char *fmt, BOOL inherit) void tty::init (void) { - OutputStopped = 0; + output_stopped = 0; setsid (0); pgid = 0; hwnd = NULL; diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h index 6eb32b387..4b2ad7f4b 100644 --- a/winsup/cygwin/tty.h +++ b/winsup/cygwin/tty.h @@ -14,8 +14,7 @@ details. */ #define INP_BUFFER_SIZE 256 #define OUT_BUFFER_SIZE 256 #define NTTYS 128 -#define TTY_CONSOLE 0x40000000 -#define tty_attached(p) ((p)->ctty >= 0 && (p)->ctty != TTY_CONSOLE) +#define real_tty_attached(p) ((p)->ctty >= 0 && (p)->ctty != TTY_CONSOLE) /* Input/Output/ioctl events */ @@ -52,7 +51,7 @@ class tty_min public: DWORD status; pid_t pgid; - int OutputStopped; + int output_stopped; int ntty; DWORD last_ctrl_c; // tick count of last ctrl-c @@ -62,6 +61,7 @@ public: void setpgid (int pid) {pgid = pid;} int getsid () {return sid;} void setsid (pid_t tsid) {sid = tsid;} + void set_ctty (int ttynum, int flags); struct termios ti; struct winsize winsize;