17aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley/* which.c - Find executable files in $PATH.
20a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley *
30a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley * Copyright 2006 Rob landley <rob@landley.net>
40a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
559f490cb4e18960e7ddd003f9a66005eccc5ebd7Rob LandleyUSE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
655928b1e0a08d84a5cbc50020f0a8c1024f5b6ceRob Landley
72896480c4918f2accccb8301bec457a7bff7377eRob Landleyconfig WHICH
87aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  bool "which"
97aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  default y
107aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  help
117aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    usage: which [-a] filename ...
122896480c4918f2accccb8301bec457a7bff7377eRob Landley
137aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    Search $PATH for executable files matching filename(s).
142896480c4918f2accccb8301bec457a7bff7377eRob Landley
157aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    -a	Show all matches
162896480c4918f2accccb8301bec457a7bff7377eRob Landley*/
170a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley#include "toys.h"
180a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
190a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley// Find an exectuable file either at a path with a slash in it (absolute or
200a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley// relative to current directory), or in $PATH.  Returns absolute path to file,
210a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley// or NULL if not found.
220a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
230a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landleystatic int which_in_path(char *filename)
240a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley{
257aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  struct string_list *list;
260a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
277aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  // If they gave us a path, don't worry about $PATH or -a
280a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
297aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  if (strchr(filename, '/')) {
307aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    // Confirm it has the executable bit set, and it's not a directory.
317aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    if (!access(filename, X_OK)) {
327aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley      struct stat st;
330a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
347aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley      if (!stat(filename, &st) && S_ISREG(st.st_mode)) {
357aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley        puts(filename);
367aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley        return 0;
377aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley      }
387aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley      return 1;
397aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    }
407aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  }
410a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
427aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  // Search $PATH for matches.
437aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  list = find_in_path(getenv("PATH"), filename);
447aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  if (!list) return 1;
450a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
467aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  // Print out matches
477aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  while (list) {
487aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    if (!access(list->str, X_OK)) {
497aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley      puts(list->str);
507aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley      // If we should stop at one match, do so
517aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley      if (!toys.optflags) {
527aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley        llist_traverse(list, free);
537aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley        break;
547aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley      }
557aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    }
567aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    free(llist_pop(&list));
577aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  }
580a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
597aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  return 0;
600a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley}
610a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley
62efda21ca931766eed6cfc49d1b2122c53827d9fcRob Landleyvoid which_main(void)
630a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley{
647aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  int i;
657aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley
667aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley  for (i=0; toys.optargs[i]; i++)
677aa651a6a4496d848f86de9b1e6b3a003256a01fRob Landley    toys.exitval |= which_in_path(toys.optargs[i]);
680a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2Rob Landley}
69