File: execlp.c

package info (click to toggle)
tar 1.12-7
  • links: PTS
  • area: main
  • in suites: slink
  • size: 3,552 kB
  • ctags: 1,623
  • sloc: ansic: 15,401; sh: 898; yacc: 856; lisp: 592; makefile: 336; perl: 111; sed: 93
file content (167 lines) | stat: -rw-r--r-- 4,226 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* Provide an execlp replacement for Minix.
   Copyright (C) 1988, 1994, 1995, 1997 Free Software Foundation, Inc.

   This file is part of GNU Tar.

   GNU Tar is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   GNU Tar is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GNU Tar; see the file COPYING.  If not, write to the Free
   Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
   USA.  */

#if HAVE_CONFIG_H
# include <config.h>
#endif

/* For defining NULL.  */
#include <stdio.h>

#if STDC_HEADERS
# include <stdlib.h>
#else
char *getenv ();
char *malloc ();
#endif

#include <errno.h>
#ifndef errno
extern int errno;
#endif

#include <sys/types.h>
#include <sys/stat.h>

#if STDC_HEADERS || HAVE_STRING_H
# include <string.h>
#else
# include <strings.h>
# ifndef strchr
#  define strchr index
# endif
#endif

/* Synopsis: execlp (file, arg0, arg1... argN, (char *) NULL)

   Exec a program, automatically searching for the program through all the
   directories on the PATH.

   This version is naive about variable argument lists and assumes a quite
   straightforward C calling sequence.  It will not work on systems having
   odd stacks.  */

int
execlp (filename, arg0)
     char *filename;
     char *arg0;
{
  register char *p, *path;
  register char *fnbuffer;
  char **argstart = &arg0;
  struct stat statbuf;
  extern char **environ;

  if (p = getenv ("PATH"), p == NULL)
    {
      /* Could not find path variable -- try to exec given filename.  */

      return execve (filename, argstart, environ);
    }

  /* Make a place to build the filename.  We malloc larger than we need,
     but we know it will fit in this.  */

  fnbuffer = malloc (strlen (p) + 1 + strlen (filename));
  if (fnbuffer == NULL)
    {
      errno = ENOMEM;
      return -1;
    }

  /* Try each component of the path to see if the file's there and
     executable.  */

  for (path = p; path; path = p)
    {

      /* Construct full path name to try.  */

      if (p = strchr (path, ':'), !p)
	strcpy (fnbuffer, path);
      else
	{
	  strncpy (fnbuffer, path, p - path);
	  fnbuffer[p - path] = '\0';
	  p++;			/* skip : for next time */
	}
      if (strlen (fnbuffer) != 0)
	strcat (fnbuffer, "/");
      strcat (fnbuffer, filename);

      /* Check to see if file is there and is a normal file.  */

      if (stat (fnbuffer, &statbuf) < 0)
	{
	  if (errno == ENOENT)
	    continue;		/* file not there,keep on looking */
	  else
	    goto fail;		/* failed for some reason, return */
	}
      if (!S_ISREG (statbuf.st_mode))
	continue;

      if (execve (fnbuffer, argstart, environ) < 0
	  && errno != ENOENT
	  && errno != ENOEXEC)
	{
	  /* Failed, for some other reason besides "file.  */

	  goto fail;
	}

      /* If we got error ENOEXEC, the file is executable but is not an
	 object file.  Try to execute it as a shell script, returning
	 error if we can't execute /bin/sh.

	 FIXME, this code is broken in several ways.  Shell scripts
	 should not in general be executed by the user's SHELL variable
	 program.  On more mature systems, the script can specify with
	 #!/bin/whatever.  Also, this code clobbers argstart[-1] if the
	 exec of the shell fails.  */

      if (errno == ENOEXEC)
	{
	  char *shell;

	  /* Try to execute command "sh arg0 arg1 ...".  */

	  if (shell = getenv ("SHELL"), shell == NULL)
	    shell = "/bin/sh";
	  argstart[-1] = shell;
	  argstart[0] = fnbuffer;
	  execve (shell, &argstart[-1], environ);
	  goto fail;		/* exec didn't work */
	}

      /* If we succeeded, the execve() doesn't return, so we can only be
	 here is if the file hasn't been found yet.  Try the next place
	 on the path.  */

    }

  /* All attempts failed to locate the file.  Give up.  */

  errno = ENOENT;

fail:
  free (fnbuffer);
  return -1;
}