mc/pc/util_os2.c

902 lines
22 KiB
C

/* 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 <config.h>
#define INCL_DOS
#define INCL_PM
#define INCL_DOSPROCESS
#define INCL_DOSFILEMGR
#define INCL_DOSDEVICES /* Device values */
#define INCL_DOSDATETIME
#define INCL_DOSERRORS
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/stat.h>
#include <errno.h>
#include <io.h>
#include <fcntl.h>
#include <signal.h> /* my_system */
#include <limits.h> /* INT_MAX */
#include <sys/time.h> /* select: timeout */
#include <sys/param.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <process.h>
#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<i; j++) {
cmdString[j] = command[j];
}
cmdString[j] = (char) 0;
if ((i < 5) || ((i > 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;
}
/* Handle backquoted BACKSLASH. */
/* if (start > 0 && path[start - 1] == '\\')
continue; */
/* 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; j<lgh-4; j++) {
p++;
}
if (!stricmp(p, ".exe") ||
!stricmp(p, ".bat") ||
!stricmp(p, ".com") ||
!stricmp(p, ".cmd")) {
return 1;
}
}
return 0;
}
int
lstat (const char* pathname, struct stat *buffer)
{
int rc = stat (pathname, buffer);
#ifdef __BORLANDC__
if (rc == 0) {
if (!(buffer->st_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)
{
}