/* Various utilities - OS/2 versions Copyright (C) 1994, 1995, 1996 the Free Software Foundation. Written 1994, 1995, 1996 by: Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter, Jakub Jelinek, Mauricio Plaza. This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #define INCL_DOS #define INCL_PM #define INCL_DOSPROCESS #define INCL_DOSFILEMGR #define INCL_DOSDEVICES /* Device values */ #define INCL_DOSDATETIME #define INCL_DOSERRORS #include #include #include #include #include #include #include #include #include #include #include /* my_system */ #include /* INT_MAX */ #include /* select: timeout */ #include #include #include #include #include "../src/fs.h" #include "../src/util.h" #include "../src/dialog.h" #ifdef get_default_editor #undef get_default_editor #endif char *get_default_shell(); #ifndef ENOTEMPTY #define ENOTEMPTY ERROR_DIR_NOT_EMPTY #endif char * get_owner (int uid) { return "none"; } char * get_group (int gid) { return "none"; } /* Pipes are guaranteed to be able to hold at least 4096 bytes */ /* More than that would be unportable */ #define MAX_PIPE_SIZE 4096 static int error_pipe[2]; /* File descriptors of error pipe */ static int old_error; /* File descriptor of old standard error */ /* Creates a pipe to hold standard error for a later analysis. */ /* The pipe can hold 4096 bytes. Make sure no more is written */ /* or a deadlock might occur. */ void open_error_pipe (void) { return; } void close_error_pipe (int error, char *text) { return; } void check_error_pipe (void) { char error[MAX_PIPE_SIZE]; int len = 0; if (old_error >= 0){ while (len < MAX_PIPE_SIZE) { int rvalue; rvalue = read (error_pipe[0], error + len, 1); len ++; if (rvalue <= 0) break; } error[len] = 0; close (error_pipe[0]); } if (len > 0) message (0, " Warning ", error); } static int StartWindowsProg (char *name, SHORT type) { #if 0 /* FIXME: PM DDL's should be loaded (or not loaded) at run time */ PROGDETAILS pDetails; memset(&pDetails, 0, sizeof(PROGDETAILS)) ; pDetails.Length = sizeof(pDetails); pDetails.pszExecutable = name; /* program name */ pDetails.pszStartupDir = NULL; /* default directory for new app. */ pDetails.pszParameters = NULL; /* command line */ pDetails.progt.fbVisible = SHE_VISIBLE ; pDetails.pszEnvironment = NULL; switch (type) { case 0: /* Win Standard */ pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ; break; case 1: /* Win 3.1 Protect */ pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ; break; case 2: /* Win 3.1 Enh. Protect */ pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ; break; default: pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ; break; } WinStartApp(NULLHANDLE, &pDetails, NULL, NULL, SAF_INSTALLEDCMDLINE|SAF_STARTCHILDAPP) ; #endif return 0; } static int os2_system (int as_shell_command, const char *shell, const char *command, char *parm); /* as_shell_command = 1: If a program is started during input line, CTRL-O or RETURN = 0: F3, F4 */ int my_system (int as_shell_command, const char *shell, const char *command) { char *sh; /* This is the shell -- always! */ char *cmd; /* This is the command (only the command) */ char *parm; /* This is the parameter (can be more than one) */ register int length, i; char temp[4096]; /* That's enough! */ char *t, *t1; sh = get_default_shell(); if (!strcmp("/bin/sh", shell)) { /* Translate "/bin/sh" to "sh" */ return spawnlp(P_WAIT, "sh", shell, "-c", command, NULL); } else if (( (t = strrchr(shell,'/')) /* Specialcase Bourne */ || (t = strrchr(shell,'\\'))) && (t1 = strchr(t, '.')) && ( ((t1 - t == 4) && strncmp("bash", t, 4)) || ((t1 - t == 3) && strncmp("ksh", t, 3)) || ((t1 - t == 2) && strncmp("sh", t, 2)) )) { return spawnlp(P_WAIT, shell, shell, "-c", command, NULL); } else if (strcmp(sh, shell)) { /* Not equal -- That means: shell is the program and command is the parameter */ cmd = (char *) shell; parm = (char *) command; } else { /* look into the command and take out the program */ if (command) { strcpy(temp, command); length = strlen(command); for (i=length-1; i>=0; i--) { if (command[i] == ' ') { temp[i] = (char) 0; length--; } else break; } if (i==-1) { /* only blanks */ return -1; } if (parm = strchr(temp, (char) ' ')) { *parm = (char) 0; parm++; } cmd = (char *) temp; } else { /* command is NULL */ cmd = parm = NULL; } } return os2_system (as_shell_command, sh, cmd, parm); } static int ux_startp (const char *shell, const char *command, const char *parm) { if (parm) { spawnlp (P_WAIT, (char *) shell, (char *) shell, "/c", (char *) command, (char *) parm, (char *) 0); } else { spawnlp (P_WAIT, (char *) shell, (char *) shell, "/c", (char *) command, (char *) 0); } return 0; } static int os2_system (int as_shell_command, const char *shell, const char *command, char *parm) { register int i, j; ULONG AppType = 0; /* Application type flags (returned) */ APIRET rc = NO_ERROR; /* Return Code */ char pathValue[5] = "PATH"; /* For DosSearchPath */ UCHAR searchResult[MC_MAXPATHLEN * 2 + 1]; /* For DosSearchPath */ char *cmdString; char *postFix[3]; char *line; /* ------------------------------------------------------- */ STARTDATA StartData; CHAR ObjBuf[100]; ULONG SessionID; PID pid; if (command == NULL) { /* .ado: just start a shell, we don't need the parameter */ spawnl (P_WAIT, (char *) shell, (char *) shell, (char *) command, (char *) 0); return 0; } memset(&StartData, 0, sizeof(StartData)) ; StartData.Length = sizeof(StartData); StartData.Related = SSF_RELATED_CHILD; StartData.FgBg = SSF_FGBG_BACK; StartData.TraceOpt = SSF_TRACEOPT_NONE; StartData.PgmTitle = NULL; StartData.TermQ = NULL; StartData.InheritOpt = SSF_INHERTOPT_PARENT; StartData.IconFile = 0; StartData.PgmHandle = 0; StartData.PgmControl = SSF_CONTROL_VISIBLE ; StartData.ObjectBuffer = ObjBuf; StartData.ObjectBuffLen = 100; StartData.PgmInputs = parm; postFix[0] = ".exe"; postFix[1] = ".cmd"; postFix[2] = ".bat"; i = strlen(command); if (command[i-1] == ' ') { /* The user has used ALT-RETURN */ i--; } cmdString = (char *) malloc(i+1); for (j=0; j 4) && (cmdString[i-4]) != '.')) { /* without Extension */ line = (char *) malloc(i+5); rc = 1; for (i=0; (i<3 && rc); i++) { /* Search for the file */ strcpy(line, cmdString); strcat(line, postFix[i]); rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY), (PSZ) pathValue, line, searchResult, sizeof(searchResult)); } free (line); } else { /* Just search */ rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY), (PSZ) pathValue, cmdString, searchResult, sizeof(searchResult)); } free(cmdString); if (rc != 0) { /* Internal command or the program was written with absolut path */ return ux_startp(shell, command, parm); } /* Application to be started */ StartData.PgmName = searchResult; StartData.Environment = NULL; rc = DosQueryAppType(searchResult, &AppType); if (rc == NO_ERROR) { StartData.SessionType = PROG_WINDOWABLEVIO; if ((AppType & 0x00000007) == FAPPTYP_WINDOWAPI) { /* Window API */ StartData.SessionType = PROG_PM; return DosStartSession(&StartData, &SessionID, &pid); } if ((AppType & 0x00000007) == FAPPTYP_WINDOWCOMPAT) { /* Window compat */ return ux_startp(shell, command, parm); } if (AppType & 0x0000ffff & FAPPTYP_DOS) { /* PC/DOS Format */ StartData.SessionType = PROG_WINDOWEDVDM; return DosStartSession(&StartData, &SessionID, &pid); } if (AppType & 0x0000ffff & FAPPTYP_WINDOWSREAL) { /* Windows real mode app */ return StartWindowsProg(searchResult, 0); } if (AppType & 0x0000ffff & FAPPTYP_WINDOWSPROT) { /* Windows Protect mode app*/ return StartWindowsProg(searchResult, 1); } if (AppType & 0x0000ffff & FAPPTYP_WINDOWSPROT31) { /* Windows 3.1 Protect mode app*/ return StartWindowsProg(searchResult, 2); } rc = DosStartSession(&StartData, &SessionID, &pid) ; } else { /* It's not a known exe type or it's a CMD/BAT file */ i = strlen(searchResult); if ((toupper(searchResult[--i]) == 'T') && (toupper(searchResult[--i]) == 'A') && (toupper(searchResult[--i]) == 'B') && (searchResult[--i] == '.') ) { StartData.SessionType = PROG_WINDOWEDVDM; rc = DosStartSession(&StartData, &SessionID, &pid) ; } else { rc = ux_startp (shell, command, parm); } } return rc; } char *tilde_expand (char *directory) { return strdup (directory); } /* Canonicalize path, and return a new path. Do everything in situ. The new path differs from path in: Multiple BACKSLASHs are collapsed to a single BACKSLASH. Leading `./'s and trailing `/.'s are removed. Trailing BACKSLASHs are removed. Non-leading `../'s and trailing `..'s are handled by removing portions of the path. */ char * canonicalize_pathname (char *path) { int i, start; char stub_char; stub_char = (*path == PATH_SEP) ? PATH_SEP : '.'; /* Walk along path looking for things to compact. */ i = 0; for (;;) { if (!path[i]) break; while (path[i] && path[i] != PATH_SEP) i++; start = i++; /* If we didn't find any slashes, then there is nothing left to do. */ if (!path[start]) break; /* Handle multiple BACKSLASHs in a row. */ while (path[i] == PATH_SEP) i++; if ((start + 1) != i) { strcpy (path + start + 1, path + i); i = start + 1; } /* Check for trailing BACKSLASH. */ if (start && !path[i]) { zero_last: path[--i] = '\0'; break; } /* Check for `../', `./' or trailing `.' by itself. */ if (path[i] == '.') { /* Handle trailing `.' by itself. */ if (!path[i + 1]) goto zero_last; /* Handle `./'. */ if (path[i + 1] == PATH_SEP) { strcpy (path + i, path + i + 1); i = start; continue; } /* Handle `../' or trailing `..' by itself. Remove the previous ?/ part with the exception of ../, which we should leave intact. */ if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) { while (--start > -1 && path[start] != PATH_SEP); if (!strncmp (path + start + 1, "..\\", 3)) continue; strcpy (path + start + 1, path + i + 2); i = start; continue; } } } if (!*path) { *path = stub_char; path[1] = '\0'; } return path; } void my_statfs (struct my_statfs *myfs_stats, char *path) { PFSALLOCATE pBuf; PFSINFO pFsInfo; ULONG lghBuf; ULONG diskNum = 0; ULONG logical = 0; UCHAR szDeviceName[3] = "A:"; PBYTE pszFSDName = NULL; /* pointer to FS name */ APIRET rc = NO_ERROR; /* Return code */ BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0}; ULONG cbBuffer = sizeof(fsqBuffer); /* Buffer length) */ PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2) fsqBuffer; int i, len = 0; /* ------------------------------------------------------------------ */ lghBuf = sizeof(FSALLOCATE); pBuf = (PFSALLOCATE) malloc(lghBuf); /* Get the free number of Bytes */ rc = DosQueryFSInfo(0L, FSIL_ALLOC, (PVOID) pBuf, lghBuf); /* KBytes available */ myfs_stats->avail = pBuf->cSectorUnit * pBuf->cUnitAvail * pBuf->cbSector / 1024; /* KBytes total */ myfs_stats->total = pBuf->cSectorUnit * pBuf->cUnit * pBuf->cbSector / 1024; myfs_stats->nfree = pBuf->cUnitAvail; myfs_stats->nodes = pBuf->cbSector; lghBuf = sizeof(FSINFO); pFsInfo = (PFSINFO) malloc(lghBuf); rc = DosQueryFSInfo(0L, FSIL_VOLSER, (PVOID) pFsInfo, lghBuf); /* Get name */ myfs_stats->device = strdup(pFsInfo->vol.szVolLabel); /* Label of the Disk */ /* Get the current disk for DosQueryFSAttach */ rc = DosQueryCurrentDisk(&diskNum, &logical); szDeviceName[0] = (UCHAR) (diskNum + (ULONG) 'A' - 1); /* Now get the type of the disk */ rc = DosQueryFSAttach(szDeviceName, 0L, FSAIL_QUERYNAME, pfsqBuffer, &cbBuffer); pszFSDName = pfsqBuffer->szName + pfsqBuffer->cbName + 1; myfs_stats->mpoint = strdup(pszFSDName); /* FAT, HPFS ... */ myfs_stats->type = pBuf->idFileSystem; /* What is about 3 ?*/ if (myfs_stats->type == 0) { myfs_stats->typename = (char *) malloc(11); strcpy(myfs_stats->typename, "Local Disk"); } else { myfs_stats->typename = (char *) malloc(13); strcpy(myfs_stats->typename, "Other Device"); } free(pBuf); free(pFsInfo); } #ifndef __EMX__ int gettimeofday (struct timeval* tvp, void *p) { DATETIME pdt = {0}; if (p != NULL) /* what is "p"? */ return 0; /* Since MC only calls this func from get_random_hint we return * some value, not exactly the "correct" one */ DosGetDateTime(&pdt); tvp->tv_usec = (pdt.hours * 60 + pdt.minutes) * 60 + pdt.seconds; /* Number of milliseconds since Windows started */ tvp->tv_sec = tvp->tv_usec * 1000 + pdt.hundredths * 10; return 0; } #endif /* FAKE functions */ int look_for_exe(const char* pathname) { int j; char *p; int lgh = strlen(pathname); if (lgh < 4) { return 0; } else { p = (char *) pathname; for (j=0; jst_mode & S_IFDIR)) { if (!look_for_exe(pathname)) { buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH; } } } #endif return rc; } int getuid () { return 0; } int getgid () { return 0; } int readlink (char* path, char* buf, int size) { return -1; } int symlink (char *n1, char *n2) { return -1; } int link (char *p1, char *p2) { return -1; } int chown (char *path, int owner, int group) { return -1; } int mknod (char *path, int mode, int dev) { return -1; } void init_uid_gid_cache (void) { return; } int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...) { return -1; } int mc_doublepclose (int pipe, pid_t pid) { return 0; } #ifndef HAVE_VFS /*hacks to get it compile, remove these after vfs works */ char * vfs_get_current_dir (void) { return NULL; } #endif int vfs_current_is_extfs (void) { return 0; } #ifndef HAVE_VFS int vfs_file_is_ftp (char *filename) { return 0; } int mc_utime (char *path, void *times) { return 0; } void extfs_run (char *file) { return; } #endif void * getgrent(void) { return NULL; } void setgrent(void) {} void endgrent(void) {} int setreuid(uid_t ruid, uid_t euid) { return -1; } pid_t setsid(void) { return (pid_t)-1; } int mkfifo(const char *path, mode_t mode) { return -1; } int socketpair(int i, int i1, int i2, int *i3) { return -1; } #ifndef HAVE_VFS int mc_chdir(char *pathname) { APIRET ret; register int lgh = strlen(pathname); /* Set the current drive */ if (lgh == 0) { return -1; } else { /* First set the default drive */ if (lgh > 1) { if (pathname[1] == ':') { ret = DosSetDefaultDisk(toupper(pathname[0]) - 'A' + 1); } } /* After that, set the current dir! */ ret = DosSetCurrentDir(pathname); } return ret; } int mc_chmod(char *pathName, int unxmode) { /* OS/2 does not need S_REG */ int os2Mode = unxmode & 0x0FFF; return chmod(pathName, os2Mode); } #endif static int conv_os2_unx_rc(int os2rc) { int errCode; switch (os2rc) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_FILENAME_EXCED_RANGE: errCode = ENOENT; break; case ERROR_NOT_DOS_DISK: case ERROR_SHARING_VIOLATION: case ERROR_SHARING_BUFFER_EXCEEDED: case ERROR_ACCESS_DENIED: errCode = EACCES; break; case ERROR_INVALID_PARAMETER: errCode = EINVAL; break; default: errCode = EINVAL; break; } return errCode; } #ifndef HAVE_VFS int mc_open (char *file, int flags, int pmode) { return open(file, (flags | O_BINARY), pmode); } int mc_unlink(char *pathName) { /* Use OS/2 API to delete a file, if the file is set as read-only, the file will be deleted without asking the user! */ APIRET rc; rc = DosDelete(pathName); if (!rc) { return 0; } if (rc == ERROR_ACCESS_DENIED) { chmod(pathName, (S_IREAD|S_IWRITE)); rc = DosDelete(pathName); if (rc) { errno = conv_os2_unx_rc(rc) ; return -1; } else { return 0; } } else { errno = conv_os2_unx_rc(rc) ; return -1; } } #endif char * get_default_editor (void) { char *tmp; APIRET rc; char pathValue[5] = "PATH"; UCHAR searchResult[MC_MAXPATHLEN + 1]; /* EPM is not always be installed */ rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY), (PSZ) pathValue, "EPM.EXE", searchResult, sizeof(searchResult)); if (rc != 0) { /* The system editor is always there */ return strdup("e.exe"); } else { /* Let it be searched from my_system */ return strdup("epm.exe"); } } /* get_default_shell Get the default shell for the current hardware platform TODO: Get the value of %OS2_SHELL% or %SHELL%: which one? */ char * get_default_shell() { return getenv ("COMSPEC"); } int errno_dir_not_empty (int err) { if (err == ENOTEMPTY) return 1; return 0; } /* The MC library directory is by default the directory where mc.exe is situated. It is recommended to specify this directory via MCHOME environment variable, otherwise you will be unable to rename mc.exe */ char * get_mc_lib_dir () { HMODULE mc_hm; int rc; char *cur = NULL; char *mchome = getenv("MCHOME"); if (mchome && *mchome) return mchome; mchome = malloc(MC_MAXPATHLEN); rc = DosQueryModuleHandle ("MC.EXE", &mc_hm); if (!rc) rc = DosQueryModuleName (mc_hm, MC_MAXPATHLEN, mchome); if (!rc) { for (cur = mchome + strlen(mchome); \ (cur > mchome) && (*cur != PATH_SEP); cur--); *cur = 0; cur = strdup(mchome); free(mchome); } if (!cur || !*cur) { free(cur); return "C:\\MC"; } return cur; } int get_user_rights (struct stat *buf) { return 2; } void init_groups (void) { } void delete_groups (void) { }