1 /* Guts of POSIX spawn interface. Generic POSIX.1 version.
2 Copyright (C) 2000-2006, 2008-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
22 #include "spawn_int.h"
29 # define O_LARGEFILE 0
32 #if _LIBC || HAVE_PATHS_H
35 # define _PATH_BSHELL BOURNE_SHELL
44 # include <not-cancel.h>
46 # define close_not_cancel close
47 # define open_not_cancel open
51 # include <local-setxid.h>
54 # define seteuid(id) setresuid (-1, id, -1)
57 # define setegid(id) setresgid (-1, id, -1)
59 # define local_seteuid(id) seteuid (id)
60 # define local_setegid(id) setegid (id)
64 # define alloca __alloca
65 # define execve __execve
68 # define getgid __getgid
69 # define getuid __getuid
70 # define sched_setparam __sched_setparam
71 # define sched_setscheduler __sched_setscheduler
72 # define setpgid __setpgid
73 # define sigaction __sigaction
74 # define sigismember __sigismember
75 # define sigprocmask __sigprocmask
76 # define strchrnul __strchrnul
77 # define vfork __vfork
81 /* The Unix standard contains a long explanation of the way to signal
82 an error after the fork() was successful. Since no new wait status
83 was wanted there is no way to signal an error using one of the
84 available methods. The committee chose to signal an error by a
85 normal program exit with the exit code 127. */
86 #define SPAWN_ERROR 127
89 #if defined _WIN32 && ! defined __CYGWIN__
90 /* Native Windows API. */
92 /* Get declarations of the native Windows API functions. */
93 # define WIN32_LEAN_AND_MEAN
99 # include "filename.h"
100 # include "concat-filename.h"
101 # include "findprog.h"
102 # include "malloca.h"
103 # include "windows-spawn.h"
105 /* Don't assume that UNICODE is not defined. */
107 # define CreateFile CreateFileA
109 # define STARTUPINFO STARTUPINFOA
110 # undef CreateProcess
111 # define CreateProcess CreateProcessA
113 /* Grows inh_handles->count so that it becomes > newfd.
114 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
117 grow_inheritable_handles (struct inheritable_handles *inh_handles, int newfd)
119 if (inh_handles->allocated <= newfd)
121 size_t new_allocated = 2 * inh_handles->allocated + 1;
122 if (new_allocated <= newfd)
123 new_allocated = newfd + 1;
124 HANDLE *new_handles_array =
126 realloc (inh_handles->handles, new_allocated * sizeof (HANDLE));
127 if (new_handles_array == NULL)
132 unsigned char *new_flags_array =
134 realloc (inh_handles->flags, new_allocated * sizeof (unsigned char));
135 if (new_flags_array == NULL)
137 free (new_handles_array);
141 inh_handles->allocated = new_allocated;
142 inh_handles->handles = new_handles_array;
143 inh_handles->flags = new_flags_array;
146 HANDLE *handles = inh_handles->handles;
148 for (; inh_handles->count <= newfd; inh_handles->count++)
149 handles[inh_handles->count] = INVALID_HANDLE_VALUE;
154 /* Reduces inh_handles->count to the minimum needed. */
156 shrink_inheritable_handles (struct inheritable_handles *inh_handles)
158 HANDLE *handles = inh_handles->handles;
160 while (inh_handles->count > 3
161 && handles[inh_handles->count - 1] == INVALID_HANDLE_VALUE)
162 inh_handles->count--;
165 /* Closes all handles in inh_handles. */
167 close_inheritable_handles (struct inheritable_handles *inh_handles)
169 HANDLE *handles = inh_handles->handles;
170 size_t handles_count = inh_handles->count;
173 for (fd = 0; fd < handles_count; fd++)
175 HANDLE handle = handles[fd];
177 if (handle != INVALID_HANDLE_VALUE)
178 CloseHandle (handle);
182 /* Tests whether a memory region, starting at P and N bytes long, contains only
185 memiszero (const void *p, size_t n)
188 for (; n > 0; cp++, n--)
194 /* Tests whether *S contains no signals. */
196 sigisempty (const sigset_t *s)
198 return memiszero (s, sizeof (sigset_t));
201 /* Opens a HANDLE to a file.
202 Upon failure, returns INVALID_HANDLE_VALUE with errno set. */
204 open_handle (const char *name, int flags, mode_t mode)
206 /* To ease portability. Like in open.c. */
207 if (strcmp (name, "/dev/null") == 0)
210 /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>
211 specifies: "More than two leading <slash> characters shall be treated as
212 a single <slash> character." */
213 if (ISSLASH (name[0]) && ISSLASH (name[1]) && ISSLASH (name[2]))
216 while (ISSLASH (name[1]))
220 size_t len = strlen (name);
221 size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0);
223 /* Remove trailing slashes (except the very first one, at position
224 drive_prefix_len), but remember their presence. */
226 bool check_dir = false;
229 while (rlen > drive_prefix_len && ISSLASH (name[rlen-1]))
232 if (rlen == drive_prefix_len + 1)
237 /* Handle '' and 'C:'. */
238 if (!check_dir && rlen == drive_prefix_len)
241 return INVALID_HANDLE_VALUE;
245 if (rlen == 1 && ISSLASH (name[0]) && len >= 2)
248 return INVALID_HANDLE_VALUE;
256 malloca_rname = NULL;
260 malloca_rname = malloca (rlen + 1);
261 if (malloca_rname == NULL)
264 return INVALID_HANDLE_VALUE;
266 memcpy (malloca_rname, name, rlen);
267 malloca_rname[rlen] = '\0';
268 rname = malloca_rname;
271 /* For the meaning of the flags, see
272 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/open-wopen> */
273 /* Open a handle to the file.
275 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea>
276 <https://docs.microsoft.com/en-us/windows/desktop/FileIO/creating-and-opening-files> */
279 ((flags & (O_WRONLY | O_RDWR)) != 0
280 ? GENERIC_READ | GENERIC_WRITE
282 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
284 ((flags & O_CREAT) != 0
285 ? ((flags & O_EXCL) != 0
287 : ((flags & O_TRUNC) != 0 ? CREATE_ALWAYS : OPEN_ALWAYS))
288 : ((flags & O_TRUNC) != 0
291 /* FILE_FLAG_BACKUP_SEMANTICS is useful for opening directories,
292 which is out-of-scope here. */
293 /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only
294 in case as different) makes sense only when applied to *all*
295 filesystem operations. */
296 /* FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS */
297 FILE_ATTRIBUTE_NORMAL
298 | ((flags & O_TEMPORARY) != 0 ? FILE_FLAG_DELETE_ON_CLOSE : 0)
299 | ((flags & O_SEQUENTIAL ) != 0 ? FILE_FLAG_SEQUENTIAL_SCAN : 0)
300 | ((flags & O_RANDOM) != 0 ? FILE_FLAG_RANDOM_ACCESS : 0),
302 if (handle == INVALID_HANDLE_VALUE)
303 switch (GetLastError ())
305 /* Some of these errors probably cannot happen with the specific flags
306 that we pass to CreateFile. But who knows... */
307 case ERROR_FILE_NOT_FOUND: /* The last component of rname does not exist. */
308 case ERROR_PATH_NOT_FOUND: /* Some directory component in rname does not exist. */
309 case ERROR_BAD_PATHNAME: /* rname is such as '\\server'. */
310 case ERROR_BAD_NETPATH: /* rname is such as '\\nonexistentserver\share'. */
311 case ERROR_BAD_NET_NAME: /* rname is such as '\\server\nonexistentshare'. */
312 case ERROR_INVALID_NAME: /* rname contains wildcards, misplaced colon, etc. */
313 case ERROR_DIRECTORY:
317 case ERROR_ACCESS_DENIED: /* rname is such as 'C:\System Volume Information\foo'. */
318 case ERROR_SHARING_VIOLATION: /* rname is such as 'C:\pagefile.sys'. */
319 /* XXX map to EACCES or EPERM? */
323 case ERROR_OUTOFMEMORY:
327 case ERROR_WRITE_PROTECT:
331 case ERROR_WRITE_FAULT:
332 case ERROR_READ_FAULT:
333 case ERROR_GEN_FAILURE:
337 case ERROR_BUFFER_OVERFLOW:
338 case ERROR_FILENAME_EXCED_RANGE:
339 errno = ENAMETOOLONG;
342 case ERROR_DELETE_PENDING: /* XXX map to EACCES or EPERM? */
351 if (malloca_rname != NULL)
353 int saved_errno = errno;
354 freea (malloca_rname);
360 /* Executes an 'open' action.
361 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
364 do_open (struct inheritable_handles *inh_handles, int newfd,
365 const char *filename, const char *directory,
366 int flags, mode_t mode, HANDLE curr_process)
368 if (!(newfd >= 0 && newfd < _getmaxstdio ()))
373 if (grow_inheritable_handles (inh_handles, newfd) < 0)
375 if (inh_handles->handles[newfd] != INVALID_HANDLE_VALUE
376 && !CloseHandle (inh_handles->handles[newfd]))
381 if (filename == NULL)
386 char *filename_to_free = NULL;
387 if (directory != NULL && IS_RELATIVE_FILE_NAME (filename))
389 char *real_filename = concatenated_filename (directory, filename, NULL);
390 if (real_filename == NULL)
395 filename = real_filename;
396 filename_to_free = real_filename;
398 HANDLE handle = open_handle (filename, flags, mode);
399 if (handle == INVALID_HANDLE_VALUE)
401 free (filename_to_free);
404 free (filename_to_free);
405 /* Duplicate the handle, so that it becomes inheritable. */
406 if (!DuplicateHandle (curr_process, handle,
407 curr_process, &inh_handles->handles[newfd],
409 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
411 errno = EBADF; /* arbitrary */
414 inh_handles->flags[newfd] = ((flags & O_APPEND) != 0 ? 32 : 0);
418 /* Executes a 'dup2' action.
419 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
422 do_dup2 (struct inheritable_handles *inh_handles, int oldfd, int newfd,
425 if (!(oldfd >= 0 && oldfd < inh_handles->count
426 && inh_handles->handles[oldfd] != INVALID_HANDLE_VALUE))
431 if (!(newfd >= 0 && newfd < _getmaxstdio ()))
438 if (grow_inheritable_handles (inh_handles, newfd) < 0)
440 if (inh_handles->handles[newfd] != INVALID_HANDLE_VALUE
441 && !CloseHandle (inh_handles->handles[newfd]))
446 /* Duplicate the handle, so that it a forthcoming do_close action on oldfd
447 has no effect on newfd. */
448 if (!DuplicateHandle (curr_process, inh_handles->handles[oldfd],
449 curr_process, &inh_handles->handles[newfd],
450 0, TRUE, DUPLICATE_SAME_ACCESS))
452 errno = EBADF; /* arbitrary */
455 inh_handles->flags[newfd] = 0;
460 /* Executes a 'close' action.
461 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
464 do_close (struct inheritable_handles *inh_handles, int fd)
466 if (!(fd >= 0 && fd < inh_handles->count
467 && inh_handles->handles[fd] != INVALID_HANDLE_VALUE))
472 if (!CloseHandle (inh_handles->handles[fd]))
477 inh_handles->handles[fd] = INVALID_HANDLE_VALUE;
482 __spawni (pid_t *pid, const char *prog_filename,
483 const posix_spawn_file_actions_t *file_actions,
484 const posix_spawnattr_t *attrp, const char *const prog_argv[],
485 const char *const envp[], int use_path)
487 /* Validate the arguments. */
488 if (prog_filename == NULL
490 && ((attrp->_flags & ~POSIX_SPAWN_SETPGROUP) != 0
492 || ! sigisempty (&attrp->_sd)
493 || ! sigisempty (&attrp->_ss)
494 || attrp->_sp.sched_priority != 0
495 || attrp->_policy != 0)))
498 /* Process group handling:
499 Native Windows does not have the concept of process group, but it has the
500 concept of a console attached to a process.
501 So, we interpret the three cases as follows:
502 - Flag POSIX_SPAWN_SETPGROUP not set: Means, the child process is in the
503 same process group as the parent process. We interpret this as a
504 request to reuse the same console.
505 - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp == 0: Means the child
506 process starts a process group of its own. See
507 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
508 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgrp.html>
509 We interpret this as a request to detach from the current console.
510 - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp != 0: Means the child
511 process joins another, existing process group. See
512 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
513 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html>
514 We don't support this case; it produces error EINVAL above. */
515 /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags> */
516 DWORD process_creation_flags =
517 (attrp != NULL && (attrp->_flags & POSIX_SPAWN_SETPGROUP) != 0 ? DETACHED_PROCESS : 0);
519 char *argv_mem_to_free;
520 const char **argv = prepare_spawn (prog_argv, &argv_mem_to_free);
522 return errno; /* errno is set here */
525 /* Compose the command. */
526 char *command = compose_command (argv);
529 free (argv_mem_to_free);
533 /* Copy *ENVP into a contiguous block of memory. */
539 envblock = compose_envblock (envp);
540 if (envblock == NULL)
543 free (argv_mem_to_free);
548 /* Set up the array of handles to inherit.
549 Duplicate each handle, so that a spawn_do_close action (below) has no
550 effect on the file descriptors of the current process. Alternatively,
551 we could store, for each handle, a bit that tells whether it is shared
552 with the current process. But this is simpler. */
553 struct inheritable_handles inh_handles;
554 if (init_inheritable_handles (&inh_handles, true) < 0)
557 /* Directory in which to execute the new process. */
558 const char *directory = NULL;
560 /* Execute the file_actions, modifying the inh_handles instead of the
561 file descriptors of the current process. */
562 if (file_actions != NULL)
564 HANDLE curr_process = GetCurrentProcess ();
567 for (cnt = 0; cnt < file_actions->_used; ++cnt)
569 struct __spawn_action *action = &file_actions->_actions[cnt];
575 int fd = action->action.close_action.fd;
576 if (do_close (&inh_handles, fd) < 0)
583 int newfd = action->action.open_action.fd;
584 const char *filename = action->action.open_action.path;
585 int flags = action->action.open_action.oflag;
586 mode_t mode = action->action.open_action.mode;
587 if (do_open (&inh_handles, newfd, filename, directory,
588 flags, mode, curr_process)
596 int oldfd = action->action.dup2_action.fd;
597 int newfd = action->action.dup2_action.newfd;
598 if (do_dup2 (&inh_handles, oldfd, newfd, curr_process) < 0)
605 char *newdir = action->action.chdir_action.path;
606 if (directory != NULL && IS_RELATIVE_FILE_NAME (newdir))
608 newdir = concatenated_filename (directory, newdir, NULL);
619 case spawn_do_fchdir:
620 /* Not supported in this implementation. */
627 /* Reduce inh_handles.count to the minimum needed. */
628 shrink_inheritable_handles (&inh_handles);
631 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
633 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
635 sinfo.cb = sizeof (STARTUPINFO);
636 sinfo.lpReserved = NULL;
637 sinfo.lpDesktop = NULL;
638 sinfo.lpTitle = NULL;
639 if (compose_handles_block (&inh_handles, &sinfo) < 0)
642 /* Perform the PATH search now, considering the final DIRECTORY. */
643 char *resolved_prog_filename_to_free = NULL;
645 const char *resolved_prog_filename =
646 find_in_given_path (prog_filename, use_path ? getenv ("PATH") : "",
648 if (resolved_prog_filename == NULL)
650 if (resolved_prog_filename != prog_filename)
651 resolved_prog_filename_to_free = (char *) resolved_prog_filename;
652 prog_filename = resolved_prog_filename;
655 PROCESS_INFORMATION pinfo;
656 if (!CreateProcess (prog_filename, command, NULL, NULL, TRUE,
657 process_creation_flags, envblock, directory, &sinfo,
660 DWORD error = GetLastError ();
662 free (resolved_prog_filename_to_free);
663 free (sinfo.lpReserved2);
664 close_inheritable_handles (&inh_handles);
665 free_inheritable_handles (&inh_handles);
668 free (argv_mem_to_free);
670 return convert_CreateProcess_error (error);
674 CloseHandle (pinfo.hThread);
676 free (resolved_prog_filename_to_free);
677 free (sinfo.lpReserved2);
678 close_inheritable_handles (&inh_handles);
679 free_inheritable_handles (&inh_handles);
682 free (argv_mem_to_free);
685 *pid = (intptr_t) pinfo.hProcess;
690 int saved_errno = errno;
691 free (sinfo.lpReserved2);
692 close_inheritable_handles (&inh_handles);
693 free_inheritable_handles (&inh_handles);
696 free (argv_mem_to_free);
702 int saved_errno = errno;
703 close_inheritable_handles (&inh_handles);
704 free_inheritable_handles (&inh_handles);
707 free (argv_mem_to_free);
714 free (argv_mem_to_free);
721 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
722 Before running the process perform the actions described in FILE-ACTIONS. */
724 __spawni (pid_t *pid, const char *file,
725 const posix_spawn_file_actions_t *file_actions,
726 const posix_spawnattr_t *attrp, const char *const argv[],
727 const char *const envp[], int use_path)
730 char *path, *p, *name;
735 short int flags = attrp == NULL ? 0 : attrp->_flags;
738 "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */
741 /* Generate the new process. */
743 if ((flags & POSIX_SPAWN_USEVFORK) != 0
744 /* If no major work is done, allow using vfork. Note that we
745 might perform the path searching. But this would be done by
746 a call to execvp(), too, and such a call must be OK according
748 || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
749 | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
750 | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
751 && file_actions == NULL))
762 /* The call was successful. Store the PID if necessary. */
769 /* Set signal mask. */
770 if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
771 && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
774 /* Set signal default action. */
775 if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
777 /* We have to iterate over all signals. This could possibly be
778 done better but it requires system specific solutions since
779 the sigset_t data type can be very different on different
784 memset (&sa, '\0', sizeof (sa));
785 sa.sa_handler = SIG_DFL;
787 for (sig = 1; sig <= NSIG; ++sig)
788 if (sigismember (&attrp->_sd, sig) != 0
789 && sigaction (sig, &sa, NULL) != 0)
794 #if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
795 /* Set the scheduling algorithm and parameters. */
796 if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
797 == POSIX_SPAWN_SETSCHEDPARAM)
799 if (sched_setparam (0, &attrp->_sp) == -1)
802 else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
804 if (sched_setscheduler (0, attrp->_policy,
805 (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
806 ? &attrp->_sp : NULL) == -1)
811 /* Set the process group ID. */
812 if ((flags & POSIX_SPAWN_SETPGROUP) != 0
813 && setpgid (0, attrp->_pgrp) != 0)
816 /* Set the effective user and group IDs. */
817 if ((flags & POSIX_SPAWN_RESETIDS) != 0
818 && (local_seteuid (getuid ()) != 0
819 || local_setegid (getgid ()) != 0))
822 /* Execute the file actions. */
823 if (file_actions != NULL)
827 for (cnt = 0; cnt < file_actions->_used; ++cnt)
829 struct __spawn_action *action = &file_actions->_actions[cnt];
834 if (close_not_cancel (action->action.close_action.fd) != 0)
835 /* Signal the error. */
841 int new_fd = open_not_cancel (action->action.open_action.path,
842 action->action.open_action.oflag
844 action->action.open_action.mode);
847 /* The 'open' call failed. */
850 /* Make sure the desired file descriptor is used. */
851 if (new_fd != action->action.open_action.fd)
853 if (dup2 (new_fd, action->action.open_action.fd)
854 != action->action.open_action.fd)
855 /* The 'dup2' call failed. */
858 if (close_not_cancel (new_fd) != 0)
859 /* The 'close' call failed. */
866 if (dup2 (action->action.dup2_action.fd,
867 action->action.dup2_action.newfd)
868 != action->action.dup2_action.newfd)
869 /* The 'dup2' call failed. */
874 if (chdir (action->action.chdir_action.path) < 0)
875 /* The 'chdir' call failed. */
879 case spawn_do_fchdir:
880 if (fchdir (action->action.fchdir_action.fd) < 0)
881 /* The 'fchdir' call failed. */
888 if (! use_path || strchr (file, '/') != NULL)
890 /* The FILE parameter is actually a path. */
891 execve (file, (char * const *) argv, (char * const *) envp);
893 /* Oh, oh. 'execve' returns. This is bad. */
897 /* We have to search for FILE on the path. */
898 path = getenv ("PATH");
902 /* There is no 'PATH' in the environment.
903 The default search path is the current directory
904 followed by the path 'confstr' returns for '_CS_PATH'. */
905 len = confstr (_CS_PATH, (char *) NULL, 0);
906 path = (char *) alloca (1 + len);
908 (void) confstr (_CS_PATH, path + 1, len);
910 /* Pretend that the PATH contains only the current directory. */
915 len = strlen (file) + 1;
916 pathlen = strlen (path);
917 name = alloca (pathlen + len + 1);
918 /* Copy the file name at the top. */
919 name = (char *) memcpy (name + pathlen + 1, file, len);
920 /* And add the slash. */
929 p = strchrnul (path, ':');
932 /* Two adjacent colons, or a colon at the beginning or the end
933 of 'PATH' means to search the current directory. */
936 startp = (char *) memcpy (name - (p - path), path, p - path);
938 /* Try to execute this name. If it works, execv will not return. */
939 execve (startp, (char * const *) argv, (char * const *) envp);
947 /* Those errors indicate the file is missing or not executable
948 by us, in which case we want to just try the next path
953 /* Some other error means we found an executable file, but
954 something went wrong executing it; return the error to our
959 while (*p++ != '\0');
961 /* Return with an error. */