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. */
24 #define INCL_DOSPROCESS
25 #define INCL_DOSFILEMGR
26 #define INCL_DOSDEVICES /* Device values */
27 #define INCL_DOSDATETIME
28 #define INCL_DOSERRORS
34 #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>
52 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
67 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
68 /* More than that would be unportable */
69 #define MAX_PIPE_SIZE 4096
71 static int error_pipe
[2]; /* File descriptors of error pipe */
72 static int old_error
; /* File descriptor of old standard error */
74 /* Creates a pipe to hold standard error for a later analysis. */
75 /* The pipe can hold 4096 bytes. Make sure no more is written */
76 /* or a deadlock might occur. */
78 open_error_pipe (void)
84 close_error_pipe (int error
, char *text
)
90 check_error_pipe (void)
92 char error
[MAX_PIPE_SIZE
];
95 while (len
< MAX_PIPE_SIZE
)
99 rvalue
= read (error_pipe
[0], error
+ len
, 1);
105 close (error_pipe
[0]);
108 message (0, " Warning ", error
);
113 StartWindowsProg (char *name
, SHORT type
)
115 #if 0 /* FIXME: PM DDL's should be loaded (or not loaded) at run time */
116 PROGDETAILS pDetails
;
118 memset(&pDetails
, 0, sizeof(PROGDETAILS
)) ;
119 pDetails
.Length
= sizeof(pDetails
);
120 pDetails
.pszExecutable
= name
; /* program name */
121 pDetails
.pszStartupDir
= NULL
; /* default directory for new app. */
122 pDetails
.pszParameters
= NULL
; /* command line */
123 pDetails
.progt
.fbVisible
= SHE_VISIBLE
;
124 pDetails
.pszEnvironment
= NULL
;
129 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
132 /* Win 3.1 Protect */
133 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
136 /* Win 3.1 Enh. Protect */
137 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
140 pDetails
.progt
.progc
= PROG_31_ENHSEAMLESSCOMMON
;
143 WinStartApp(NULLHANDLE
,
147 SAF_INSTALLEDCMDLINE
|SAF_STARTCHILDAPP
) ;
154 os2_system (int as_shell_command
, const char *shell
, const char *command
, char *parm
);
157 as_shell_command = 1: If a program is started during input line, CTRL-O
162 my_system (int as_shell_command
, const char *shell
, const char *command
)
164 char *sh
; /* This is the shell -- always! */
165 char *cmd
; /* This is the command (only the command) */
166 char *parm
; /* This is the parameter (can be more than one) */
167 register int length
, i
;
168 char temp
[4096]; /* That's enough! */
170 sh
= get_default_shell();
171 if (strcmp(sh
, shell
)) {
173 Not equal -- That means: shell is the program and command is the
176 cmd
= (char *) shell
;
177 parm
= (char *) command
;
179 /* look into the command and take out the program */
181 strcpy(temp
, command
);
182 length
= strlen(command
);
183 for (i
=length
-1; i
>=0; i
--) {
184 if (command
[i
] == ' ') {
194 if (parm
= strchr(temp
, (char) ' ')) {
200 /* command is NULL */
204 /* .ado: Konvertierung wenn shell <> get_default_shell */
205 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 ULONG ulOrdinal
= 0; /* Ordinal of entry in name list */
469 PBYTE pszFSDName
= NULL
; /* pointer to FS name */
470 APIRET rc
= NO_ERROR
; /* Return code */
471 BYTE fsqBuffer
[sizeof(FSQBUFFER2
) + (3 * CCHMAXPATH
)] = {0};
472 ULONG cbBuffer
= sizeof(fsqBuffer
); /* Buffer length) */
473 PFSQBUFFER2 pfsqBuffer
= (PFSQBUFFER2
) fsqBuffer
;
477 /* ------------------------------------------------------------------ */
479 lghBuf
= sizeof(FSALLOCATE
);
480 pBuf
= (PFSALLOCATE
) malloc(lghBuf
);
482 /* Get the free number of Bytes */
483 rc
= DosQueryFSInfo(0L, FSIL_ALLOC
, (PVOID
) pBuf
, lghBuf
);
484 /* KBytes available */
485 myfs_stats
->avail
= pBuf
->cSectorUnit
* pBuf
->cUnitAvail
* pBuf
->cbSector
/ 1024;
487 myfs_stats
->total
= pBuf
->cSectorUnit
* pBuf
->cUnit
* pBuf
->cbSector
/ 1024;
488 myfs_stats
->nfree
= pBuf
->cUnitAvail
;
489 myfs_stats
->nodes
= pBuf
->cbSector
;
491 lghBuf
= sizeof(FSINFO
);
492 pFsInfo
= (PFSINFO
) malloc(lghBuf
);
493 rc
= DosQueryFSInfo(0L,
498 myfs_stats
->device
= strdup(pFsInfo
->vol
.szVolLabel
); /* Label of the Disk */
500 /* Get the current disk for DosQueryFSAttach */
501 rc
= DosQueryCurrentDisk(&diskNum
, &logical
);
503 szDeviceName
[0] = (UCHAR
) (diskNum
+ (ULONG
) 'A' - 1);
504 /* Now get the type of the disk */
505 rc
= DosQueryFSAttach(szDeviceName
,
511 pszFSDName
= pfsqBuffer
->szName
+ pfsqBuffer
->cbName
+ 1;
512 myfs_stats
->mpoint
= strdup(pszFSDName
); /* FAT, HPFS ... */
514 myfs_stats
->type
= pBuf
->idFileSystem
;
515 /* What is about 3 ?*/
516 if (myfs_stats
->type
== 0) {
517 myfs_stats
->typename
= (char *) malloc(11);
518 strcpy(myfs_stats
->typename
, "Local Disk");
520 myfs_stats
->typename
= (char *) malloc(13);
521 strcpy(myfs_stats
->typename
, "Other Device");
529 gettimeofday (struct timeval
* tvp
, void *p
)
532 if (p
!= NULL
) /* what is "p"? */
535 /* Since MC only calls this func from get_random_hint we return
536 * some value, not exactly the "correct" one
538 DosGetDateTime(&pdt
);
539 tvp
->tv_usec
= (pdt
.hours
* 60 + pdt
.minutes
) * 60 + pdt
.seconds
;
540 /* Number of milliseconds since Windows started */
541 tvp
->tv_sec
= tvp
->tv_usec
* 1000 + pdt
.hundredths
* 10;
548 look_for_exe(const char* pathname
)
552 int lgh
= strlen(pathname
);
557 p
= (char *) pathname
;
558 for (j
=0; j
<lgh
-4; j
++) {
561 if (!stricmp(p
, ".exe") ||
562 !stricmp(p
, ".bat") ||
563 !stricmp(p
, ".com") ||
564 !stricmp(p
, ".cmd")) {
572 lstat (const char* pathname
, struct stat
*buffer
)
574 int rc
= stat (pathname
, buffer
);
577 if (!(buffer
->st_mode
& S_IFDIR
)) {
578 if (!look_for_exe(pathname
)) {
579 buffer
->st_mode
&= !S_IXUSR
& !S_IXGRP
& !S_IXOTH
;
600 readlink (char* path
, char* buf
, int size
)
606 symlink (char *n1
, char *n2
)
612 link (char *p1
, char *p2
)
618 chown (char *path
, int owner
, int group
)
624 mknod (char *path
, int mode
, int dev
)
630 init_uid_gid_cache (void)
636 mc_doublepopen (int inhandle
, int inlen
, pid_t
*the_pid
, char *command
, ...)
642 mc_doublepclose (int pipe
, pid_t pid
)
647 /*hacks to get it compile, remove these after vfs works */
649 vfs_get_current_dir (void)
655 vfs_current_is_extfs (void)
661 vfs_file_is_ftp (char *filename
)
667 mc_utime (char *path
, void *times
)
674 extfs_run (char *file
)
687 mc_chdir(char *pathname
)
690 register int lgh
= strlen(pathname
);
692 /* Set the current drive */
696 /* First set the default drive */
698 if (pathname
[1] == ':') {
699 ret
= DosSetDefaultDisk(toupper(pathname
[0]) - 'A' + 1);
702 /* After that, set the current dir! */
703 ret
= DosSetCurrentDir(pathname
);
709 mc_chmod(char *pathName
, int unxmode
)
711 /* OS/2 does not need S_REG */
712 int os2Mode
= unxmode
& 0x0FFF;
713 return chmod(pathName
, os2Mode
);
717 conv_os2_unx_rc(int os2rc
)
721 case ERROR_FILE_NOT_FOUND
:
722 case ERROR_PATH_NOT_FOUND
:
723 case ERROR_FILENAME_EXCED_RANGE
:
726 case ERROR_NOT_DOS_DISK
:
727 case ERROR_SHARING_VIOLATION
:
728 case ERROR_SHARING_BUFFER_EXCEEDED
:
729 case ERROR_ACCESS_DENIED
:
732 case ERROR_INVALID_PARAMETER
:
743 mc_open (char *file
, int flags
, int pmode
)
745 return open(file
, (flags
| O_BINARY
), pmode
);
749 mc_unlink(char *pathName
)
751 /* Use OS/2 API to delete a file, if the file is set as read-only,
752 the file will be deleted without asking the user! */
754 rc
= DosDelete(pathName
);
758 if (rc
== ERROR_ACCESS_DENIED
) {
759 chmod(pathName
, (S_IREAD
|S_IWRITE
));
760 rc
= DosDelete(pathName
);
762 errno
= conv_os2_unx_rc(rc
) ;
768 errno
= conv_os2_unx_rc(rc
) ;
774 strncasecmp (char *s
, char *d
, int count
)
776 register char result
;
779 if (result
= (0x20 | *s
) - (0x20 | *d
))
791 _popen(const char *cmd
, const char *mode
)
803 get_default_editor (void)
807 char pathValue
[5] = "PATH";
808 UCHAR searchResult
[MC_MAXPATHLEN
+ 1];
810 /* EPM is not always be installed */
811 rc
= DosSearchPath((SEARCH_IGNORENETERRS
| SEARCH_ENVIRONMENT
| SEARCH_CUR_DIRECTORY
),
815 sizeof(searchResult
));
817 /* The system editor is always there */
818 return strdup("e.exe");
820 /* Let it be searched from my_system */
821 return strdup("epm.exe");
826 Get the default shell for the current hardware platform
827 TODO: Get the value of %OS2_SHELL% or %SHELL%: which one?
832 return getenv ("COMSPEC");
842 errno_dir_not_empty (int err
)
844 if (err
== ENOTEMPTY
)
852 char *mchome
= getenv("MCHOME");
860 int get_user_rights (struct stat
*buf
)
864 void init_groups (void)
867 void delete_groups (void)