2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
5 Desc: Find the whereabouts of an executable file
9 /******************************************************************************
17 FILE/A, NORES/S, RES/S, ALL/S
25 Find and print the location of a specific program.
26 Resident programs are marked as RES if they are not
27 internal resident in which case they are marked as INTERNAL.
29 Which searches the resident list, the current directory,
30 the command paths and the C: assign. If the item was not
31 found the condition flag is set to WARN but no error is
36 FILE -- the command to search for
37 NORES -- don't include resident programs in the search
38 RES -- consider resident programs only
39 ALL -- find all locations of the FILE. This may cause the
40 printing of the same location several times, for
41 instance if the current directory is C: and the
48 For compatibility reasons these cases are handled specially:
51 Prints the expanded path if it exists and is a file
52 and no RES argument is given.
54 Path which ends with a ':':
55 Prints the expanded path if it exists and no RES argument is given.
65 Executable files in AROS currently haven't got the e-flag set,
66 which makes Which unusable for now in emulated mode.
71 ******************************************************************************/
74 #include <aros/debug.h>
75 #include <proto/exec.h>
76 #include <proto/dos.h>
77 #include <exec/memory.h>
78 #include <dos/dosextens.h>
79 #include <utility/tagitem.h>
81 #define ARG_COUNT 4 /* Number of ReadArgs() arguments */
83 const TEXT version
[] = "$VER: Which 41.2 (14.2.2016)";
85 /* NOTE: For now, compatibility to the Amiga Which command is kept, but
86 I think that the restriction to only executable files should be
87 removed, especially considering soft links and such. */
91 * Check the resident list for the command 'name'.
93 static BOOL
FindResidentCommand(STRPTR name
);
97 * Check the paths for the command 'name'.
99 static BOOL
FindCommandinPath(STRPTR name
, BOOL checkAll
, struct FileInfoBlock
*fib
);
103 * Handle absolute path for the command 'name'.
106 static BOOL
FindCommandInAbsolutePath(STRPTR name
, TEXT
*colon
, struct FileInfoBlock
*fib
);
110 * Check the C: multiassign for the command 'name'.
112 static BOOL
FindCommandinC(STRPTR name
, BOOL checkAll
, struct FileInfoBlock
*fib
);
116 * Look in the current directory for the command 'name'.
118 static BOOL
CheckDirectory(STRPTR name
, BOOL directory
, struct FileInfoBlock
*fib
);
122 * Get a string that specifies the full path to a file or NULL if there
123 * was not enough memory to allocate the string. This string should be
124 * freed using FreeVec().
126 static STRPTR
GetFullPath(BPTR lock
);
133 /* Array filled by ReadArgs() call */
134 IPTR args
[ARG_COUNT
] = {0, 0, 0, 0};
136 struct RDArgs
*rda
; /* ReadArgs standard struct */
137 BOOL found
= FALSE
; /* Indicates whether we've found a file
138 or not -- used for ALL ReadArgs() tag. */
139 int error
= RETURN_WARN
; /* Error value to return */
141 struct FileInfoBlock
*fib
; /* Used in Examine(). Allocated at top level
142 to skip multiple calls to
143 AllocDosObject() / FreeDosObject */
145 if((rda
= ReadArgs("FILE/A,NORES/S,RES/S,ALL/S", args
, NULL
)) != NULL
)
147 BOOL noRes
= (BOOL
)args
[1]; /* Don't check resident commands */
148 BOOL resOnly
= (BOOL
)args
[2]; /* Check resident commands only */
149 BOOL checkAll
= (BOOL
)args
[3]; /* Check for multiple occurances */
151 STRPTR commandName
= (STRPTR
)args
[0]; /* Command to look for */
155 fib
= AllocDosObject(DOS_FIB
, NULL
);
159 if (!resOnly
&& (colon
= strchr(commandName
, ':')))
161 /* Check for absolute path */
162 found
|= FindCommandInAbsolutePath(commandName
, colon
, fib
);
163 D(bug("Absolute path\n"));
169 /* Check resident lists */
170 found
|= FindResidentCommand(commandName
);
171 D(bug("Resident list\n"));
174 if(!found
&& !resOnly
)
176 /* Check all available paths */
177 found
|= FindCommandinPath(commandName
, checkAll
, fib
);
181 if(!found
&& !resOnly
)
183 /* Check C: multiassign */
184 found
|= FindCommandinC(commandName
, checkAll
, fib
);
194 FreeDosObject(DOS_FIB
, fib
);
201 PrintFault(IoErr(), "Which");
209 /* NOTE: The filesystemtask stuff is only necessary for this to work
210 correctly on AmigaOS. AROS doesn't use this concept. */
211 static BOOL
FindCommandinC(STRPTR name
, BOOL checkAll
, struct FileInfoBlock
*fib
)
213 BOOL found
= FALSE
; /* Object found? */
214 struct DevProc
*dp
= NULL
; /* For GetDeviceProc() call */
215 BPTR oldCurDir
; /* Temporary holder of old current dir */
216 // struct MsgPort *oldFST; /* Temporary holder of old FileSysTask */
218 /* If FilePart(name) is not name itself, it can't be in the C: directory;
219 or rather, it isn't in the C: directory or we found it in
220 FindCommandinPath(). */
221 if(FilePart(name
) != name
)
224 oldCurDir
= CurrentDir(BNULL
); /* Just to save the old current dir... */
225 // oldFST = GetFileSysTask(); /* ... and the filesystem task */
227 while(((dp
= GetDeviceProc("C:", dp
)) != NULL
) && (!found
|| checkAll
))
229 // SetFileSysTask(dp2->dvp_Port);
230 CurrentDir(dp
->dvp_Lock
);
231 found
|= CheckDirectory(name
, FALSE
, fib
);
233 /* Is this a multi assign? */
234 if(!(dp
->dvp_Flags
& DVPF_ASSIGN
))
238 // SetFileSysTask(oldFST);
239 CurrentDir(oldCurDir
);
246 static BOOL
FindCommandinPath(STRPTR name
, BOOL checkAll
, struct FileInfoBlock
*fib
)
248 BOOL found
; /* Have we found the 'file' yet? */
249 BPTR oldCurDir
; /* Space to store the current dir */
250 BPTR
*paths
; /* Loop variable */
252 struct CommandLineInterface
*cli
= Cli();
253 D(bug("checkAll = %ld\n", checkAll
));
254 /* Can this happen at all? */
258 /* Check the current directory */
259 D(bug("Calling CheckDirectory()\n"));
260 found
= CheckDirectory(name
, FALSE
, fib
);
262 oldCurDir
= CurrentDir(BNULL
);
264 /* Check all paths */
265 paths
= (BPTR
*)BADDR(cli
->cli_CommandDir
);
266 D(bug("paths = 0x%08lx\n", paths
));
268 while((!found
|| checkAll
) && (paths
!= NULL
))
270 CurrentDir(paths
[1]);
272 D(bug("Calling CheckDirectory()\n"));
273 found
|= CheckDirectory(name
, FALSE
, fib
);
275 paths
= (BPTR
*)BADDR(paths
[0]); /* Go on with the next path */
278 CurrentDir(oldCurDir
);
284 static BOOL
FindCommandInAbsolutePath(STRPTR name
, TEXT
*colon
, struct FileInfoBlock
*fib
)
286 BOOL found
; /* Have we found the 'file' yet? */
288 if (*(colon
+ 1) == '\0')
290 /* In case path ends with ':' we print the directory */
291 D(bug("Path ends with ':'\n"));
292 /* Check the current directory */
293 D(bug("Calling CheckDirectory()\n"));
294 found
= CheckDirectory(name
, TRUE
, fib
);
298 /* Check the current directory */
299 D(bug("Calling CheckDirectory()\n"));
300 found
= CheckDirectory(name
, FALSE
, fib
);
307 static BOOL
CheckDirectory(STRPTR name
, BOOL directory
, struct FileInfoBlock
*fib
)
309 BPTR lock
; /* Lock on 'name' */
310 BOOL found
= FALSE
; /* For return value purposes */
313 lock
= Lock(name
, SHARED_LOCK
);
315 D(bug("Locked command %s\n", name
));
319 D(bug("Calling Examine()\n"));
321 if(Examine(lock
, fib
) == DOSTRUE
)
323 D(bug("Calling GetFullPath()\n"));
325 pathName
= GetFullPath(lock
);
329 /* File or directory? */
330 if(fib
->fib_DirEntryType
< 0)
332 /* FIBF_EXECUTE is active low! */
333 if(!(fib
->fib_Protection
& FIBF_EXECUTE
))
335 Printf("%s\n", pathName
);
341 Printf("%s\n", pathName
);
345 FreeVec(pathName
); /* Free memory holding the full path name */
356 static STRPTR
GetFullPath(BPTR lock
)
358 UBYTE
*buf
; /* Pointer to the memory allocated for the string */
359 ULONG size
; /* Holder of the (growing) size of the string */
361 for(size
= 512; ; size
+= 512)
363 buf
= AllocVec(size
, MEMF_ANY
);
368 if(NameFromLock(lock
, buf
, size
))
380 static BOOL
FindResidentCommand(STRPTR name
)
382 BOOL found
= FALSE
; /* For return value purposes */
383 struct Segment
*seg
; /* Holder of segment if 'name' is a
386 /* Look in both system and normal list. Or rather, in the normal list
387 ONLY if it wasn't found in the system list. This is what the Amiga
388 Which does thus not giving the whole picture if you have 'cmd'
389 resident while 'cmd' is an internal command also. However, if this
390 is the case, you may never access it as the system list is searched
391 first by the Shell? */
392 if((seg
= FindSegment(name
, NULL
, TRUE
)) == NULL
)
394 seg
= FindSegment(name
, NULL
, FALSE
);
401 if(seg
->seg_UC
== CMD_INTERNAL
)
403 Printf("INTERNAL %s\n", name
);
405 else if(seg
->seg_UC
== CMD_DISABLED
)
407 Printf("INTERNAL %s ;(DISABLED)\n", name
);
410 Printf("RES %s\n", name
);