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"
52 #ifdef get_default_editor
53 #undef get_default_editor
56 char *get_default_shell();
60 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
75 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
76 /* More than that would be unportable */
77 #define MAX_PIPE_SIZE 4096
79 static int error_pipe
[2]; /* File descriptors of error pipe */
80 static int old_error
; /* File descriptor of old standard error */
82 /* Creates a pipe to hold standard error for a later analysis. */
83 /* The pipe can hold 4096 bytes. Make sure no more is written */
84 /* or a deadlock might occur. */
86 open_error_pipe (void)
92 close_error_pipe (int error
, char *text
)
98 check_error_pipe (void)
100 char error
[MAX_PIPE_SIZE
];
103 while (len
< MAX_PIPE_SIZE
)
107 rvalue
= read (error_pipe
[0], error
+ len
, 1);
113 close (error_pipe
[0]);
116 message (0, " Warning ", error
);
121 StartWindowsProg (char *name
, SHORT type
)
123 #if 0 /* FIXME: PM DDL's should be loaded (or not loaded) at run time */
124 PROGDETAILS pDetails
;
126 memset(&pDetails
, 0, sizeof(PROGDETAILS
)) ;
127 pDetails
.Length
= sizeof(pDetails
);
128 pDetails
.pszExecutable
= name
; /* program name */
129 pDetails
.pszStartupDir
= NULL
; /* default directory for new app. */
130 pDetails
.pszParameters
= NULL
; /* command line */
131 pDetails
.progt
.fbVisible
= SHE_VISIBLE
;
132 pDetails
.pszEnvironment
= NULL
;
137 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
140 /* Win 3.1 Protect */
141 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
144 /* Win 3.1 Enh. Protect */
145 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
148 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
151 WinStartApp(NULLHANDLE
,
155 SAF_INSTALLEDCMDLINE
|SAF_STARTCHILDAPP
) ;
162 os2_system (int as_shell_command
, const char *shell
, const char *command
, char *parm
);
165 as_shell_command = 1: If a program is started during input line, CTRL-O
170 my_system (int as_shell_command
, const char *shell
, const char *command
)
172 char *sh
; /* This is the shell -- always! */
173 char *cmd
; /* This is the command (only the command) */
174 char *parm
; /* This is the parameter (can be more than one) */
175 register int length
, i
;
176 char temp
[4096]; /* That's enough! */
179 sh
= get_default_shell();
180 if (!strcmp("/bin/sh", shell
)) { /* Translate "/bin/sh" to "sh" */
181 return spawnlp(P_WAIT
, "sh", shell
, "-c", command
, NULL
);
182 } else if (( (t
= strrchr(shell
,'/')) /* Specialcase Bourne */
183 || (t
= strrchr(shell
,'\\')))
184 && (t1
= strchr(t
, '.'))
186 ((t1
- t
== 4) && strncmp("bash", t
, 4))
187 || ((t1
- t
== 3) && strncmp("ksh", t
, 3))
188 || ((t1
- t
== 2) && strncmp("sh", t
, 2))
190 return spawnlp(P_WAIT
, shell
, shell
, "-c", command
, NULL
);
191 } else if (strcmp(sh
, shell
)) {
193 Not equal -- That means: shell is the program and command is the
196 cmd
= (char *) shell
;
197 parm
= (char *) command
;
199 /* look into the command and take out the program */
201 strcpy(temp
, command
);
202 length
= strlen(command
);
203 for (i
=length
-1; i
>=0; i
--) {
204 if (command
[i
] == ' ') {
214 if (parm
= strchr(temp
, (char) ' ')) {
220 /* command is NULL */
224 return os2_system (as_shell_command
, sh
, cmd
, parm
);
228 ux_startp (const char *shell
, const char *command
, const char *parm
)
251 os2_system (int as_shell_command
, const char *shell
, const char *command
, char *parm
)
254 ULONG AppType
= 0; /* Application type flags (returned) */
255 APIRET rc
= NO_ERROR
; /* Return Code */
256 char pathValue
[5] = "PATH"; /* For DosSearchPath */
257 UCHAR searchResult
[MC_MAXPATHLEN
* 2 + 1]; /* For DosSearchPath */
262 /* ------------------------------------------------------- */
268 if (command
== NULL
) {
269 /* .ado: just start a shell, we don't need the parameter */
273 (char *) command
, (char *) 0);
277 memset(&StartData
, 0, sizeof(StartData
)) ;
278 StartData
.Length
= sizeof(StartData
);
279 StartData
.Related
= SSF_RELATED_CHILD
;
280 StartData
.FgBg
= SSF_FGBG_BACK
;
281 StartData
.TraceOpt
= SSF_TRACEOPT_NONE
;
282 StartData
.PgmTitle
= NULL
;
283 StartData
.TermQ
= NULL
;
284 StartData
.InheritOpt
= SSF_INHERTOPT_PARENT
;
285 StartData
.IconFile
= 0;
286 StartData
.PgmHandle
= 0;
287 StartData
.PgmControl
= SSF_CONTROL_VISIBLE
;
288 StartData
.ObjectBuffer
= ObjBuf
;
289 StartData
.ObjectBuffLen
= 100;
290 StartData
.PgmInputs
= parm
;
297 if (command
[i
-1] == ' ') {
298 /* The user has used ALT-RETURN */
301 cmdString
= (char *) malloc(i
+1);
302 for (j
=0; j
<i
; j
++) {
303 cmdString
[j
] = command
[j
];
305 cmdString
[j
] = (char) 0;
307 if ((i
< 5) || ((i
> 4) && (cmdString
[i
-4]) != '.')) {
308 /* without Extension */
309 line
= (char *) malloc(i
+5);
311 for (i
=0; (i
<3 && rc
); i
++) {
312 /* Search for the file */
313 strcpy(line
, cmdString
);
314 strcat(line
, postFix
[i
]);
315 rc
= DosSearchPath((SEARCH_IGNORENETERRS
| SEARCH_ENVIRONMENT
| SEARCH_CUR_DIRECTORY
),
319 sizeof(searchResult
));
324 rc
= DosSearchPath((SEARCH_IGNORENETERRS
| SEARCH_ENVIRONMENT
| SEARCH_CUR_DIRECTORY
),
328 sizeof(searchResult
));
332 /* Internal command or the program was written with absolut path */
333 return ux_startp(shell
, command
, parm
);
336 /* Application to be started */
337 StartData
.PgmName
= searchResult
;
338 StartData
.Environment
= NULL
;
339 rc
= DosQueryAppType(searchResult
, &AppType
);
340 if (rc
== NO_ERROR
) {
341 StartData
.SessionType
= PROG_WINDOWABLEVIO
;
342 if ((AppType
& 0x00000007) == FAPPTYP_WINDOWAPI
) {
344 StartData
.SessionType
= PROG_PM
;
345 return DosStartSession(&StartData
, &SessionID
, &pid
);
347 if ((AppType
& 0x00000007) == FAPPTYP_WINDOWCOMPAT
) {
349 return ux_startp(shell
, command
, parm
);
351 if (AppType
& 0x0000ffff & FAPPTYP_DOS
) {
353 StartData
.SessionType
= PROG_WINDOWEDVDM
;
354 return DosStartSession(&StartData
, &SessionID
, &pid
);
356 if (AppType
& 0x0000ffff & FAPPTYP_WINDOWSREAL
) {
357 /* Windows real mode app */
358 return StartWindowsProg(searchResult
, 0);
360 if (AppType
& 0x0000ffff & FAPPTYP_WINDOWSPROT
) {
361 /* Windows Protect mode app*/
362 return StartWindowsProg(searchResult
, 1);
364 if (AppType
& 0x0000ffff & FAPPTYP_WINDOWSPROT31
) {
365 /* Windows 3.1 Protect mode app*/
366 return StartWindowsProg(searchResult
, 2);
368 rc
= DosStartSession(&StartData
, &SessionID
, &pid
) ;
370 /* It's not a known exe type or it's a CMD/BAT file */
371 i
= strlen(searchResult
);
372 if ((toupper(searchResult
[--i
]) == 'T') &&
373 (toupper(searchResult
[--i
]) == 'A') &&
374 (toupper(searchResult
[--i
]) == 'B') &&
375 (searchResult
[--i
] == '.') ) {
376 StartData
.SessionType
= PROG_WINDOWEDVDM
;
377 rc
= DosStartSession(&StartData
, &SessionID
, &pid
) ;
379 rc
= ux_startp (shell
, command
, parm
);
385 char *tilde_expand (char *directory
)
387 return strdup (directory
);
391 /* Canonicalize path, and return a new path. Do everything in situ.
392 The new path differs from path in:
393 Multiple BACKSLASHs are collapsed to a single BACKSLASH.
394 Leading `./'s and trailing `/.'s are removed.
395 Trailing BACKSLASHs are removed.
396 Non-leading `../'s and trailing `..'s are handled by removing
397 portions of the path. */
399 canonicalize_pathname (char *path
)
404 stub_char
= (*path
== PATH_SEP
) ? PATH_SEP
: '.';
406 /* Walk along path looking for things to compact. */
412 while (path
[i
] && path
[i
] != PATH_SEP
)
417 /* If we didn't find any slashes, then there is nothing left to do. */
421 /* Handle multiple BACKSLASHs in a row. */
422 while (path
[i
] == PATH_SEP
)
425 if ((start
+ 1) != i
) {
426 strcpy (path
+ start
+ 1, path
+ i
);
430 /* Handle backquoted BACKSLASH. */
431 /* if (start > 0 && path[start - 1] == '\\')
434 /* Check for trailing BACKSLASH. */
435 if (start
&& !path
[i
]) {
441 /* Check for `../', `./' or trailing `.' by itself. */
442 if (path
[i
] == '.') {
443 /* Handle trailing `.' by itself. */
448 if (path
[i
+ 1] == PATH_SEP
) {
449 strcpy (path
+ i
, path
+ i
+ 1);
454 /* Handle `../' or trailing `..' by itself.
455 Remove the previous ?/ part with the exception of
456 ../, which we should leave intact. */
457 if (path
[i
+ 1] == '.' && (path
[i
+ 2] == PATH_SEP
|| !path
[i
+ 2])) {
458 while (--start
> -1 && path
[start
] != PATH_SEP
);
459 if (!strncmp (path
+ start
+ 1, "..\\", 3))
461 strcpy (path
+ start
+ 1, path
+ i
+ 2);
477 my_statfs (struct my_statfs
*myfs_stats
, char *path
)
486 UCHAR szDeviceName
[3] = "A:";
487 PBYTE pszFSDName
= NULL
; /* pointer to FS name */
488 APIRET rc
= NO_ERROR
; /* Return code */
489 BYTE fsqBuffer
[sizeof(FSQBUFFER2
) + (3 * CCHMAXPATH
)] = {0};
490 ULONG cbBuffer
= sizeof(fsqBuffer
); /* Buffer length) */
491 PFSQBUFFER2 pfsqBuffer
= (PFSQBUFFER2
) fsqBuffer
;
495 /* ------------------------------------------------------------------ */
497 lghBuf
= sizeof(FSALLOCATE
);
498 pBuf
= (PFSALLOCATE
) malloc(lghBuf
);
500 /* Get the free number of Bytes */
501 rc
= DosQueryFSInfo(0L, FSIL_ALLOC
, (PVOID
) pBuf
, lghBuf
);
502 /* KBytes available */
503 myfs_stats
->avail
= pBuf
->cSectorUnit
* pBuf
->cUnitAvail
* pBuf
->cbSector
/ 1024;
505 myfs_stats
->total
= pBuf
->cSectorUnit
* pBuf
->cUnit
* pBuf
->cbSector
/ 1024;
506 myfs_stats
->nfree
= pBuf
->cUnitAvail
;
507 myfs_stats
->nodes
= pBuf
->cbSector
;
509 lghBuf
= sizeof(FSINFO
);
510 pFsInfo
= (PFSINFO
) malloc(lghBuf
);
511 rc
= DosQueryFSInfo(0L,
516 myfs_stats
->device
= strdup(pFsInfo
->vol
.szVolLabel
); /* Label of the Disk */
518 /* Get the current disk for DosQueryFSAttach */
519 rc
= DosQueryCurrentDisk(&diskNum
, &logical
);
521 szDeviceName
[0] = (UCHAR
) (diskNum
+ (ULONG
) 'A' - 1);
522 /* Now get the type of the disk */
523 rc
= DosQueryFSAttach(szDeviceName
,
529 pszFSDName
= pfsqBuffer
->szName
+ pfsqBuffer
->cbName
+ 1;
530 myfs_stats
->mpoint
= strdup(pszFSDName
); /* FAT, HPFS ... */
532 myfs_stats
->type
= pBuf
->idFileSystem
;
533 /* What is about 3 ?*/
534 if (myfs_stats
->type
== 0) {
535 myfs_stats
->typename
= (char *) malloc(11);
536 strcpy(myfs_stats
->typename
, "Local Disk");
538 myfs_stats
->typename
= (char *) malloc(13);
539 strcpy(myfs_stats
->typename
, "Other Device");
548 gettimeofday (struct timeval
* tvp
, void *p
)
551 if (p
!= NULL
) /* what is "p"? */
554 /* Since MC only calls this func from get_random_hint we return
555 * some value, not exactly the "correct" one
557 DosGetDateTime(&pdt
);
558 tvp
->tv_usec
= (pdt
.hours
* 60 + pdt
.minutes
) * 60 + pdt
.seconds
;
559 /* Number of milliseconds since Windows started */
560 tvp
->tv_sec
= tvp
->tv_usec
* 1000 + pdt
.hundredths
* 10;
568 look_for_exe(const char* pathname
)
572 int lgh
= strlen(pathname
);
577 p
= (char *) pathname
;
578 for (j
=0; j
<lgh
-4; j
++) {
581 if (!stricmp(p
, ".exe") ||
582 !stricmp(p
, ".bat") ||
583 !stricmp(p
, ".com") ||
584 !stricmp(p
, ".cmd")) {
592 lstat (const char* pathname
, struct stat
*buffer
)
594 int rc
= stat (pathname
, buffer
);
597 if (!(buffer
->st_mode
& S_IFDIR
)) {
598 if (!look_for_exe(pathname
)) {
599 buffer
->st_mode
&= !S_IXUSR
& !S_IXGRP
& !S_IXOTH
;
620 readlink (char* path
, char* buf
, int size
)
626 symlink (char *n1
, char *n2
)
632 link (char *p1
, char *p2
)
638 chown (char *path
, int owner
, int group
)
644 mknod (char *path
, int mode
, int dev
)
650 init_uid_gid_cache (void)
656 mc_doublepopen (int inhandle
, int inlen
, pid_t
*the_pid
, char *command
, ...)
662 mc_doublepclose (int pipe
, pid_t pid
)
668 /*hacks to get it compile, remove these after vfs works */
670 vfs_get_current_dir (void)
677 vfs_current_is_extfs (void)
684 vfs_file_is_ftp (char *filename
)
690 mc_utime (char *path
, void *times
)
697 extfs_run (char *file
)
704 getgrent(void) { return NULL
; }
713 setreuid(uid_t ruid
, uid_t euid
) { return -1; }
716 setsid(void) { return (pid_t
)-1; }
719 mkfifo(const char *path
, mode_t mode
) { return -1; }
722 socketpair(int i
, int i1
, int i2
, int *i3
)
730 mc_chdir(char *pathname
)
733 register int lgh
= strlen(pathname
);
735 /* Set the current drive */
739 /* First set the default drive */
741 if (pathname
[1] == ':') {
742 ret
= DosSetDefaultDisk(toupper(pathname
[0]) - 'A' + 1);
745 /* After that, set the current dir! */
746 ret
= DosSetCurrentDir(pathname
);
752 mc_chmod(char *pathName
, int unxmode
)
754 /* OS/2 does not need S_REG */
755 int os2Mode
= unxmode
& 0x0FFF;
756 return chmod(pathName
, os2Mode
);
761 conv_os2_unx_rc(int os2rc
)
765 case ERROR_FILE_NOT_FOUND
:
766 case ERROR_PATH_NOT_FOUND
:
767 case ERROR_FILENAME_EXCED_RANGE
:
770 case ERROR_NOT_DOS_DISK
:
771 case ERROR_SHARING_VIOLATION
:
772 case ERROR_SHARING_BUFFER_EXCEEDED
:
773 case ERROR_ACCESS_DENIED
:
776 case ERROR_INVALID_PARAMETER
:
788 mc_open (char *file
, int flags
, int pmode
)
790 return open(file
, (flags
| O_BINARY
), pmode
);
794 mc_unlink(char *pathName
)
796 /* Use OS/2 API to delete a file, if the file is set as read-only,
797 the file will be deleted without asking the user! */
799 rc
= DosDelete(pathName
);
803 if (rc
== ERROR_ACCESS_DENIED
) {
804 chmod(pathName
, (S_IREAD
|S_IWRITE
));
805 rc
= DosDelete(pathName
);
807 errno
= conv_os2_unx_rc(rc
) ;
813 errno
= conv_os2_unx_rc(rc
) ;
820 get_default_editor (void)
824 char pathValue
[5] = "PATH";
825 UCHAR searchResult
[MC_MAXPATHLEN
+ 1];
827 /* EPM is not always be installed */
828 rc
= DosSearchPath((SEARCH_IGNORENETERRS
| SEARCH_ENVIRONMENT
| SEARCH_CUR_DIRECTORY
),
832 sizeof(searchResult
));
834 /* The system editor is always there */
835 return strdup("e.exe");
837 /* Let it be searched from my_system */
838 return strdup("epm.exe");
843 Get the default shell for the current hardware platform
844 TODO: Get the value of %OS2_SHELL% or %SHELL%: which one?
849 return getenv ("COMSPEC");
853 errno_dir_not_empty (int err
)
855 if (err
== ENOTEMPTY
)
860 /* The MC library directory is by default the directory where mc.exe
861 is situated. It is recommended to specify this directory via MCHOME
862 environment variable, otherwise you will be unable to rename mc.exe */
869 char *mchome
= getenv("MCHOME");
871 if (mchome
&& *mchome
)
873 mchome
= malloc(MC_MAXPATHLEN
);
874 rc
= DosQueryModuleHandle ("MC.EXE", &mc_hm
);
876 rc
= DosQueryModuleName (mc_hm
, MC_MAXPATHLEN
, mchome
);
879 for (cur
= mchome
+ strlen(mchome
); \
880 (cur
> mchome
) && (*cur
!= PATH_SEP
); cur
--);
882 cur
= strdup(mchome
);
892 int get_user_rights (struct stat
*buf
)
896 void init_groups (void)
899 void delete_groups (void)