static int touch_file (struct file *file) { if (!silent_flag) message (0, "touch %s", file->name); /* Print-only (-n) takes precedence over touch (-t). */ if (just_print_flag) return 0; #ifndef NO_ARCHIVES if (ar_name (file->name)) return ar_touch (file->name); else #endif { int fd = open (file->name, O_RDWR | O_CREAT, 0666); if (fd < 0) TOUCH_ERROR ("touch: open: "); else { struct stat statbuf; char buf = 'x'; int e; EINTRLOOP (e, fstat (fd, &statbuf)); if (e < 0) TOUCH_ERROR ("touch: fstat: "); /* Rewrite character 0 same as it already is. */ if (read (fd, &buf, 1) < 0) TOUCH_ERROR ("touch: read: "); if (lseek (fd, 0L, 0) < 0L) TOUCH_ERROR ("touch: lseek: "); if (write (fd, &buf, 1) < 0) TOUCH_ERROR ("touch: write: "); /* If file length was 0, we just changed it, so change it back. */ if (statbuf.st_size == 0) { (void) close (fd); fd = open (file->name, O_RDWR | O_TRUNC, 0666); if (fd < 0) TOUCH_ERROR ("touch: open: "); } (void) close (fd); } } return 0; }
static void delete_target (struct file *file, const char *on_behalf_of) { struct stat st; int e; if (file->precious || file->phony) { return; } #ifndef NO_ARCHIVES if (ar_name (file->name)) { time_t file_date = (file->last_mtime == NONEXISTENT_MTIME ? (time_t) -1 : (time_t) FILE_TIMESTAMP_S (file->last_mtime)); if (ar_member_date (file->name) != file_date) { if (on_behalf_of) { error (NILF, _("*** [%s] Archive member `%s' may be bogus; not deleted"), on_behalf_of, file->name); } else { error (NILF, _("*** Archive member `%s' may be bogus; not deleted"), file->name); } } return; } #endif /* !NO_ARCHIVES. */ EINTRLOOP (e, stat (file->name, &st)); if (e == 0 && S_ISREG (st.st_mode) #ifdef ST_MTIM_NSEC && FILE_TIMESTAMP_STAT_MODTIME (file->name, st) != file->last_mtime #endif /* ST_MTIM_NSEC */ && e != 1) { if (on_behalf_of) { error (NILF, _("*** [%s] Deleting file `%s'"), on_behalf_of, file->name); } else error (NILF, _("*** Deleting file `%s'"), file->name); if (unlink (file->name) < 0 && errno != ENOENT) /* It disappeared; so what. */ perror_with_name ("unlink: ", file->name); } }
unsigned long AddModule(unsigned long mod_start, unsigned long mod_end, unsigned long end) { char *p = (char *)mod_start; if (p[0] == 0x7f && p[1] == 'E' && p[2] == 'L' && p[3] == 'F') { /* * The loaded file is an ELF object. It may be put directly into our list of modules. * Unfortunately GRUB doesn't give us names of loaded modules */ struct ELFNode *mo = module_prepare(NULL); mo->Name = "Kickstart ELF"; mo->eh = (void*)mod_start; D(kprintf("[BOOT] * ELF module %s @ %p\n", mo->Name, mo->eh)); if (mod_end > end) end = mod_end; } else if (p[0] == 'P' && p[1] == 'K' && p[2] == 'G' && p[3] == 0x01) { /* * The loaded file is an PKG\0 archive. Scan it to find all modules which are * stored here. */ void *file = p + 8; D(kprintf("[BOOT] * package @ %p:\n", mod_start)); while (file < (void*)mod_end) { int len = LONG2BE(*(int *)file); char *s = __bs_remove_path(file+4); struct ELFNode *mo = module_prepare(s); file += 5+len; len = LONG2BE(*(int *)file); file += 4; mo->Name = s; mo->eh = file; D(kprintf("[BOOT] * PKG module %s @ %p\n", mo->Name, mo->eh)); file += len; } if (mod_end > end) end = mod_end; } else if (memcmp(p,"!<arch>\n",8) == 0) { const struct ar_header *file; char *name; const struct ar_header *longnames = NULL; /* ar(1) archive */ D(kprintf("[BOOT] * archive @ %p:\n", mod_start)); /* Look for the GNU extended name section */ for (file = (void *)(p + 8); (void *)file < (void*)mod_end; file = ar_next(file)) { name = ar_name(file, NULL); if (strcmp(name, "//") == 0) { longnames = file; break; } } D(kprintf("[BOOT] * longnames @ %p\n", longnames)); for (file = (void *)(p + 8); (void *)file < (void*)mod_end; file = ar_next(file)) { const char *data = ar_data(file); char *s = ar_name(file, longnames); if (memcmp(data,"\177ELF",4) == 0) { struct ELFNode *mo = module_prepare(s); mo->Name = s; mo->eh = (void *)data; D(kprintf("[BOOT] * ar module %s @ %p\n", mo->Name, mo->eh)); } else { D(kprintf("[BOOT] * Ignored @ %p (%s)\n", file, s)); } } if (mod_end > end) end = mod_end; } else kprintf("[BOOT] Unknown module 0x%p\n", p); return end; }
FILE_TIMESTAMP f_mtime (struct file *file, int search) { FILE_TIMESTAMP mtime; /* File's mtime is not known; must get it from the system. */ #ifndef NO_ARCHIVES if (ar_name (file->name)) { /* This file is an archive-member reference. */ char *arname, *memname; struct file *arfile; time_t member_date; /* Find the archive's name. */ ar_parse_name (file->name, &arname, &memname); /* Find the modification time of the archive itself. Also allow for its name to be changed via VPATH search. */ arfile = lookup_file (arname); if (arfile == 0) arfile = enter_file (strcache_add (arname)); mtime = f_mtime (arfile, search); check_renamed (arfile); if (search && strcmp (arfile->hname, arname)) { /* The archive's name has changed. Change the archive-member reference accordingly. */ char *name; unsigned int arlen, memlen; arlen = strlen (arfile->hname); memlen = strlen (memname); name = xmalloc (arlen + 1 + memlen + 2); memcpy (name, arfile->hname, arlen); name[arlen] = '('; memcpy (name + arlen + 1, memname, memlen); name[arlen + 1 + memlen] = ')'; name[arlen + 1 + memlen + 1] = '\0'; /* If the archive was found with GPATH, make the change permanent; otherwise defer it until later. */ if (arfile->name == arfile->hname) rename_file (file, name); else rehash_file (file, name); check_renamed (file); } free (arname); file->low_resolution_time = 1; if (mtime == NONEXISTENT_MTIME) /* The archive doesn't exist, so its members don't exist either. */ return NONEXISTENT_MTIME; member_date = ar_member_date (file->hname); mtime = (member_date == (time_t) -1 ? NONEXISTENT_MTIME : file_timestamp_cons (file->hname, member_date, 0)); } else #endif { mtime = name_mtime (file->name); if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath) { /* If name_mtime failed, search VPATH. */ const char *name = vpath_search (file->name, &mtime, NULL, NULL); if (name /* Last resort, is it a library (-lxxx)? */ || (file->name[0] == '-' && file->name[1] == 'l' && (name = library_search (file->name, &mtime)) != 0)) { if (mtime != UNKNOWN_MTIME) /* vpath_search and library_search store UNKNOWN_MTIME if they didn't need to do a stat call for their work. */ file->last_mtime = mtime; /* If we found it in VPATH, see if it's in GPATH too; if so, change the name right now; if not, defer until after the dependencies are updated. */ if (gpath_search (name, strlen(name) - strlen(file->name) - 1)) { rename_file (file, name); check_renamed (file); return file_mtime (file); } rehash_file (file, name); check_renamed (file); /* If the result of a vpath search is -o or -W, preserve it. Otherwise, find the mtime of the resulting file. */ if (mtime != OLD_MTIME && mtime != NEW_MTIME) mtime = name_mtime (name); } } } /* Files can have bogus timestamps that nothing newly made will be "newer" than. Updating their dependents could just result in loops. So notify the user of the anomaly with a warning. We only need to do this once, for now. */ if (!clock_skew_detected && mtime != NONEXISTENT_MTIME && mtime != NEW_MTIME && !file->updated) { static FILE_TIMESTAMP adjusted_now; FILE_TIMESTAMP adjusted_mtime = mtime; #if defined(WINDOWS32) || defined(__MSDOS__) /* Experimentation has shown that FAT filesystems can set file times up to 3 seconds into the future! Play it safe. */ #define FAT_ADJ_OFFSET (FILE_TIMESTAMP) 3 FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS; if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime) adjusted_mtime -= adjustment; #elif defined(__EMX__) /* FAT filesystems round time to the nearest even second! Allow for any file (NTFS or FAT) to perhaps suffer from this brain damage. */ FILE_TIMESTAMP adjustment = (((FILE_TIMESTAMP_S (adjusted_mtime) & 1) == 0 && FILE_TIMESTAMP_NS (adjusted_mtime) == 0) ? (FILE_TIMESTAMP) 1 << FILE_TIMESTAMP_LO_BITS : 0); #endif /* If the file's time appears to be in the future, update our concept of the present and try once more. */ if (adjusted_now < adjusted_mtime) { int resolution; FILE_TIMESTAMP now = file_timestamp_now (&resolution); adjusted_now = now + (resolution - 1); if (adjusted_now < adjusted_mtime) { #ifdef NO_FLOAT error (NILF, _("Warning: File '%s' has modification time in the future"), file->name); #else double from_now = (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now) + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now)) / 1e9)); char from_now_string[100]; if (from_now >= 99 && from_now <= ULONG_MAX) sprintf (from_now_string, "%lu", (unsigned long) from_now); else sprintf (from_now_string, "%.2g", from_now); error (NILF, _("Warning: File '%s' has modification time %s s in the future"), file->name, from_now_string); #endif clock_skew_detected = 1; } } } /* Store the mtime into all the entries for this file. */ if (file->double_colon) file = file->double_colon; do { /* If this file is not implicit but it is intermediate then it was made so by the .INTERMEDIATE target. If this file has never been built by us but was found now, it existed before make started. So, turn off the intermediate bit so make doesn't delete it, since it didn't create it. */ if (mtime != NONEXISTENT_MTIME && file->command_state == cs_not_started && file->command_state == cs_not_started && !file->tried_implicit && file->intermediate) file->intermediate = 0; file->last_mtime = mtime; file = file->prev; } while (file != 0); return mtime; }
void set_file_variables (struct file *file) { struct dep *d; const char *at, *percent, *star, *less; #ifndef NO_ARCHIVES /* If the target is an archive member `lib(member)', then $@ is `lib' and $% is `member'. */ if (ar_name (file->name)) { unsigned int len; const char *cp; char *p; cp = strchr (file->name, '('); p = alloca (cp - file->name + 1); memcpy (p, file->name, cp - file->name); p[cp - file->name] = '\0'; at = p; len = strlen (cp + 1); p = alloca (len); memcpy (p, cp + 1, len - 1); p[len - 1] = '\0'; percent = p; } else #endif /* NO_ARCHIVES. */ { at = file->name; percent = ""; } /* $* is the stem from an implicit or static pattern rule. */ if (file->stem == 0) { /* In Unix make, $* is set to the target name with any suffix in the .SUFFIXES list stripped off for explicit rules. We store this in the `stem' member. */ const char *name; unsigned int len; #ifndef NO_ARCHIVES if (ar_name (file->name)) { name = strchr (file->name, '(') + 1; len = strlen (name) - 1; } else #endif { name = file->name; len = strlen (name); } for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next) { unsigned int slen = strlen (dep_name (d)); if (len > slen && strneq (dep_name (d), name + (len - slen), slen)) { file->stem = strcache_add_len (name, len - slen); break; } } if (d == 0) file->stem = ""; } star = file->stem; /* $< is the first not order-only dependency. */ less = ""; for (d = file->deps; d != 0; d = d->next) if (!d->ignore_mtime) { if (!d->need_2nd_expansion) less = dep_name (d); break; } if (file->cmds == default_file->cmds) /* This file got its commands from .DEFAULT. In this case $< is the same as $@. */ less = at; #define DEFINE_VARIABLE(name, len, value) \ (void) define_variable_for_file (name,len,value,o_automatic,0,file) /* Define the variables. */ DEFINE_VARIABLE ("<", 1, less); DEFINE_VARIABLE ("*", 1, star); DEFINE_VARIABLE ("@", 1, at); DEFINE_VARIABLE ("%", 1, percent); /* Compute the values for $^, $+, $?, and $|. */ { static char *plus_value=0, *bar_value=0, *qmark_value=0; static unsigned int plus_max=0, bar_max=0, qmark_max=0; unsigned int qmark_len, plus_len, bar_len; char *cp; char *caret_value; char *qp; char *bp; unsigned int len; struct hash_table dep_hash; void **slot; /* Compute first the value for $+, which is supposed to contain duplicate dependencies as they were listed in the makefile. */ plus_len = 0; bar_len = 0; for (d = file->deps; d != 0; d = d->next) { if (!d->need_2nd_expansion) { if (d->ignore_mtime) bar_len += strlen (dep_name (d)) + 1; else plus_len += strlen (dep_name (d)) + 1; } } if (bar_len == 0) bar_len++; if (plus_len == 0) plus_len++; if (plus_len > plus_max) plus_value = xrealloc (plus_value, plus_max = plus_len); cp = plus_value; qmark_len = plus_len + 1; /* Will be this or less. */ for (d = file->deps; d != 0; d = d->next) if (! d->ignore_mtime && ! d->need_2nd_expansion) { const char *c = dep_name (d); #ifndef NO_ARCHIVES if (ar_name (c)) { c = strchr (c, '(') + 1; len = strlen (c) - 1; } else #endif len = strlen (c); memcpy (cp, c, len); cp += len; *cp++ = FILE_LIST_SEPARATOR; if (! (d->changed || always_make_flag)) qmark_len -= len + 1; /* Don't space in $? for this one. */ } /* Kill the last space and define the variable. */ cp[cp > plus_value ? -1 : 0] = '\0'; DEFINE_VARIABLE ("+", 1, plus_value); /* Compute the values for $^, $?, and $|. */ cp = caret_value = plus_value; /* Reuse the buffer; it's big enough. */ if (qmark_len > qmark_max) qmark_value = xrealloc (qmark_value, qmark_max = qmark_len); qp = qmark_value; if (bar_len > bar_max) bar_value = xrealloc (bar_value, bar_max = bar_len); bp = bar_value; /* Make sure that no dependencies are repeated in $^, $?, and $|. It would be natural to combine the next two loops but we can't do it because of a situation where we have two dep entries, the first is order-only and the second is normal (see below). */ hash_init (&dep_hash, 500, dep_hash_1, dep_hash_2, dep_hash_cmp); for (d = file->deps; d != 0; d = d->next) { if (d->need_2nd_expansion) continue; slot = hash_find_slot (&dep_hash, d); if (HASH_VACANT (*slot)) hash_insert_at (&dep_hash, d, slot); else { /* Check if the two prerequisites have different ignore_mtime. If so then we need to "upgrade" one that is order-only. */ struct dep* hd = (struct dep*) *slot; if (d->ignore_mtime != hd->ignore_mtime) d->ignore_mtime = hd->ignore_mtime = 0; } } for (d = file->deps; d != 0; d = d->next) { const char *c; if (d->need_2nd_expansion || hash_find_item (&dep_hash, d) != d) continue; c = dep_name (d); #ifndef NO_ARCHIVES if (ar_name (c)) { c = strchr (c, '(') + 1; len = strlen (c) - 1; } else #endif len = strlen (c); if (d->ignore_mtime) { memcpy (bp, c, len); bp += len; *bp++ = FILE_LIST_SEPARATOR; } else { memcpy (cp, c, len); cp += len; *cp++ = FILE_LIST_SEPARATOR; if (d->changed || always_make_flag) { memcpy (qp, c, len); qp += len; *qp++ = FILE_LIST_SEPARATOR; } } } hash_free (&dep_hash, 0); /* Kill the last spaces and define the variables. */ cp[cp > caret_value ? -1 : 0] = '\0'; DEFINE_VARIABLE ("^", 1, caret_value); qp[qp > qmark_value ? -1 : 0] = '\0'; DEFINE_VARIABLE ("?", 1, qmark_value); bp[bp > bar_value ? -1 : 0] = '\0'; DEFINE_VARIABLE ("|", 1, bar_value); } #undef DEFINE_VARIABLE }