1 /* Various utilities - OS/2 versions
2 Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
4 Written 1994, 1995, 1996 by:
5 Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
6 Jakub Jelinek, Mauricio Plaza.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
26 #define INCL_DOSPROCESS
27 #define INCL_DOSFILEMGR
28 #define INCL_DOSDEVICES /* Device values */
29 #define INCL_DOSDATETIME
30 #define INCL_DOSERRORS
35 #include <sys/types.h>
41 #include <signal.h> /* my_system */
42 #include <limits.h> /* INT_MAX */
43 #include <sys/time.h> /* select: timeout */
44 #include <sys/param.h>
48 #include "../src/fs.h"
49 #include "../src/util.h"
50 #include "../src/dialog.h"
53 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
68 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
69 /* More than that would be unportable */
70 #define MAX_PIPE_SIZE 4096
72 static int error_pipe
[2]; /* File descriptors of error pipe */
73 static int old_error
; /* File descriptor of old standard error */
75 /* Creates a pipe to hold standard error for a later analysis. */
76 /* The pipe can hold 4096 bytes. Make sure no more is written */
77 /* or a deadlock might occur. */
79 open_error_pipe (void)
85 close_error_pipe (int error
, char *text
)
91 check_error_pipe (void)
93 char error
[MAX_PIPE_SIZE
];
96 while (len
< MAX_PIPE_SIZE
)
100 rvalue
= read (error_pipe
[0], error
+ len
, 1);
106 close (error_pipe
[0]);
109 message (0, " Warning ", error
);
114 StartWindowsProg (char *name
, SHORT type
)
116 #if 0 /* FIXME: PM DDL's should be loaded (or not loaded) at run time */
117 PROGDETAILS pDetails
;
119 memset(&pDetails
, 0, sizeof(PROGDETAILS
)) ;
120 pDetails
.Length
= sizeof(pDetails
);
121 pDetails
.pszExecutable
= name
; /* program name */
122 pDetails
.pszStartupDir
= NULL
; /* default directory for new app. */
123 pDetails
.pszParameters
= NULL
; /* command line */
124 pDetails
.progt
.fbVisible
= SHE_VISIBLE
;
125 pDetails
.pszEnvironment
= NULL
;
130 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
133 /* Win 3.1 Protect */
134 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
137 /* Win 3.1 Enh. Protect */
138 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
141 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
144 WinStartApp(NULLHANDLE
,
148 SAF_INSTALLEDCMDLINE
|SAF_STARTCHILDAPP
) ;
155 os2_system (int as_shell_command
, const char *shell
, const char *command
, char *parm
);
158 as_shell_command = 1: If a program is started during input line, CTRL-O
163 my_system (int as_shell_command
, const char *shell
, const char *command
)
165 char *sh
; /* This is the shell -- always! */
166 char *cmd
; /* This is the command (only the command) */
167 char *parm
; /* This is the parameter (can be more than one) */
168 register int length
, i
;
169 char temp
[4096]; /* That's enough! */
171 sh
= get_default_shell();
172 if (strcmp(sh
, shell
)) {
174 Not equal -- That means: shell is the program and command is the
177 cmd
= (char *) shell
;
178 parm
= (char *) command
;
180 /* look into the command and take out the program */
182 strcpy(temp
, command
);
183 length
= strlen(command
);
184 for (i
=length
-1; i
>=0; i
--) {
185 if (command
[i
] == ' ') {
195 if (parm
= strchr(temp
, (char) ' ')) {
201 /* command is NULL */
205 return os2_system (as_shell_command
, sh
, cmd
, parm
);
209 ux_startp (const char *shell
, const char *command
, const char *parm
)
232 os2_system (int as_shell_command
, const char *shell
, const char *command
, char *parm
)
235 ULONG AppType
= 0; /* Application type flags (returned) */
236 APIRET rc
= NO_ERROR
; /* Return Code */
237 char pathValue
[5] = "PATH"; /* For DosSearchPath */
238 UCHAR searchResult
[MC_MAXPATHLEN
* 2 + 1]; /* For DosSearchPath */
243 /* ------------------------------------------------------- */
249 if (command
== NULL
) {
250 /* .ado: just start a shell, we don't need the parameter */
254 (char *) command
, (char *) 0);
258 memset(&StartData
, 0, sizeof(StartData
)) ;
259 StartData
.Length
= sizeof(StartData
);
260 StartData
.Related
= SSF_RELATED_CHILD
;
261 StartData
.FgBg
= SSF_FGBG_BACK
;
262 StartData
.TraceOpt
= SSF_TRACEOPT_NONE
;
263 StartData
.PgmTitle
= NULL
;
264 StartData
.TermQ
= NULL
;
265 StartData
.InheritOpt
= SSF_INHERTOPT_PARENT
;
266 StartData
.IconFile
= 0;
267 StartData
.PgmHandle
= 0;
268 StartData
.PgmControl
= SSF_CONTROL_VISIBLE
;
269 StartData
.ObjectBuffer
= ObjBuf
;
270 StartData
.ObjectBuffLen
= 100;
271 StartData
.PgmInputs
= parm
;
278 if (command
[i
-1] == ' ') {
279 /* The user has used ALT-RETURN */
282 cmdString
= (char *) malloc(i
+1);
283 for (j
=0; j
<i
; j
++) {
284 cmdString
[j
] = command
[j
];
286 cmdString
[j
] = (char) 0;
288 if ((i
< 5) || ((i
> 4) && (cmdString
[i
-4]) != '.')) {
289 /* without Extension */
290 line
= (char *) malloc(i
+5);
292 for (i
=0; (i
<3 && rc
); i
++) {
293 /* Search for the file */
294 strcpy(line
, cmdString
);
295 strcat(line
, postFix
[i
]);
296 rc
= DosSearchPath((SEARCH_IGNORENETERRS
| SEARCH_ENVIRONMENT
| SEARCH_CUR_DIRECTORY
),
300 sizeof(searchResult
));
305 rc
= DosSearchPath((SEARCH_IGNORENETERRS
| SEARCH_ENVIRONMENT
| SEARCH_CUR_DIRECTORY
),
309 sizeof(searchResult
));
313 /* Internal command or the program was written with absolut path */
314 return ux_startp(shell
, command
, parm
);
317 /* Application to be started */
318 StartData
.PgmName
= searchResult
;
319 StartData
.Environment
= NULL
;
320 rc
= DosQueryAppType(searchResult
, &AppType
);
321 if (rc
== NO_ERROR
) {
322 StartData
.SessionType
= PROG_WINDOWABLEVIO
;
323 if ((AppType
& 0x00000007) == FAPPTYP_WINDOWAPI
) {
325 StartData
.SessionType
= PROG_PM
;
326 return DosStartSession(&StartData
, &SessionID
, &pid
);
328 if ((AppType
& 0x00000007) == FAPPTYP_WINDOWCOMPAT
) {
330 return ux_startp(shell
, command
, parm
);
332 if (AppType
& 0x0000ffff & FAPPTYP_DOS
) {
334 StartData
.SessionType
= PROG_WINDOWEDVDM
;
335 return DosStartSession(&StartData
, &SessionID
, &pid
);
337 if (AppType
& 0x0000ffff & FAPPTYP_WINDOWSREAL
) {
338 /* Windows real mode app */
339 return StartWindowsProg(searchResult
, 0);
341 if (AppType
& 0x0000ffff & FAPPTYP_WINDOWSPROT
) {
342 /* Windows Protect mode app*/
343 return StartWindowsProg(searchResult
, 1);
345 if (AppType
& 0x0000ffff & FAPPTYP_WINDOWSPROT31
) {
346 /* Windows 3.1 Protect mode app*/
347 return StartWindowsProg(searchResult
, 2);
349 rc
= DosStartSession(&StartData
, &SessionID
, &pid
) ;
351 /* It's not a known exe type or it's a CMD/BAT file */
352 i
= strlen(searchResult
);
353 if ((toupper(searchResult
[--i
]) == 'T') &&
354 (toupper(searchResult
[--i
]) == 'A') &&
355 (toupper(searchResult
[--i
]) == 'B') &&
356 (searchResult
[--i
] == '.') ) {
357 StartData
.SessionType
= PROG_WINDOWEDVDM
;
358 rc
= DosStartSession(&StartData
, &SessionID
, &pid
) ;
360 rc
= ux_startp (shell
, command
, parm
);
366 char *tilde_expand (char *directory
)
368 return strdup (directory
);
372 /* Canonicalize path, and return a new path. Do everything in situ.
373 The new path differs from path in:
374 Multiple BACKSLASHs are collapsed to a single BACKSLASH.
375 Leading `./'s and trailing `/.'s are removed.
376 Trailing BACKSLASHs are removed.
377 Non-leading `../'s and trailing `..'s are handled by removing
378 portions of the path. */
380 canonicalize_pathname (char *path
)
385 stub_char
= (*path
== PATH_SEP
) ? PATH_SEP
: '.';
387 /* Walk along path looking for things to compact. */
393 while (path
[i
] && path
[i
] != PATH_SEP
)
398 /* If we didn't find any slashes, then there is nothing left to do. */
402 /* Handle multiple BACKSLASHs in a row. */
403 while (path
[i
] == PATH_SEP
)
406 if ((start
+ 1) != i
) {
407 strcpy (path
+ start
+ 1, path
+ i
);
411 /* Handle backquoted BACKSLASH. */
412 /* if (start > 0 && path[start - 1] == '\\')
415 /* Check for trailing BACKSLASH. */
416 if (start
&& !path
[i
]) {
422 /* Check for `../', `./' or trailing `.' by itself. */
423 if (path
[i
] == '.') {
424 /* Handle trailing `.' by itself. */
429 if (path
[i
+ 1] == PATH_SEP
) {
430 strcpy (path
+ i
, path
+ i
+ 1);
435 /* Handle `../' or trailing `..' by itself.
436 Remove the previous ?/ part with the exception of
437 ../, which we should leave intact. */
438 if (path
[i
+ 1] == '.' && (path
[i
+ 2] == PATH_SEP
|| !path
[i
+ 2])) {
439 while (--start
> -1 && path
[start
] != PATH_SEP
);
440 if (!strncmp (path
+ start
+ 1, "..\\", 3))
442 strcpy (path
+ start
+ 1, path
+ i
+ 2);
458 my_statfs (struct my_statfs
*myfs_stats
, char *path
)
467 UCHAR szDeviceName
[3] = "A:";
468 PBYTE pszFSDName
= NULL
; /* pointer to FS name */
469 APIRET rc
= NO_ERROR
; /* Return code */
470 BYTE fsqBuffer
[sizeof(FSQBUFFER2
) + (3 * CCHMAXPATH
)] = {0};
471 ULONG cbBuffer
= sizeof(fsqBuffer
); /* Buffer length) */
472 PFSQBUFFER2 pfsqBuffer
= (PFSQBUFFER2
) fsqBuffer
;
476 /* ------------------------------------------------------------------ */
478 lghBuf
= sizeof(FSALLOCATE
);
479 pBuf
= (PFSALLOCATE
) malloc(lghBuf
);
481 /* Get the free number of Bytes */
482 rc
= DosQueryFSInfo(0L, FSIL_ALLOC
, (PVOID
) pBuf
, lghBuf
);
483 /* KBytes available */
484 myfs_stats
->avail
= pBuf
->cSectorUnit
* pBuf
->cUnitAvail
* pBuf
->cbSector
/ 1024;
486 myfs_stats
->total
= pBuf
->cSectorUnit
* pBuf
->cUnit
* pBuf
->cbSector
/ 1024;
487 myfs_stats
->nfree
= pBuf
->cUnitAvail
;
488 myfs_stats
->nodes
= pBuf
->cbSector
;
490 lghBuf
= sizeof(FSINFO
);
491 pFsInfo
= (PFSINFO
) malloc(lghBuf
);
492 rc
= DosQueryFSInfo(0L,
497 myfs_stats
->device
= strdup(pFsInfo
->vol
.szVolLabel
); /* Label of the Disk */
499 /* Get the current disk for DosQueryFSAttach */
500 rc
= DosQueryCurrentDisk(&diskNum
, &logical
);
502 szDeviceName
[0] = (UCHAR
) (diskNum
+ (ULONG
) 'A' - 1);
503 /* Now get the type of the disk */
504 rc
= DosQueryFSAttach(szDeviceName
,
510 pszFSDName
= pfsqBuffer
->szName
+ pfsqBuffer
->cbName
+ 1;
511 myfs_stats
->mpoint
= strdup(pszFSDName
); /* FAT, HPFS ... */
513 myfs_stats
->type
= pBuf
->idFileSystem
;
514 /* What is about 3 ?*/
515 if (myfs_stats
->type
== 0) {
516 myfs_stats
->typename
= (char *) malloc(11);
517 strcpy(myfs_stats
->typename
, "Local Disk");
519 myfs_stats
->typename
= (char *) malloc(13);
520 strcpy(myfs_stats
->typename
, "Other Device");
528 gettimeofday (struct timeval
* tvp
, void *p
)
531 if (p
!= NULL
) /* what is "p"? */
534 /* Since MC only calls this func from get_random_hint we return
535 * some value, not exactly the "correct" one
537 DosGetDateTime(&pdt
);
538 tvp
->tv_usec
= (pdt
.hours
* 60 + pdt
.minutes
) * 60 + pdt
.seconds
;
539 /* Number of milliseconds since Windows started */
540 tvp
->tv_sec
= tvp
->tv_usec
* 1000 + pdt
.hundredths
* 10;
547 look_for_exe(const char* pathname
)
551 int lgh
= strlen(pathname
);
556 p
= (char *) pathname
;
557 for (j
=0; j
<lgh
-4; j
++) {
560 if (!stricmp(p
, ".exe") ||
561 !stricmp(p
, ".bat") ||
562 !stricmp(p
, ".com") ||
563 !stricmp(p
, ".cmd")) {
571 lstat (const char* pathname
, struct stat
*buffer
)
573 int rc
= stat (pathname
, buffer
);
576 if (!(buffer
->st_mode
& S_IFDIR
)) {
577 if (!look_for_exe(pathname
)) {
578 buffer
->st_mode
&= !S_IXUSR
& !S_IXGRP
& !S_IXOTH
;
599 readlink (char* path
, char* buf
, int size
)
605 symlink (char *n1
, char *n2
)
611 link (char *p1
, char *p2
)
617 chown (char *path
, int owner
, int group
)
623 mknod (char *path
, int mode
, int dev
)
629 init_uid_gid_cache (void)
635 mc_doublepopen (int inhandle
, int inlen
, pid_t
*the_pid
, char *command
, ...)
641 mc_doublepclose (int pipe
, pid_t pid
)
646 /*hacks to get it compile, remove these after vfs works */
648 vfs_get_current_dir (void)
654 vfs_current_is_extfs (void)
660 vfs_file_is_ftp (char *filename
)
666 mc_utime (char *path
, void *times
)
673 extfs_run (char *file
)
686 mc_chdir(char *pathname
)
689 register int lgh
= strlen(pathname
);
691 /* Set the current drive */
695 /* First set the default drive */
697 if (pathname
[1] == ':') {
698 ret
= DosSetDefaultDisk(toupper(pathname
[0]) - 'A' + 1);
701 /* After that, set the current dir! */
702 ret
= DosSetCurrentDir(pathname
);
708 mc_chmod(char *pathName
, int unxmode
)
710 /* OS/2 does not need S_REG */
711 int os2Mode
= unxmode
& 0x0FFF;
712 return chmod(pathName
, os2Mode
);
716 conv_os2_unx_rc(int os2rc
)
720 case ERROR_FILE_NOT_FOUND
:
721 case ERROR_PATH_NOT_FOUND
:
722 case ERROR_FILENAME_EXCED_RANGE
:
725 case ERROR_NOT_DOS_DISK
:
726 case ERROR_SHARING_VIOLATION
:
727 case ERROR_SHARING_BUFFER_EXCEEDED
:
728 case ERROR_ACCESS_DENIED
:
731 case ERROR_INVALID_PARAMETER
:
742 mc_open (char *file
, int flags
, int pmode
)
744 return open(file
, (flags
| O_BINARY
), pmode
);
748 mc_unlink(char *pathName
)
750 /* Use OS/2 API to delete a file, if the file is set as read-only,
751 the file will be deleted without asking the user! */
753 rc
= DosDelete(pathName
);
757 if (rc
== ERROR_ACCESS_DENIED
) {
758 chmod(pathName
, (S_IREAD
|S_IWRITE
));
759 rc
= DosDelete(pathName
);
761 errno
= conv_os2_unx_rc(rc
) ;
767 errno
= conv_os2_unx_rc(rc
) ;
773 get_default_editor (void)
777 char pathValue
[5] = "PATH";
778 UCHAR searchResult
[MC_MAXPATHLEN
+ 1];
780 /* EPM is not always be installed */
781 rc
= DosSearchPath((SEARCH_IGNORENETERRS
| SEARCH_ENVIRONMENT
| SEARCH_CUR_DIRECTORY
),
785 sizeof(searchResult
));
787 /* The system editor is always there */
788 return strdup("e.exe");
790 /* Let it be searched from my_system */
791 return strdup("epm.exe");
796 Get the default shell for the current hardware platform
797 TODO: Get the value of %OS2_SHELL% or %SHELL%: which one?
802 return getenv ("COMSPEC");
806 errno_dir_not_empty (int err
)
808 if (err
== ENOTEMPTY
)
813 /* The MC library directory is by default the directory where mc.exe
814 is situated. It is recommended to specify this directory via MCHOME
815 environment variable, otherwise you will be unable to rename mc.exe */
822 char *mchome
= getenv("MCHOME");
824 if (mchome
&& *mchome
)
826 mchome
= malloc(MC_MAXPATHLEN
);
827 rc
= DosQueryModuleHandle ("MC.EXE", &mc_hm
);
829 rc
= DosQueryModuleName (mc_hm
, MC_MAXPATHLEN
, mchome
);
832 for (cur
= mchome
+ strlen(mchome
); \
833 (cur
> mchome
) && (*cur
!= PATH_SEP
); cur
--);
835 cur
= strdup(mchome
);
845 int get_user_rights (struct stat
*buf
)
849 void init_groups (void)
852 void delete_groups (void)