void location_print (FILE *out, location loc) { fprintf (out, "%s:%d.%d", quotearg_n_style (3, escape_quoting_style, loc.start.file), loc.start.line, loc.start.column); if (loc.start.file != loc.end.file) fprintf (out, "-%s:%d.%d", quotearg_n_style (3, escape_quoting_style, loc.end.file), loc.end.line, loc.end.column - 1); else if (loc.start.line < loc.end.line) fprintf (out, "-%d.%d", loc.end.line, loc.end.column - 1); else if (loc.start.column < loc.end.column - 1) fprintf (out, "-%d", loc.end.column - 1); }
void argmatch_invalid (const char *context, const char *value, ptrdiff_t problem) { char const *format = (problem == -1 ? _("invalid argument %s for %s") : _("ambiguous argument %s for %s")); error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value), quote_n (1, context)); }
static const char* partial_quotearg_n (int n, char *s, size_t len, enum quoting_style style) { if (0 == len) { return quotearg_n_style (n, style, ""); } else { char saved; const char *result; saved = s[len]; s[len] = 0; result = quotearg_n_style (n, style, s); s[len] = saved; return result; } }
/* Output to OUT the location LOC. Warning: it uses quotearg's slot 3. */ unsigned location_print (FILE *out, location loc) { unsigned res = 0; int end_col = 0 != loc.end.column ? loc.end.column - 1 : 0; res += fprintf (out, "%s", quotearg_n_style (3, escape_quoting_style, loc.start.file)); if (0 <= loc.start.line) { res += fprintf (out, ":%d", loc.start.line); if (0 <= loc.start.column) res += fprintf (out, ".%d", loc.start.column); } if (loc.start.file != loc.end.file) { res += fprintf (out, "-%s", quotearg_n_style (3, escape_quoting_style, loc.end.file)); if (0 <= loc.end.line) { res += fprintf (out, ":%d", loc.end.line); if (0 <= end_col) res += fprintf (out, ".%d", end_col); } } else if (0 <= loc.end.line) { if (loc.start.line < loc.end.line) { res += fprintf (out, "-%d", loc.end.line); if (0 <= end_col) res += fprintf (out, ".%d", end_col); } else if (0 <= end_col && loc.start.column < end_col) res += fprintf (out, "-%d", end_col); } return res; }
static void process_debug_options(char *arg) { const char *p; char *token_context = NULL; const char delimiters[] = ","; boolean empty = true; size_t i; p = strtok_r(arg, delimiters, &token_context); while (p) { empty = false; for (i=0; i<N_DEBUGASSOC; ++i) { if (0 == strcmp(debugassoc[i].name, p)) { options.debug_options |= debugassoc[i].val; break; } } if (i >= N_DEBUGASSOC) { error(0, 0, _("Ignoring unrecognised debug flag %s"), quotearg_n_style(0, options.err_quoting_style, arg)); } p = strtok_r(NULL, delimiters, &token_context); } if (empty) { error(1, 0, _("Empty argument to the -D option.")); } else if (options.debug_options & DebugHelp) { show_valid_debug_options(stdout, 1); exit(0); } }
/* Get the stat information for a file, if it is * not already known. */ int get_statinfo (const char *pathname, const char *name, struct stat *p) { /* Set markers in fields so we have a good idea if the implementation * didn't bother to set them (e.g., NetBSD st_birthtimespec for MS-DOS * files) */ if (!state.have_stat) { set_stat_placeholders(p); if (0 == (*options.xstat) (name, p)) { if (00000 == p->st_mode) { /* Savannah bug #16378. */ error(0, 0, _("Warning: file %s appears to have mode 0000"), quotearg_n_style(0, options.err_quoting_style, name)); } } else { if (!options.ignore_readdir_race || (errno != ENOENT) ) { error (0, errno, "%s", safely_quote_err_filename(0, pathname)); state.exit_status = 1; } return -1; } } state.have_stat = true; state.have_type = true; state.type = p->st_mode; return 0; }
int launch (struct buildcmd_control *ctl, void *usercontext, int argc, char **argv) { pid_t child_pid; static int first_time = 1; struct exec_val *execp = usercontext; /* Make sure output of command doesn't get mixed with find output. */ fflush (stdout); fflush (stderr); /* Make sure to listen for the kids. */ if (first_time) { first_time = 0; signal (SIGCHLD, SIG_DFL); } child_pid = fork (); if (child_pid == -1) error (EXIT_FAILURE, errno, _("cannot fork")); if (child_pid == 0) { /* We are the child. */ assert (NULL != execp->wd_for_exec); if (!prep_child_for_exec (execp->close_stdin, execp->wd_for_exec)) { _exit (1); } else { if (fd_leak_check_is_enabled ()) { complain_about_leaky_fds (); } } if (bc_args_exceed_testing_limit (argv)) errno = E2BIG; else execvp (argv[0], argv); /* TODO: use a pipe to pass back the errno value, like xargs does */ error (0, errno, "%s", safely_quote_err_filename (0, argv[0])); _exit (1); } while (waitpid (child_pid, &(execp->last_child_status), 0) == (pid_t) -1) { if (errno != EINTR) { error (0, errno, _("error waiting for %s"), safely_quote_err_filename (0, argv[0])); state.exit_status = 1; return 0; /* FAIL */ } } if (WIFSIGNALED (execp->last_child_status)) { error (0, 0, _("%s terminated by signal %d"), quotearg_n_style (0, options.err_quoting_style, argv[0]), WTERMSIG (execp->last_child_status)); if (execp->multiple) { /* -exec \; just returns false if the invoked command fails. * -exec {} + returns true if the invoked command fails, but * sets the program exit status. */ state.exit_status = 1; } return 1; /* OK */ } if (0 == WEXITSTATUS (execp->last_child_status)) { return 1; /* OK */ } else { if (execp->multiple) { /* -exec \; just returns false if the invoked command fails. * -exec {} + returns true if the invoked command fails, but * sets the program exit status. */ state.exit_status = 1; } /* The child failed, but this is the exec callback. We * don't want to run the child again in this case anwyay. */ return 1; /* FAIL (but don't try again) */ } }
static char * quote (char const *name) { return quotearg_n_style (2, c_quoting_style, name); }
static void consider_visiting (FTS *p, FTSENT *ent) { struct stat statbuf; mode_t mode; int ignore, isdir; if (options.debug_options & DebugSearch) fprintf (stderr, "consider_visiting (early): %s: " "fts_info=%-6s, fts_level=%2d, prev_depth=%d " "fts_path=%s, fts_accpath=%s\n", quotearg_n_style (0, options.err_quoting_style, ent->fts_path), get_fts_info_name (ent->fts_info), (int)ent->fts_level, prev_depth, quotearg_n_style (1, options.err_quoting_style, ent->fts_path), quotearg_n_style (2, options.err_quoting_style, ent->fts_accpath)); if (ent->fts_info == FTS_DP) { left_dir (); } else if (ent->fts_level > prev_depth || ent->fts_level==0) { left_dir (); } inside_dir (p->fts_cwd_fd); prev_depth = ent->fts_level; statbuf.st_ino = ent->fts_statp->st_ino; /* Cope with various error conditions. */ if (ent->fts_info == FTS_ERR || ent->fts_info == FTS_DNR) { nonfatal_target_file_error (ent->fts_errno, ent->fts_path); return; } else if (ent->fts_info == FTS_DC) { issue_loop_warning (ent); error_severity (EXIT_FAILURE); return; } else if (ent->fts_info == FTS_SLNONE) { /* fts_read() claims that ent->fts_accpath is a broken symbolic * link. That would be fine, but if this is part of a symbolic * link loop, we diagnose the problem and also ensure that the * eventual return value is nonzero. Note that while the path * we stat is local (fts_accpath), we print the full path name * of the file (fts_path) in the error message. */ if (symlink_loop (ent->fts_accpath)) { nonfatal_target_file_error (ELOOP, ent->fts_path); return; } } else if (ent->fts_info == FTS_NS) { if (ent->fts_level == 0) { /* e.g., nonexistent starting point */ nonfatal_target_file_error (ent->fts_errno, ent->fts_path); return; } else { /* The following if statement fixes Savannah bug #19605 * (failure to diagnose a symbolic link loop) */ if (symlink_loop (ent->fts_accpath)) { nonfatal_target_file_error (ELOOP, ent->fts_path); return; } else { nonfatal_target_file_error (ent->fts_errno, ent->fts_path); /* Continue despite the error, as file name without stat info * might be better than not even processing the file name. This * can lead to repeated error messages later on, though, if a * predicate requires stat information. * * Not printing an error message here would be even more wrong, * though, as this could cause the contents of a directory to be * silently ignored, as the directory wouldn't be identified as * such. */ } } } /* Cope with the usual cases. */ if (ent->fts_info == FTS_NSOK || ent->fts_info == FTS_NS /* e.g. symlink loop */) { assert (!state.have_stat); assert (ent->fts_info == FTS_NSOK || state.type == 0); mode = state.type; } else { state.have_stat = true; state.have_type = true; statbuf = *(ent->fts_statp); state.type = mode = statbuf.st_mode; if (00000 == mode) { /* Savannah bug #16378. */ error (0, 0, _("WARNING: file %s appears to have mode 0000"), quotearg_n_style (0, options.err_quoting_style, ent->fts_path)); } } /* update state.curdepth before calling digest_mode(), because digest_mode * may call following_links(). */ state.curdepth = ent->fts_level; if (mode) { if (!digest_mode (&mode, ent->fts_path, ent->fts_name, &statbuf, 0)) return; } /* examine this item. */ ignore = 0; isdir = S_ISDIR(mode) || (FTS_D == ent->fts_info) || (FTS_DP == ent->fts_info) || (FTS_DC == ent->fts_info); if (isdir && (ent->fts_info == FTS_NSOK)) { /* This is a directory, but fts did not stat it, so * presumably would not be planning to search its * children. Force a stat of the file so that the * children can be checked. */ fts_set (p, ent, FTS_AGAIN); return; } if (options.maxdepth >= 0) { if (ent->fts_level >= options.maxdepth) { fts_set (p, ent, FTS_SKIP); /* descend no further */ if (ent->fts_level > options.maxdepth) ignore = 1; /* don't even look at this one */ } } if ( (ent->fts_info == FTS_D) && !options.do_dir_first ) { /* this is the preorder visit, but user said -depth */ ignore = 1; } else if ( (ent->fts_info == FTS_DP) && options.do_dir_first ) { /* this is the postorder visit, but user didn't say -depth */ ignore = 1; } else if (ent->fts_level < options.mindepth) { ignore = 1; } if (options.debug_options & DebugSearch) fprintf (stderr, "consider_visiting (late): %s: " "fts_info=%-6s, isdir=%d ignore=%d have_stat=%d have_type=%d \n", quotearg_n_style (0, options.err_quoting_style, ent->fts_path), get_fts_info_name (ent->fts_info), isdir, ignore, state.have_stat, state.have_type); if (!ignore) { visit (p, ent, &statbuf); } if (ent->fts_info == FTS_DP) { /* we're leaving a directory. */ state.stop_at_current_level = false; } }
struct urlpos * append_url (const char *link_uri, int position, int size, struct map_context *ctx) { int link_has_scheme = url_has_scheme (link_uri); struct urlpos *newel; const char *base = ctx->base ? ctx->base : ctx->parent_base; struct url *url; struct iri *iri = iri_new (); set_uri_encoding (iri, opt.locale, true); iri->utf8_encode = true; if (!base) { DEBUGP (("%s: no base, merge will use \"%s\".\n", ctx->document_file, link_uri)); if (!link_has_scheme) { /* Base URL is unavailable, and the link does not have a location attached to it -- we have to give up. Since this can only happen when using `--force-html -i', print a warning. */ logprintf (LOG_NOTQUIET, _("%s: Cannot resolve incomplete link %s.\n"), ctx->document_file, link_uri); return NULL; } url = url_parse (link_uri, NULL, iri, false); if (!url) { DEBUGP (("%s: link \"%s\" doesn't parse.\n", ctx->document_file, link_uri)); return NULL; } } else { /* Merge BASE with LINK_URI, but also make sure the result is canonicalized, i.e. that "../" have been resolved. (parse_url will do that for us.) */ char *complete_uri = uri_merge (base, link_uri); DEBUGP (("%s: merge(%s, %s) -> %s\n", quotearg_n_style (0, escape_quoting_style, ctx->document_file), quote_n (1, base), quote_n (2, link_uri), quotearg_n_style (3, escape_quoting_style, complete_uri))); url = url_parse (complete_uri, NULL, iri, false); if (!url) { DEBUGP (("%s: merged link \"%s\" doesn't parse.\n", ctx->document_file, complete_uri)); xfree (complete_uri); return NULL; } xfree (complete_uri); } iri_free (iri); DEBUGP (("appending %s to urlpos.\n", quote (url->url))); newel = xnew0 (struct urlpos); newel->url = url; newel->pos = position; newel->size = size; /* A URL is relative if the host is not named, and the name does not start with `/'. */ if (!link_has_scheme && *link_uri != '/') newel->link_relative_p = 1; else if (link_has_scheme) newel->link_complete_p = 1; /* Append the new URL maintaining the order by position. */ if (ctx->head == NULL) ctx->head = newel; else { struct urlpos *it, *prev = NULL; it = ctx->head; while (it && position > it->pos) { prev = it; it = it->next; } newel->next = it; if (prev) prev->next = newel; else ctx->head = newel; } return newel; }
/* safely_quote_err_filename * */ const char * safely_quote_err_filename (int n, char const *arg) { return quotearg_n_style (n, options.err_quoting_style, arg); }
bool ssl_check_certificate (int fd, const char *host) { X509 *cert; char common_name[256]; long vresult; bool success = true; /* If the user has specified --no-check-cert, we still want to warn him about problems with the server's certificate. */ const char *severity = opt.check_cert ? _("ERROR") : _("WARNING"); struct openssl_transport_context *ctx = fd_transport_context (fd); SSL *conn = ctx->conn; assert (conn != NULL); cert = SSL_get_peer_certificate (conn); if (!cert) { logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"), severity, quotearg_style (escape_quoting_style, host)); success = false; goto no_cert; /* must bail out since CERT is NULL */ } IF_DEBUG { char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0); char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0); DEBUGP (("certificate:\n subject: %s\n issuer: %s\n", quotearg_n_style (0, escape_quoting_style, subject), quotearg_n_style (1, escape_quoting_style, issuer))); OPENSSL_free (subject); OPENSSL_free (issuer); } vresult = SSL_get_verify_result (conn); if (vresult != X509_V_OK) { char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0); logprintf (LOG_NOTQUIET, _("%s: cannot verify %s's certificate, issued by %s:\n"), severity, quotearg_n_style (0, escape_quoting_style, host), quote_n (1, issuer)); /* Try to print more user-friendly (and translated) messages for the frequent verification errors. */ switch (vresult) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: logprintf (LOG_NOTQUIET, _(" Unable to locally verify the issuer's authority.\n")); break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: logprintf (LOG_NOTQUIET, _(" Self-signed certificate encountered.\n")); break; case X509_V_ERR_CERT_NOT_YET_VALID: logprintf (LOG_NOTQUIET, _(" Issued certificate not yet valid.\n")); break; case X509_V_ERR_CERT_HAS_EXPIRED: logprintf (LOG_NOTQUIET, _(" Issued certificate has expired.\n")); break; default: /* For the less frequent error strings, simply provide the OpenSSL error message. */ logprintf (LOG_NOTQUIET, " %s\n", X509_verify_cert_error_string (vresult)); } success = false; /* Fall through, so that the user is warned about *all* issues with the cert (important with --no-check-certificate.) */ } /* Check that HOST matches the common name in the certificate. #### The following remains to be done: - It should use dNSName/ipAddress subjectAltName extensions if available; according to rfc2818: "If a subjectAltName extension of type dNSName is present, that MUST be used as the identity." - When matching against common names, it should loop over all common names and choose the most specific one, i.e. the last one, not the first one, which the current code picks. - Ensure that ASN1 strings from the certificate are encoded as UTF-8 which can be meaningfully compared to HOST. */ { X509_NAME *xname = X509_get_subject_name(cert); common_name[0] = '\0'; X509_NAME_get_text_by_NID (xname, NID_commonName, common_name, sizeof (common_name)); if (!pattern_match (common_name, host)) { logprintf (LOG_NOTQUIET, _("\ %s: certificate common name %s doesn't match requested host name %s.\n"), severity, quote_n (0, common_name), quote_n (1, host)); success = false; } else {
bool ssl_check_certificate (int fd, const char *host) { X509 *cert; GENERAL_NAMES *subjectAltNames; char common_name[256]; long vresult; bool success = true; bool alt_name_checked = false; /* If the user has specified --no-check-cert, we still want to warn him about problems with the server's certificate. */ const char *severity = opt.check_cert ? _("ERROR") : _("WARNING"); struct openssl_transport_context *ctx = fd_transport_context (fd); SSL *conn = ctx->conn; assert (conn != NULL); cert = SSL_get_peer_certificate (conn); if (!cert) { logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"), severity, quotearg_style (escape_quoting_style, host)); success = false; goto no_cert; /* must bail out since CERT is NULL */ } IF_DEBUG { char *subject = _get_rfc2253_formatted (X509_get_subject_name (cert)); char *issuer = _get_rfc2253_formatted (X509_get_issuer_name (cert)); DEBUGP (("certificate:\n subject: %s\n issuer: %s\n", quotearg_n_style (0, escape_quoting_style, subject), quotearg_n_style (1, escape_quoting_style, issuer))); xfree (subject); xfree (issuer); } vresult = SSL_get_verify_result (conn); if (vresult != X509_V_OK) { char *issuer = _get_rfc2253_formatted (X509_get_issuer_name (cert)); logprintf (LOG_NOTQUIET, _("%s: cannot verify %s's certificate, issued by %s:\n"), severity, quotearg_n_style (0, escape_quoting_style, host), quote_n (1, issuer)); xfree(issuer); /* Try to print more user-friendly (and translated) messages for the frequent verification errors. */ switch (vresult) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: logprintf (LOG_NOTQUIET, _(" Unable to locally verify the issuer's authority.\n")); break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: logprintf (LOG_NOTQUIET, _(" Self-signed certificate encountered.\n")); break; case X509_V_ERR_CERT_NOT_YET_VALID: logprintf (LOG_NOTQUIET, _(" Issued certificate not yet valid.\n")); break; case X509_V_ERR_CERT_HAS_EXPIRED: logprintf (LOG_NOTQUIET, _(" Issued certificate has expired.\n")); break; default: /* For the less frequent error strings, simply provide the OpenSSL error message. */ logprintf (LOG_NOTQUIET, " %s\n", X509_verify_cert_error_string (vresult)); } success = false; /* Fall through, so that the user is warned about *all* issues with the cert (important with --no-check-certificate.) */ } /* Check that HOST matches the common name in the certificate. #### The following remains to be done: - When matching against common names, it should loop over all common names and choose the most specific one, i.e. the last one, not the first one, which the current code picks. - Ensure that ASN1 strings from the certificate are encoded as UTF-8 which can be meaningfully compared to HOST. */ subjectAltNames = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL); if (subjectAltNames) { /* Test subject alternative names */ /* Do we want to check for dNSNAmes or ipAddresses (see RFC 2818)? * Signal it by host_in_octet_string. */ ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (host); int numaltnames = sk_GENERAL_NAME_num (subjectAltNames); int i; for (i=0; i < numaltnames; i++) { const GENERAL_NAME *name = sk_GENERAL_NAME_value (subjectAltNames, i); if (name) { if (host_in_octet_string) { if (name->type == GEN_IPADD) { /* Check for ipAddress */ /* TODO: Should we convert between IPv4-mapped IPv6 * addresses and IPv4 addresses? */ alt_name_checked = true; if (!ASN1_STRING_cmp (host_in_octet_string, name->d.iPAddress)) break; } } else if (name->type == GEN_DNS) { /* dNSName should be IA5String (i.e. ASCII), however who * does trust CA? Convert it into UTF-8 for sure. */ unsigned char *name_in_utf8 = NULL; /* Check for dNSName */ alt_name_checked = true; if (0 <= ASN1_STRING_to_UTF8 (&name_in_utf8, name->d.dNSName)) { /* Compare and check for NULL attack in ASN1_STRING */ if (pattern_match ((char *)name_in_utf8, host) && (strlen ((char *)name_in_utf8) == (size_t) ASN1_STRING_length (name->d.dNSName))) { OPENSSL_free (name_in_utf8); break; } OPENSSL_free (name_in_utf8); } } } } sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free); if (host_in_octet_string) ASN1_OCTET_STRING_free(host_in_octet_string); if (alt_name_checked == true && i >= numaltnames) { logprintf (LOG_NOTQUIET, _("%s: no certificate subject alternative name matches\n" "\trequested host name %s.\n"), severity, quote_n (1, host)); success = false; } } if (alt_name_checked == false) { /* Test commomName */ X509_NAME *xname = X509_get_subject_name(cert); common_name[0] = '\0'; X509_NAME_get_text_by_NID (xname, NID_commonName, common_name, sizeof (common_name)); if (!pattern_match (common_name, host)) { logprintf (LOG_NOTQUIET, _("\ %s: certificate common name %s doesn't match requested host name %s.\n"), severity, quote_n (0, common_name), quote_n (1, host)); success = false; }
/* Search for FILENAME according to -B options, `.', -I options, then M4PATH environment. If successful, return the open file, and if RESULT is not NULL, set *RESULT to a malloc'd string that represents the file found with respect to the current working directory. Otherwise, return NULL, and errno reflects the failure from searching `.' (regardless of what else was searched). */ char * m4_path_search (m4 *context, const char *filename, const char **suffixes) { m4__search_path *incl; char *filepath; /* buffer for constructed name */ size_t max_suffix_len = 0; int i, e = 0; /* Reject empty file. */ if (*filename == '\0') { errno = ENOENT; return NULL; } /* Use no suffixes by default. */ if (suffixes == NULL) suffixes = NO_SUFFIXES; /* Find the longest suffix, so that we will always allocate enough memory for a filename with suffix. */ for (i = 0; suffixes && suffixes[i]; ++i) { size_t len = strlen (suffixes[i]); if (len > max_suffix_len) max_suffix_len = len; } /* If file is absolute, or if we are not searching a path, a single lookup will do the trick. */ if (IS_ABSOLUTE_FILE_NAME (filename)) { size_t mem = strlen (filename); /* Try appending each of the suffixes we were given. */ filepath = strncpy (xmalloc (mem + max_suffix_len +1), filename, mem +1); #if TRUNCATE_FILENAME filepath = path_truncate (filepath); mem = strlen (filepath); /* recalculate length after truncation */ #endif for (i = 0; suffixes && suffixes[i]; ++i) { strcpy (filepath + mem, suffixes[i]); if (access (filepath, R_OK) == 0) return filepath; /* If search fails, we'll use the error we got from the first access (usually with no suffix). */ if (i == 0) e = errno; } free (filepath); /* No such file. */ errno = e; return NULL; } for (incl = m4__get_search_path (context)->list; incl != NULL; incl = incl->next) { char *pathname = file_name_concat (incl->dir, filename, NULL); size_t mem = strlen (pathname); #ifdef DEBUG_INCL xfprintf (stderr, "path_search (%s) -- trying %s\n", filename, pathname); #endif if (access (pathname, R_OK) == 0) { m4_debug_message (context, M4_DEBUG_TRACE_PATH, _("path search for %s found %s"), quotearg_style (locale_quoting_style, filename), quotearg_n_style (1, locale_quoting_style, pathname)); return pathname; } else if (!incl->len) /* Capture errno only when searching `.'. */ e = errno; filepath = strncpy (xmalloc (mem + max_suffix_len +1), pathname, mem +1); free (pathname); #if TRUNCATE_FILENAME filepath = path_truncate (filepath); mem = strlen (filepath); /* recalculate length after truncation */ #endif for (i = 0; suffixes && suffixes[i]; ++i) { strcpy (filepath + mem, suffixes[i]); if (access (filepath, R_OK) == 0) return filepath; } free (filepath); } errno = e; return NULL; }
/* Return an unambiguous printable representation of NAME, allocated in slot N, suitable for diagnostics. */ char const * quote_n (int n, char const *name) { return quotearg_n_style (n, locale_quoting_style, name); }
static void consider_visiting(FTS *p, FTSENT *ent) { struct stat statbuf; mode_t mode; int ignore, isdir; if (options.debug_options & DebugSearch) fprintf(stderr, "consider_visiting: fts_info=%-6s, fts_level=%2d, prev_depth=%d " "fts_path=%s, fts_accpath=%s\n", get_fts_info_name(ent->fts_info), (int)ent->fts_level, prev_depth, quotearg_n_style(0, options.err_quoting_style, ent->fts_path), quotearg_n_style(1, options.err_quoting_style, ent->fts_accpath)); if (ent->fts_info == FTS_DP) { left_dir(); } else if (ent->fts_level > prev_depth || ent->fts_level==0) { left_dir(); } inside_dir(p->fts_cwd_fd); prev_depth = ent->fts_level; /* Cope with various error conditions. */ if (ent->fts_info == FTS_ERR || ent->fts_info == FTS_DNR) { error(0, ent->fts_errno, "%s", safely_quote_err_filename(0, ent->fts_path)); error_severity(1); return; } else if (ent->fts_info == FTS_DC) { issue_loop_warning(ent); error_severity(1); return; } else if (ent->fts_info == FTS_SLNONE) { /* fts_read() claims that ent->fts_accpath is a broken symbolic * link. That would be fine, but if this is part of a symbolic * link loop, we diagnose the problem and also ensure that the * eventual return value is nonzero. Note that while the path * we stat is local (fts_accpath), we print the full path name * of the file (fts_path) in the error message. */ if (symlink_loop(ent->fts_accpath)) { error(0, ELOOP, "%s", safely_quote_err_filename(0, ent->fts_path)); error_severity(1); return; } } else if (ent->fts_info == FTS_NS) { if (ent->fts_level == 0) { /* e.g., nonexistent starting point */ error(0, ent->fts_errno, "%s", safely_quote_err_filename(0, ent->fts_path)); error_severity(1); /* remember problem */ return; } else { /* The following if statement fixes Savannah bug #19605 * (failure to diagnose a symbolic link loop) */ if (symlink_loop(ent->fts_accpath)) { error(0, ELOOP, "%s", safely_quote_err_filename(0, ent->fts_path)); error_severity(1); return; } } } /* Cope with the usual cases. */ if (ent->fts_info == FTS_NSOK || ent->fts_info == FTS_NS /* e.g. symlink loop */) { assert (!state.have_stat); assert (!state.have_type); state.type = mode = 0; } else { state.have_stat = true; state.have_type = true; statbuf = *(ent->fts_statp); state.type = mode = statbuf.st_mode; if (00000 == mode) { /* Savannah bug #16378. */ error(0, 0, _("Warning: file %s appears to have mode 0000"), quotearg_n_style(0, options.err_quoting_style, ent->fts_path)); } } if (mode) { if (!digest_mode(mode, ent->fts_path, ent->fts_name, &statbuf, 0)) return; } /* examine this item. */ ignore = 0; isdir = S_ISDIR(mode) || (FTS_D == ent->fts_info) || (FTS_DP == ent->fts_info) || (FTS_DC == ent->fts_info); if (isdir && (ent->fts_info == FTS_NSOK)) { /* This is a directory, but fts did not stat it, so * presumably would not be planning to search its * children. Force a stat of the file so that the * children can be checked. */ fts_set(p, ent, FTS_AGAIN); return; } if (options.maxdepth >= 0) { if (ent->fts_level >= options.maxdepth) { fts_set(p, ent, FTS_SKIP); /* descend no further */ if (ent->fts_level > options.maxdepth) ignore = 1; /* don't even look at this one */ } } if ( (ent->fts_info == FTS_D) && !options.do_dir_first ) { /* this is the preorder visit, but user said -depth */ ignore = 1; } else if ( (ent->fts_info == FTS_DP) && options.do_dir_first ) { /* this is the postorder visit, but user didn't say -depth */ ignore = 1; } else if (ent->fts_level < options.mindepth) { ignore = 1; } if (!ignore) { visit(p, ent, &statbuf); } /* XXX: if we allow a build-up of pending arguments for "-execdir foo {} +" * we need to execute them in the same directory as we found the item. * If we are trying to do "find a -execdir echo {} +", we will need to * echo * a while in the original working directory * b while in a * c while in b (just before leaving b) * * These restrictions are hard to satisfy while using fts(). The reason is * that it doesn't tell us just before we leave a directory. For the moment, * we punt and don't allow the arguments to build up. */ if (state.execdirs_outstanding) { show_outstanding_execdirs(stderr); run_in_dir(p->fts_cwd_fd, complete_execdirs_cb, NULL); } if (ent->fts_info == FTS_DP) { /* we're leaving a directory. */ state.stop_at_current_level = false; } }