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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 /* Check for trailing BACKSLASH. */
431 if (start
&& !path
[i
]) {
437 /* Check for `../', `./' or trailing `.' by itself. */
438 if (path
[i
] == '.') {
439 /* Handle trailing `.' by itself. */
444 if (path
[i
+ 1] == PATH_SEP
) {
445 strcpy (path
+ i
, path
+ i
+ 1);
450 /* Handle `../' or trailing `..' by itself.
451 Remove the previous ?/ part with the exception of
452 ../, which we should leave intact. */
453 if (path
[i
+ 1] == '.' && (path
[i
+ 2] == PATH_SEP
|| !path
[i
+ 2])) {
454 while (--start
> -1 && path
[start
] != PATH_SEP
);
455 if (!strncmp (path
+ start
+ 1, "..\\", 3))
457 strcpy (path
+ start
+ 1, path
+ i
+ 2);
473 my_statfs (struct my_statfs
*myfs_stats
, char *path
)
482 UCHAR szDeviceName
[3] = "A:";
483 PBYTE pszFSDName
= NULL
; /* pointer to FS name */
484 APIRET rc
= NO_ERROR
; /* Return code */
485 BYTE fsqBuffer
[sizeof(FSQBUFFER2
) + (3 * CCHMAXPATH
)] = {0};
486 ULONG cbBuffer
= sizeof(fsqBuffer
); /* Buffer length) */
487 PFSQBUFFER2 pfsqBuffer
= (PFSQBUFFER2
) fsqBuffer
;
491 /* ------------------------------------------------------------------ */
493 lghBuf
= sizeof(FSALLOCATE
);
494 pBuf
= (PFSALLOCATE
) malloc(lghBuf
);
496 /* Get the free number of Bytes */
497 rc
= DosQueryFSInfo(0L, FSIL_ALLOC
, (PVOID
) pBuf
, lghBuf
);
498 /* KBytes available */
499 myfs_stats
->avail
= pBuf
->cSectorUnit
* pBuf
->cUnitAvail
* pBuf
->cbSector
/ 1024;
501 myfs_stats
->total
= pBuf
->cSectorUnit
* pBuf
->cUnit
* pBuf
->cbSector
/ 1024;
502 myfs_stats
->nfree
= pBuf
->cUnitAvail
;
503 myfs_stats
->nodes
= pBuf
->cbSector
;
505 lghBuf
= sizeof(FSINFO
);
506 pFsInfo
= (PFSINFO
) malloc(lghBuf
);
507 rc
= DosQueryFSInfo(0L,
512 myfs_stats
->device
= strdup(pFsInfo
->vol
.szVolLabel
); /* Label of the Disk */
514 /* Get the current disk for DosQueryFSAttach */
515 rc
= DosQueryCurrentDisk(&diskNum
, &logical
);
517 szDeviceName
[0] = (UCHAR
) (diskNum
+ (ULONG
) 'A' - 1);
518 /* Now get the type of the disk */
519 rc
= DosQueryFSAttach(szDeviceName
,
525 pszFSDName
= pfsqBuffer
->szName
+ pfsqBuffer
->cbName
+ 1;
526 myfs_stats
->mpoint
= strdup(pszFSDName
); /* FAT, HPFS ... */
528 myfs_stats
->type
= pBuf
->idFileSystem
;
529 /* What is about 3 ?*/
530 if (myfs_stats
->type
== 0) {
531 myfs_stats
->typename
= (char *) malloc(11);
532 strcpy(myfs_stats
->typename
, "Local Disk");
534 myfs_stats
->typename
= (char *) malloc(13);
535 strcpy(myfs_stats
->typename
, "Other Device");
544 gettimeofday (struct timeval
* tvp
, void *p
)
547 if (p
!= NULL
) /* what is "p"? */
550 /* Since MC only calls this func from get_random_hint we return
551 * some value, not exactly the "correct" one
553 DosGetDateTime(&pdt
);
554 tvp
->tv_usec
= (pdt
.hours
* 60 + pdt
.minutes
) * 60 + pdt
.seconds
;
555 /* Number of milliseconds since Windows started */
556 tvp
->tv_sec
= tvp
->tv_usec
* 1000 + pdt
.hundredths
* 10;
564 look_for_exe(const char* pathname
)
568 int lgh
= strlen(pathname
);
573 p
= (char *) pathname
;
574 for (j
=0; j
<lgh
-4; j
++) {
577 if (!stricmp(p
, ".exe") ||
578 !stricmp(p
, ".bat") ||
579 !stricmp(p
, ".com") ||
580 !stricmp(p
, ".cmd")) {
588 lstat (const char* pathname
, struct stat
*buffer
)
590 int rc
= stat (pathname
, buffer
);
593 if (!(buffer
->st_mode
& S_IFDIR
)) {
594 if (!look_for_exe(pathname
)) {
595 buffer
->st_mode
&= !S_IXUSR
& !S_IXGRP
& !S_IXOTH
;
616 readlink (char* path
, char* buf
, int size
)
622 symlink (char *n1
, char *n2
)
628 link (char *p1
, char *p2
)
634 chown (char *path
, int owner
, int group
)
640 mknod (char *path
, int mode
, int dev
)
646 init_uid_gid_cache (void)
652 mc_doublepopen (int inhandle
, int inlen
, pid_t
*the_pid
, char *command
, ...)
658 mc_doublepclose (int pipe
, pid_t pid
)
664 /*hacks to get it compile, remove these after vfs works */
666 vfs_get_current_dir (void)
673 vfs_current_is_extfs (void)
680 vfs_file_is_ftp (char *filename
)
686 mc_utime (char *path
, void *times
)
693 extfs_run (char *file
)
700 getgrent(void) { return NULL
; }
709 setreuid(uid_t ruid
, uid_t euid
) { return -1; }
712 setsid(void) { return (pid_t
)-1; }
715 mkfifo(const char *path
, mode_t mode
) { return -1; }
718 socketpair(int i
, int i1
, int i2
, int *i3
)
726 mc_chdir(char *pathname
)
729 register int lgh
= strlen(pathname
);
731 /* Set the current drive */
735 /* First set the default drive */
737 if (pathname
[1] == ':') {
738 ret
= DosSetDefaultDisk(toupper(pathname
[0]) - 'A' + 1);
741 /* After that, set the current dir! */
742 ret
= DosSetCurrentDir(pathname
);
748 mc_chmod(char *pathName
, int unxmode
)
750 /* OS/2 does not need S_REG */
751 int os2Mode
= unxmode
& 0x0FFF;
752 return chmod(pathName
, os2Mode
);
757 conv_os2_unx_rc(int os2rc
)
761 case ERROR_FILE_NOT_FOUND
:
762 case ERROR_PATH_NOT_FOUND
:
763 case ERROR_FILENAME_EXCED_RANGE
:
766 case ERROR_NOT_DOS_DISK
:
767 case ERROR_SHARING_VIOLATION
:
768 case ERROR_SHARING_BUFFER_EXCEEDED
:
769 case ERROR_ACCESS_DENIED
:
772 case ERROR_INVALID_PARAMETER
:
784 mc_open (char *file
, int flags
, int pmode
)
786 return open(file
, (flags
| O_BINARY
), pmode
);
790 mc_unlink(char *pathName
)
792 /* Use OS/2 API to delete a file, if the file is set as read-only,
793 the file will be deleted without asking the user! */
795 rc
= DosDelete(pathName
);
799 if (rc
== ERROR_ACCESS_DENIED
) {
800 chmod(pathName
, (S_IREAD
|S_IWRITE
));
801 rc
= DosDelete(pathName
);
803 errno
= conv_os2_unx_rc(rc
) ;
809 errno
= conv_os2_unx_rc(rc
) ;
816 get_default_editor (void)
820 char pathValue
[5] = "PATH";
821 UCHAR searchResult
[MC_MAXPATHLEN
+ 1];
823 /* EPM is not always be installed */
824 rc
= DosSearchPath((SEARCH_IGNORENETERRS
| SEARCH_ENVIRONMENT
| SEARCH_CUR_DIRECTORY
),
828 sizeof(searchResult
));
830 /* The system editor is always there */
831 return strdup("e.exe");
833 /* Let it be searched from my_system */
834 return strdup("epm.exe");
839 Get the default shell for the current hardware platform
840 TODO: Get the value of %OS2_SHELL% or %SHELL%: which one?
845 return getenv ("COMSPEC");
849 errno_dir_not_empty (int err
)
851 if (err
== ENOTEMPTY
)
856 /* The MC library directory is by default the directory where mc.exe
857 is situated. It is recommended to specify this directory via MCHOME
858 environment variable, otherwise you will be unable to rename mc.exe */
865 char *mchome
= getenv("MCHOME");
867 if (mchome
&& *mchome
)
869 mchome
= malloc(MC_MAXPATHLEN
);
870 rc
= DosQueryModuleHandle ("MC.EXE", &mc_hm
);
872 rc
= DosQueryModuleName (mc_hm
, MC_MAXPATHLEN
, mchome
);
875 for (cur
= mchome
+ strlen(mchome
); \
876 (cur
> mchome
) && (*cur
!= PATH_SEP
); cur
--);
878 cur
= strdup(mchome
);
888 int get_user_rights (struct stat
*buf
)
892 void init_groups (void)
895 void delete_groups (void)