char *getenv(const char *name) { size_t l = __strchrnul(name, '=') - name; if (l && !name[l] && __environ) for (char **e = __environ; *e; e++) if (!strncmp(name, *e, l) && l[*e] == '=') return *e + l+1; return 0; }
int ether_line (const char *line, struct ether_addr *addr, char *hostname) { size_t cnt; char *cp; for (cnt = 0; cnt < 6; ++cnt) { unsigned int number; char ch; ch = _tolower (*line++); if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f')) return -1; number = isdigit (ch) ? (ch - '0') : (ch - 'a' + 10); ch = _tolower (*line); if ((cnt < 5 && ch != ':') || (cnt == 5 && ch != '\0' && !isspace (ch))) { ++line; if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f')) return -1; number <<= 4; number += isdigit (ch) ? (ch - '0') : (ch - 'a' + 10); ch = *line; if (cnt < 5 && ch != ':') return -1; } /* Store result. */ addr->ether_addr_octet[cnt] = (unsigned char) number; /* Skip ':'. */ if (ch != '\0') ++line; } /* Remove trailing white space. */ cp = __strchrnul (line, '#'); while (cp > line && isspace (cp[-1])) --cp; if (cp == line) /* No hostname. */ return -1; /* XXX This can cause trouble because the hostname might be too long but we have no possibility to check it here. */ memcpy (hostname, line, cp - line); hostname [cp - line] = '\0'; return 0; }
size_t strcspn(const char *s, const char *c) { const char *a = s; size_t byteset[32/sizeof(size_t)]; if (!c[0] || !c[1]) return __strchrnul(s, *c)-a; memset(byteset, 0, sizeof byteset); for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++); for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++); return s-a; }
char *__shm_mapname(const char *name, char *buf) { char *p; while (*name == '/') name++; if (*(p = __strchrnul(name, '/')) || p==name || (p-name <= 2 && name[0]=='.' && p[-1]=='.')) { errno = EINVAL; return 0; } if (p-name > NAME_MAX) { errno = ENAMETOOLONG; return 0; } memcpy(buf, "/dev/shm/", 9); memcpy(buf+9, name, p-name+1); return buf; }
/* Parse comma separated suboption from *OPTIONP and match against strings in TOKENS. If found return index and set *VALUEP to optional value introduced by an equal sign. If the suboption is not part of TOKENS return in *VALUEP beginning of unknown suboption. On exit *OPTIONP is set to the beginning of the next token or at the terminating NUL character. */ int getsubopt (char **optionp, char *const *tokens, char **valuep) { char *endp, *vstart; int cnt; if (**optionp == '\0') return -1; /* Find end of next token. */ endp = __strchrnul (*optionp, ','); /* Find start of value. */ vstart = memchr (*optionp, '=', endp - *optionp); if (vstart == NULL) vstart = endp; /* Try to match the characters between *OPTIONP and VSTART against one of the TOKENS. */ for (cnt = 0; tokens[cnt] != NULL; ++cnt) if (strncmp (*optionp, tokens[cnt], vstart - *optionp) == 0 && tokens[cnt][vstart - *optionp] == '\0') { /* We found the current option in TOKENS. */ *valuep = vstart != endp ? vstart + 1 : NULL; if (*endp != '\0') *endp++ = '\0'; *optionp = endp; return cnt; } /* The current suboption does not match any option. */ *valuep = *optionp; if (*endp != '\0') *endp++ = '\0'; *optionp = endp; return -1; }
/* Return the length of the maximum initial segment of S which contains no characters from REJECT. */ size_t STRCSPN (const char *str, const char *reject) { if (__glibc_unlikely (reject[0] == '\0') || __glibc_unlikely (reject[1] == '\0')) return __strchrnul (str, reject [0]) - str; /* Use multiple small memsets to enable inlining on most targets. */ unsigned char table[256]; unsigned char *p = memset (table, 0, 64); memset (p + 64, 0, 64); memset (p + 128, 0, 64); memset (p + 192, 0, 64); unsigned char *s = (unsigned char*) reject; unsigned char tmp; do p[tmp = *s++] = 1; while (tmp); s = (unsigned char*) str; if (p[s[0]]) return 0; if (p[s[1]]) return 1; if (p[s[2]]) return 2; if (p[s[3]]) return 3; s = (unsigned char *) PTR_ALIGN_DOWN (s, 4); unsigned int c0, c1, c2, c3; do { s += 4; c0 = p[s[0]]; c1 = p[s[1]]; c2 = p[s[2]]; c3 = p[s[3]]; } while ((c0 | c1 | c2 | c3) == 0); size_t count = s - (unsigned char *) str; return (c0 | c1) != 0 ? count - c0 + 1 : count - c2 + 3; }
char * __old_strchrnul_g (const char *s, int c) { return __strchrnul (s, c); }
_IO_FILE * _IO_new_file_fopen (_IO_FILE *fp, const char *filename, const char *mode, int is32not64) { int oflags = 0, omode; int read_write; int oprot = 0666; int i; _IO_FILE *result; #ifdef _LIBC const char *cs; const char *last_recognized; #endif if (_IO_file_is_open (fp)) return 0; switch (*mode) { case 'r': omode = O_RDONLY; read_write = _IO_NO_WRITES; break; case 'w': omode = O_WRONLY; oflags = O_CREAT|O_TRUNC; read_write = _IO_NO_READS; break; case 'a': omode = O_WRONLY; oflags = O_CREAT|O_APPEND; read_write = _IO_NO_READS|_IO_IS_APPENDING; break; default: __set_errno (EINVAL); return NULL; } #ifdef _LIBC last_recognized = mode; #endif for (i = 1; i < 7; ++i) { switch (*++mode) { case '\0': break; case '+': omode = O_RDWR; read_write &= _IO_IS_APPENDING; #ifdef _LIBC last_recognized = mode; #endif continue; case 'x': oflags |= O_EXCL; #ifdef _LIBC last_recognized = mode; #endif continue; case 'b': #ifdef _LIBC last_recognized = mode; #endif continue; case 'm': fp->_flags2 |= _IO_FLAGS2_MMAP; continue; case 'c': fp->_flags2 |= _IO_FLAGS2_NOTCANCEL; continue; case 'e': #ifdef O_CLOEXEC oflags |= O_CLOEXEC; #endif fp->_flags2 |= _IO_FLAGS2_CLOEXEC; continue; default: /* Ignore. */ continue; } break; } result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write, is32not64); if (result != NULL) { #ifndef __ASSUME_O_CLOEXEC if ((fp->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 && __have_o_cloexec <= 0) { int fd = _IO_fileno (fp); if (__have_o_cloexec == 0) { int flags = __fcntl (fd, F_GETFD); __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1; } if (__have_o_cloexec < 0) __fcntl (fd, F_SETFD, FD_CLOEXEC); } #endif /* Test whether the mode string specifies the conversion. */ cs = strstr (last_recognized + 1, ",ccs="); if (cs != NULL) { /* Yep. Load the appropriate conversions and set the orientation to wide. */ struct gconv_fcts fcts; struct _IO_codecvt *cc; char *endp = __strchrnul (cs + 5, ','); char *ccs = malloc (endp - (cs + 5) + 3); if (ccs == NULL) { int malloc_err = errno; /* Whatever malloc failed with. */ (void) _IO_file_close_it (fp); __set_errno (malloc_err); return NULL; } *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0'; strip (ccs, ccs); if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0' ? upstr (ccs, cs + 5) : ccs) != 0) { /* Something went wrong, we cannot load the conversion modules. This means we cannot proceed since the user explicitly asked for these. */ (void) _IO_file_close_it (fp); free (ccs); __set_errno (EINVAL); return NULL; } free (ccs); assert (fcts.towc_nsteps == 1); assert (fcts.tomb_nsteps == 1); fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end; fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base; /* Clear the state. We start all over again. */ memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t)); memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t)); cc = fp->_codecvt = &fp->_wide_data->_codecvt; /* The functions are always the same. */ *cc = __libio_codecvt; cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps; cc->__cd_in.__cd.__steps = fcts.towc; cc->__cd_in.__cd.__data[0].__invocation_counter = 0; cc->__cd_in.__cd.__data[0].__internal_use = 1; cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST; cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state; cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps; cc->__cd_out.__cd.__steps = fcts.tomb; cc->__cd_out.__cd.__data[0].__invocation_counter = 0; cc->__cd_out.__cd.__data[0].__internal_use = 1; cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST | __GCONV_TRANSLIT; cc->__cd_out.__cd.__data[0].__statep = &result->_wide_data->_IO_state; /* From now on use the wide character callback functions. */ _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable; /* Set the mode now. */ result->_mode = 1; } } return result; }
int putenv(char *s) { size_t l = __strchrnul(s, '=') - s; if (!l || !s[l]) return unsetenv(s); return __putenv(s, l, 0); }
/* Spawn a new process executing PATH with the attributes describes in *ATTRP. Before running the process perform the actions described in FILE-ACTIONS. */ int __spawni (pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[], int xflags) { pid_t new_pid; char *path, *p, *name; size_t len; size_t pathlen; /* Do this once. */ short int flags = attrp == NULL ? 0 : attrp->__flags; /* Generate the new process. */ if ((flags & POSIX_SPAWN_USEVFORK) != 0 /* If no major work is done, allow using vfork. Note that we might perform the path searching. But this would be done by a call to execvp(), too, and such a call must be OK according to POSIX. */ || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0 && file_actions == NULL)) new_pid = __vfork (); else new_pid = __fork (); if (new_pid != 0) { if (new_pid < 0) return errno; /* The call was successful. Store the PID if necessary. */ if (pid != NULL) *pid = new_pid; return 0; } /* Set signal mask. */ if ((flags & POSIX_SPAWN_SETSIGMASK) != 0 && __sigprocmask (SIG_SETMASK, &attrp->__ss, NULL) != 0) _exit (SPAWN_ERROR); /* Set signal default action. */ if ((flags & POSIX_SPAWN_SETSIGDEF) != 0) { /* We have to iterate over all signals. This could possibly be done better but it requires system specific solutions since the sigset_t data type can be very different on different architectures. */ int sig; struct sigaction sa; memset (&sa, '\0', sizeof (sa)); sa.sa_handler = SIG_DFL; for (sig = 1; sig <= _NSIG; ++sig) if (__sigismember (&attrp->__sd, sig) != 0 && __sigaction (sig, &sa, NULL) != 0) _exit (SPAWN_ERROR); } #ifdef _POSIX_PRIORITY_SCHEDULING /* Set the scheduling algorithm and parameters. */ if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER)) == POSIX_SPAWN_SETSCHEDPARAM) { if (__sched_setparam (0, &attrp->__sp) == -1) _exit (SPAWN_ERROR); } else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0) { if (__sched_setscheduler (0, attrp->__policy, &attrp->__sp) == -1) _exit (SPAWN_ERROR); } #endif /* Set the process group ID. */ if ((flags & POSIX_SPAWN_SETPGROUP) != 0 && __setpgid (0, attrp->__pgrp) != 0) _exit (SPAWN_ERROR); /* Set the effective user and group IDs. */ if ((flags & POSIX_SPAWN_RESETIDS) != 0 && (local_seteuid (__getuid ()) != 0 || local_setegid (__getgid ()) != 0)) _exit (SPAWN_ERROR); /* Execute the file actions. */ if (file_actions != NULL) { int cnt; struct rlimit64 fdlimit; bool have_fdlimit = false; for (cnt = 0; cnt < file_actions->__used; ++cnt) { struct __spawn_action *action = &file_actions->__actions[cnt]; switch (action->tag) { case spawn_do_close: if (close_not_cancel (action->action.close_action.fd) != 0) { if (! have_fdlimit) { getrlimit64 (RLIMIT_NOFILE, &fdlimit); have_fdlimit = true; } /* Only signal errors for file descriptors out of range. */ if (action->action.close_action.fd < 0 || action->action.close_action.fd >= fdlimit.rlim_cur) /* Signal the error. */ _exit (SPAWN_ERROR); } break; case spawn_do_open: { int new_fd = open_not_cancel (action->action.open_action.path, action->action.open_action.oflag | O_LARGEFILE, action->action.open_action.mode); if (new_fd == -1) /* The `open' call failed. */ _exit (SPAWN_ERROR); /* Make sure the desired file descriptor is used. */ if (new_fd != action->action.open_action.fd) { if (__dup2 (new_fd, action->action.open_action.fd) != action->action.open_action.fd) /* The `dup2' call failed. */ _exit (SPAWN_ERROR); if (close_not_cancel (new_fd) != 0) /* The `close' call failed. */ _exit (SPAWN_ERROR); } } break; case spawn_do_dup2: if (__dup2 (action->action.dup2_action.fd, action->action.dup2_action.newfd) != action->action.dup2_action.newfd) /* The `dup2' call failed. */ _exit (SPAWN_ERROR); break; } } } if ((xflags & SPAWN_XFLAGS_USE_PATH) == 0 || strchr (file, '/') != NULL) { /* The FILE parameter is actually a path. */ __execve (file, argv, envp); maybe_script_execute (file, argv, envp, xflags); /* Oh, oh. `execve' returns. This is bad. */ _exit (SPAWN_ERROR); } /* We have to search for FILE on the path. */ path = getenv ("PATH"); if (path == NULL) { /* There is no `PATH' in the environment. The default search path is the current directory followed by the path `confstr' returns for `_CS_PATH'. */ len = confstr (_CS_PATH, (char *) NULL, 0); path = (char *) __alloca (1 + len); path[0] = ':'; (void) confstr (_CS_PATH, path + 1, len); } len = strlen (file) + 1; pathlen = strlen (path); name = __alloca (pathlen + len + 1); /* Copy the file name at the top. */ name = (char *) memcpy (name + pathlen + 1, file, len); /* And add the slash. */ *--name = '/'; p = path; do { char *startp; path = p; p = __strchrnul (path, ':'); if (p == path) /* Two adjacent colons, or a colon at the beginning or the end of `PATH' means to search the current directory. */ startp = name + 1; else startp = (char *) memcpy (name - (p - path), path, p - path); /* Try to execute this name. If it works, execv will not return. */ __execve (startp, argv, envp); maybe_script_execute (startp, argv, envp, xflags); switch (errno) { case EACCES: case ENOENT: case ESTALE: case ENOTDIR: /* Those errors indicate the file is missing or not executable by us, in which case we want to just try the next path directory. */ break; default: /* Some other error means we found an executable file, but something went wrong executing it; return the error to our caller. */ _exit (SPAWN_ERROR); } } while (*p++ != '\0'); /* Return with an error. */ _exit (SPAWN_ERROR); }
/* Execute FILE, searching in the `PATH' environment variable if it contains no slashes, with arguments ARGV and environment from ENVP. */ int __execvpe (const char *file, char *const argv[], char *const envp[]) { if (*file == '\0') { /* We check the simple case first. */ __set_errno (ENOENT); return -1; } if (strchr (file, '/') != NULL) { /* Don't search when it contains a slash. */ __execve (file, argv, envp); if (errno == ENOEXEC) { /* Count the arguments. */ int argc = 0; while (argv[argc++]) ; size_t len = (argc + 1) * sizeof (char *); char **script_argv; void *ptr = NULL; if (__libc_use_alloca (len)) script_argv = alloca (len); else script_argv = ptr = malloc (len); if (script_argv != NULL) { scripts_argv (file, argv, argc, script_argv); __execve (script_argv[0], script_argv, envp); free (ptr); } } } else { size_t pathlen; size_t alloclen = 0; char *path = getenv ("PATH"); if (path == NULL) { pathlen = confstr (_CS_PATH, (char *) NULL, 0); alloclen = pathlen + 1; } else pathlen = strlen (path); size_t len = strlen (file) + 1; alloclen += pathlen + len + 1; char *name; char *path_malloc = NULL; if (__libc_use_alloca (alloclen)) name = alloca (alloclen); else { path_malloc = name = malloc (alloclen); if (name == NULL) return -1; } if (path == NULL) { /* There is no `PATH' in the environment. The default search path is the current directory followed by the path `confstr' returns for `_CS_PATH'. */ path = name + pathlen + len + 1; path[0] = ':'; (void) confstr (_CS_PATH, path + 1, pathlen); } /* Copy the file name at the top. */ name = (char *) memcpy (name + pathlen + 1, file, len); /* And add the slash. */ *--name = '/'; char **script_argv = NULL; void *script_argv_malloc = NULL; bool got_eacces = false; char *p = path; do { char *startp; path = p; p = __strchrnul (path, ':'); if (p == path) /* Two adjacent colons, or a colon at the beginning or the end of `PATH' means to search the current directory. */ startp = name + 1; else startp = (char *) memcpy (name - (p - path), path, p - path); /* Try to execute this name. If it works, execve will not return. */ __execve (startp, argv, envp); if (errno == ENOEXEC) { if (script_argv == NULL) { /* Count the arguments. */ int argc = 0; while (argv[argc++]) ; size_t arglen = (argc + 1) * sizeof (char *); if (__libc_use_alloca (alloclen + arglen)) script_argv = alloca (arglen); else script_argv = script_argv_malloc = malloc (arglen); if (script_argv == NULL) { /* A possible EACCES error is not as important as the ENOMEM. */ got_eacces = false; break; } scripts_argv (startp, argv, argc, script_argv); } __execve (script_argv[0], script_argv, envp); } switch (errno) { case EACCES: /* Record the we got a `Permission denied' error. If we end up finding no executable we can use, we want to diagnose that we did find one but were denied access. */ got_eacces = true; case ENOENT: case ESTALE: case ENOTDIR: /* Those errors indicate the file is missing or not executable by us, in which case we want to just try the next path directory. */ case ENODEV: case ETIMEDOUT: /* Some strange filesystems like AFS return even stranger error numbers. They cannot reasonably mean anything else so ignore those, too. */ break; default: /* Some other error means we found an executable file, but something went wrong executing it; return the error to our caller. */ return -1; } } while (*p++ != '\0'); /* We tried every element and none of them worked. */ if (got_eacces) /* At least one failure was due to permissions, so report that error. */ __set_errno (EACCES); free (script_argv_malloc); free (path_malloc); } /* Return the error from the last attempt (probably ENOENT). */ return -1; }
internal_function nss_parse_file (const char *fname) { FILE *fp; name_database *result; name_database_entry *last; char *line; size_t len; /* Open the configuration file. */ fp = fopen (fname, "r"); if (fp == NULL) return NULL; /* No threads use this stream. */ __fsetlocking (fp, FSETLOCKING_BYCALLER); result = (name_database *) malloc (sizeof (name_database)); if (result == NULL) return NULL; result->entry = NULL; result->library = NULL; last = NULL; line = NULL; len = 0; do { name_database_entry *this; ssize_t n; n = __getline (&line, &len, fp); if (n < 0) break; if (line[n - 1] == '\n') line[n - 1] = '\0'; /* Because the file format does not know any form of quoting we can search forward for the next '#' character and if found make it terminating the line. */ *__strchrnul (line, '#') = '\0'; /* If the line is blank it is ignored. */ if (line[0] == '\0') continue; /* Each line completely specifies the actions for a database. */ this = nss_getline (line); if (this != NULL) { if (last != NULL) last->next = this; else result->entry = this; last = this; } } while (!feof_unlocked (fp)); /* Free the buffer. */ free (line); /* Close configuration file. */ fclose (fp); return result; }
static int internal_function internal_fnmatch (const char *pattern, const char *string, int no_leading_period, int flags) { register const char *p = pattern, *n = string; register unsigned char c; /* Note that this evaluates C many times. */ # ifdef _LIBC # define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) # else # define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) # endif while ((c = *p++) != '\0') { c = FOLD (c); switch (c) { case '?': if (*n == '\0') return FNM_NOMATCH; else if (*n == '/' && (flags & FNM_FILE_NAME)) return FNM_NOMATCH; else if (*n == '.' && no_leading_period && (n == string || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) return FNM_NOMATCH; break; case '\\': if (!(flags & FNM_NOESCAPE)) { c = *p++; if (c == '\0') /* Trailing \ loses. */ return FNM_NOMATCH; c = FOLD (c); } if (FOLD ((unsigned char) *n) != c) return FNM_NOMATCH; break; case '*': if (*n == '.' && no_leading_period && (n == string || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) return FNM_NOMATCH; for (c = *p++; c == '?' || c == '*'; c = *p++) { if (*n == '/' && (flags & FNM_FILE_NAME)) /* A slash does not match a wildcard under FNM_FILE_NAME. */ return FNM_NOMATCH; else if (c == '?') { /* A ? needs to match one character. */ if (*n == '\0') /* There isn't another character; no match. */ return FNM_NOMATCH; else /* One character of the string is consumed in matching this ? wildcard, so *??? won't match if there are less than three characters. */ ++n; } } if (c == '\0') /* The wildcard(s) is/are the last element of the pattern. If the name is a file name and contains another slash this does mean it cannot match. */ return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL ? FNM_NOMATCH : 0); else { const char *endp; endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0'); if (c == '[') { int flags2 = ((flags & FNM_FILE_NAME) ? flags : (flags & ~FNM_PERIOD)); for (--p; n < endp; ++n) if (internal_fnmatch (p, n, (no_leading_period && (n == string || (n[-1] == '/' && (flags & FNM_FILE_NAME)))), flags2) == 0) return 0; } else if (c == '/' && (flags & FNM_FILE_NAME)) { while (*n != '\0' && *n != '/') ++n; if (*n == '/' && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD, flags) == 0)) return 0; } else { int flags2 = ((flags & FNM_FILE_NAME) ? flags : (flags & ~FNM_PERIOD)); if (c == '\\' && !(flags & FNM_NOESCAPE)) c = *p; c = FOLD (c); for (--p; n < endp; ++n) if (FOLD ((unsigned char) *n) == c && (internal_fnmatch (p, n, (no_leading_period && (n == string || (n[-1] == '/' && (flags & FNM_FILE_NAME)))), flags2) == 0)) return 0; } } /* If we come here no match is possible with the wildcard. */ return FNM_NOMATCH; case '[': { /* Nonzero if the sense of the character class is inverted. */ static int posixly_correct; register int not; char cold; if (posixly_correct == 0) posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; if (*n == '\0') return FNM_NOMATCH; if (*n == '.' && no_leading_period && (n == string || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) return FNM_NOMATCH; if (*n == '/' && (flags & FNM_FILE_NAME)) /* `/' cannot be matched. */ return FNM_NOMATCH; not = (*p == '!' || (posixly_correct < 0 && *p == '^')); if (not) ++p; c = *p++; for (;;) { unsigned char fn = FOLD ((unsigned char) *n); if (!(flags & FNM_NOESCAPE) && c == '\\') { if (*p == '\0') return FNM_NOMATCH; c = FOLD ((unsigned char) *p); ++p; if (c == fn) goto matched; } else if (c == '[' && *p == ':') { /* Leave room for the null. */ char str[CHAR_CLASS_MAX_LENGTH + 1]; size_t c1 = 0; # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) wctype_t wt; # endif const char *startp = p; for (;;) { if (c1 > CHAR_CLASS_MAX_LENGTH) /* The name is too long and therefore the pattern is ill-formed. */ return FNM_NOMATCH; c = *++p; if (c == ':' && p[1] == ']') { p += 2; break; } if (c < 'a' || c >= 'z') { /* This cannot possibly be a character class name. Match it as a normal range. */ p = startp; c = '['; goto normal_bracket; } str[c1++] = c; } str[c1] = '\0'; # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) wt = IS_CHAR_CLASS (str); if (wt == 0) /* Invalid character class name. */ return FNM_NOMATCH; if (__iswctype (__btowc ((unsigned char) *n), wt)) goto matched; # else if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n)) || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n)) || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n)) || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n)) || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n)) || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n)) || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n)) || (STREQ (str, "print") && ISPRINT ((unsigned char) *n)) || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n)) || (STREQ (str, "space") && ISSPACE ((unsigned char) *n)) || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n)) || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n))) goto matched; # endif } else if (c == '\0') /* [ (unterminated) loses. */ return FNM_NOMATCH; else { normal_bracket: if (FOLD (c) == fn) goto matched; cold = c; c = *p++; if (c == '-' && *p != ']') { /* It is a range. */ unsigned char cend = *p++; if (!(flags & FNM_NOESCAPE) && cend == '\\') cend = *p++; if (cend == '\0') return FNM_NOMATCH; if (cold <= fn && fn <= FOLD (cend)) goto matched; c = *p++; } } if (c == ']') break; } if (!not) return FNM_NOMATCH; break; matched: /* Skip the rest of the [...] that already matched. */ while (c != ']') { if (c == '\0') /* [... (unterminated) loses. */ return FNM_NOMATCH; c = *p++; if (!(flags & FNM_NOESCAPE) && c == '\\') { if (*p == '\0') return FNM_NOMATCH; /* XXX 1003.2d11 is unclear if this is right. */ ++p; } else if (c == '[' && *p == ':') { do if (*++p == '\0') return FNM_NOMATCH; while (*p != ':' || p[1] == ']'); p += 2; c = *p; } } if (not) return FNM_NOMATCH; } break; default: if (c != FOLD ((unsigned char) *n)) return FNM_NOMATCH; } ++n; } if (*n == '\0') return 0; if ((flags & FNM_LEADING_DIR) && *n == '/') /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ return 0; return FNM_NOMATCH; # undef FOLD }
int ruserpass (const char *host, const char **aname, const char **apass) { char *hdir, *buf, *tmp; char myname[1024], *mydomain; int t, usedefault = 0; struct stat64 stb; hdir = __libc_secure_getenv("HOME"); if (hdir == NULL) { /* If we can't get HOME, fail instead of trying ".", which is no improvement. This really should call getpwuid(getuid()). */ /*hdir = ".";*/ return -1; } buf = alloca (strlen (hdir) + 8); __stpcpy (__stpcpy (buf, hdir), "/.netrc"); cfile = fopen(buf, "rce"); if (cfile == NULL) { if (errno != ENOENT) warn("%s", buf); return (0); } /* No threads use this stream. */ __fsetlocking (cfile, FSETLOCKING_BYCALLER); if (__gethostname(myname, sizeof(myname)) < 0) myname[0] = '\0'; mydomain = __strchrnul(myname, '.'); next: while ((t = token())) switch(t) { case DEFAULT: usedefault = 1; /* FALL THROUGH */ case MACHINE: if (!usedefault) { if (token() != ID) continue; /* * Allow match either for user's input host name * or official hostname. Also allow match of * incompletely-specified host in local domain. */ if (__strcasecmp(host, tokval) == 0) goto match; /* if (__strcasecmp(hostname, tokval) == 0) goto match; if ((tmp = strchr(hostname, '.')) != NULL && __strcasecmp(tmp, mydomain) == 0 && __strncasecmp(hostname, tokval, tmp-hostname) == 0 && tokval[tmp - hostname] == '\0') goto match; */ if ((tmp = strchr(host, '.')) != NULL && __strcasecmp(tmp, mydomain) == 0 && __strncasecmp(host, tokval, tmp - host) == 0 && tokval[tmp - host] == '\0') goto match; continue; } match: while ((t = token()) && t != MACHINE && t != DEFAULT) switch(t) { case LOGIN: if (token()) { if (*aname == 0) { char *newp; newp = malloc((unsigned) strlen(tokval) + 1); if (newp == NULL) { warnx(_("out of memory")); goto bad; } *aname = strcpy(newp, tokval); } else { if (strcmp(*aname, tokval)) goto next; } } break; case PASSWD: if (strcmp(*aname, "anonymous") && fstat64(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { warnx(_("Error: .netrc file is readable by others.")); warnx(_("Remove password or make file unreadable by others.")); goto bad; } if (token() && *apass == 0) { char *newp; newp = malloc((unsigned) strlen(tokval) + 1); if (newp == NULL) { warnx(_("out of memory")); goto bad; } *apass = strcpy(newp, tokval); } break; case ACCOUNT: break; case MACDEF: break; default: warnx(_("Unknown .netrc keyword %s"), tokval); break; } goto done; } done: (void) fclose(cfile); return (0); bad: (void) fclose(cfile); return (-1); }