libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / tools / set_haiku_revision.cpp
blob88c4704e04057dc00b6af68251866e592e8332d0
1 /*
2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <inttypes.h>
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
15 #include <algorithm>
16 #include <string>
18 #include <system_revision.h>
20 // We use htonl(), which is defined in <ByteOrder.h> on BeOS R5.
21 #ifdef HAIKU_HOST_PLATFORM_BEOS
22 #include <ByteOrder.h>
23 #else
24 #include <arpa/inet.h>
25 #endif
28 using std::string;
29 using std::max;
30 using std::min;
33 // #pragma mark - ELF definitions
36 // types
37 typedef uint32_t Elf32_Addr;
38 typedef uint16_t Elf32_Half;
39 typedef uint32_t Elf32_Off;
40 typedef int32_t Elf32_Sword;
41 typedef uint32_t Elf32_Word;
42 typedef uint64_t Elf64_Addr;
43 typedef uint64_t Elf64_Off;
44 typedef uint16_t Elf64_Half;
45 typedef uint32_t Elf64_Word;
46 typedef int32_t Elf64_Sword;
47 typedef uint64_t Elf64_Xword;
48 typedef int64_t Elf64_Sxword;
50 // e_ident indices
51 #define EI_MAG0 0
52 #define EI_MAG1 1
53 #define EI_MAG2 2
54 #define EI_MAG3 3
55 #define EI_CLASS 4
56 #define EI_DATA 5
57 #define EI_VERSION 6
58 #define EI_PAD 7
59 #define EI_NIDENT 16
61 // object file header
62 typedef struct {
63 unsigned char e_ident[EI_NIDENT];
64 Elf32_Half e_type;
65 Elf32_Half e_machine;
66 Elf32_Word e_version;
67 Elf32_Addr e_entry;
68 Elf32_Off e_phoff;
69 Elf32_Off e_shoff;
70 Elf32_Word e_flags;
71 Elf32_Half e_ehsize;
72 Elf32_Half e_phentsize;
73 Elf32_Half e_phnum;
74 Elf32_Half e_shentsize;
75 Elf32_Half e_shnum;
76 Elf32_Half e_shstrndx;
77 } Elf32_Ehdr;
79 typedef struct {
80 unsigned char e_ident[EI_NIDENT];
81 Elf64_Half e_type;
82 Elf64_Half e_machine;
83 Elf64_Word e_version;
84 Elf64_Addr e_entry;
85 Elf64_Off e_phoff;
86 Elf64_Off e_shoff;
87 Elf64_Word e_flags;
88 Elf64_Half e_ehsize;
89 Elf64_Half e_phentsize;
90 Elf64_Half e_phnum;
91 Elf64_Half e_shentsize;
92 Elf64_Half e_shnum;
93 Elf64_Half e_shstrndx;
94 } Elf64_Ehdr;
96 // e_ident EI_CLASS and EI_DATA values
97 #define ELFCLASSNONE 0
98 #define ELFCLASS32 1
99 #define ELFCLASS64 2
100 #define ELFDATANONE 0
101 #define ELFDATA2LSB 1
102 #define ELFDATA2MSB 2
104 // program header
105 typedef struct {
106 Elf32_Word p_type;
107 Elf32_Off p_offset;
108 Elf32_Addr p_vaddr;
109 Elf32_Addr p_paddr;
110 Elf32_Word p_filesz;
111 Elf32_Word p_memsz;
112 Elf32_Word p_flags;
113 Elf32_Word p_align;
114 } Elf32_Phdr;
116 typedef struct {
117 Elf64_Word p_type;
118 Elf64_Word p_flags;
119 Elf64_Off p_offset;
120 Elf64_Addr p_vaddr;
121 Elf64_Addr p_paddr;
122 Elf64_Xword p_filesz;
123 Elf64_Xword p_memsz;
124 Elf64_Xword p_align;
125 } Elf64_Phdr;
127 // p_type
128 #define PT_NULL 0
129 #define PT_LOAD 1
130 #define PT_DYNAMIC 2
131 #define PT_INTERP 3
132 #define PT_NOTE 4
133 #define PT_SHLIB 5
134 #define PT_PHDIR 6
135 #define PT_LOPROC 0x70000000
136 #define PT_HIPROC 0x7fffffff
138 // section header
139 typedef struct {
140 Elf32_Word sh_name;
141 Elf32_Word sh_type;
142 Elf32_Word sh_flags;
143 Elf32_Addr sh_addr;
144 Elf32_Off sh_offset;
145 Elf32_Word sh_size;
146 Elf32_Word sh_link;
147 Elf32_Word sh_info;
148 Elf32_Word sh_addralign;
149 Elf32_Word sh_entsize;
150 } Elf32_Shdr;
152 typedef struct {
153 Elf64_Word sh_name;
154 Elf64_Word sh_type;
155 Elf64_Xword sh_flags;
156 Elf64_Addr sh_addr;
157 Elf64_Off sh_offset;
158 Elf64_Xword sh_size;
159 Elf64_Word sh_link;
160 Elf64_Word sh_info;
161 Elf64_Xword sh_addralign;
162 Elf64_Xword sh_entsize;
163 } Elf64_Shdr;
165 // sh_type values
166 #define SHT_NULL 0
167 #define SHT_PROGBITS 1
168 #define SHT_SYMTAB 2
169 #define SHT_STRTAB 3
170 #define SHT_RELA 4
171 #define SHT_HASH 5
172 #define SHT_DYNAMIC 6
173 #define SHT_NOTE 7
174 #define SHT_NOBITS 8
175 #define SHT_REL 9
176 #define SHT_SHLIB 10
177 #define SHT_DYNSYM 11
178 #define SHT_LOPROC 0x70000000
179 #define SHT_HIPROC 0x7fffffff
180 #define SHT_LOUSER 0x80000000
181 #define SHT_HIUSER 0xffffffff
183 // special section indexes
184 #define SHN_UNDEF 0
186 static const char kELFFileMagic[4] = { 0x7f, 'E', 'L', 'F' };
189 // #pragma mark - Usage
191 // usage
192 static const char *kUsage =
193 "Usage: %s <file> <revision>\n"
194 "\n"
195 "Finds the haiku revision section in ELF object file <file> and replaces the\n"
196 "writes the number given by <revision> into the first 32 bits of the\n"
197 "section.\n"
200 // command line args
201 static int sArgc;
202 static const char *const *sArgv;
204 // print_usage
205 void
206 print_usage(bool error)
208 // get nice program name
209 const char *programName = (sArgc > 0 ? sArgv[0] : "resattr");
210 if (const char *lastSlash = strrchr(programName, '/'))
211 programName = lastSlash + 1;
213 // print usage
214 fprintf((error ? stderr : stdout), kUsage, programName);
217 // print_usage_and_exit
218 static void
219 print_usage_and_exit(bool error)
221 print_usage(error);
222 exit(error ? 1 : 0);
226 // #pragma mark - Exception
229 class Exception {
230 public:
231 // constructor
232 Exception()
233 : fError(errno),
234 fDescription()
238 // constructor
239 Exception(const char* format,...)
240 : fError(errno),
241 fDescription()
243 va_list args;
244 va_start(args, format);
245 SetTo(errno, format, args);
246 va_end(args);
249 // constructor
250 Exception(int error)
251 : fError(error),
252 fDescription()
256 // constructor
257 Exception(int error, const char* format,...)
258 : fError(error),
259 fDescription()
261 va_list args;
262 va_start(args, format);
263 SetTo(error, format, args);
264 va_end(args);
267 // copy constructor
268 Exception(const Exception& exception)
269 : fError(exception.fError),
270 fDescription(exception.fDescription)
274 // destructor
275 ~Exception()
279 // SetTo
280 void SetTo(int error, const char* format, va_list arg)
282 char buffer[2048];
283 vsprintf(buffer, format, arg);
284 fError = error;
285 fDescription = buffer;
288 // Error
289 int Error() const
291 return fError;
294 // Description
295 const string& Description() const
297 return fDescription;
300 private:
301 int fError;
302 string fDescription;
306 // #pragma mark - ELFObject
309 struct SectionInfo {
310 uint32_t type;
311 off_t offset;
312 size_t size;
313 const char* name;
317 class ELFObject {
318 public:
319 ELFObject()
320 : fFD(-1),
321 fSectionHeaderStrings(NULL),
322 fSectionHeaderStringsLength(0)
326 ~ELFObject()
328 Unset();
331 void Unset()
333 if (fFD >= 0) {
334 close(fFD);
335 fFD = -1;
338 delete[] fSectionHeaderStrings;
339 fSectionHeaderStrings = NULL;
342 void SetTo(const char* fileName)
344 Unset();
346 // open the file
347 fFD = open(fileName, O_RDWR);
348 if (fFD < 0)
349 throw Exception("Failed to open \"%s\"", fileName);
351 // get the file size
352 fFileSize = FileSize();
353 if (fFileSize < 0)
354 throw Exception("Failed to get the file size.");
356 // Read identification information
357 unsigned char ident[EI_NIDENT];
358 Read(0, ident, sizeof(ident), "Failed to read ELF identification.");
359 if (memcmp(ident, kELFFileMagic, sizeof(kELFFileMagic)) != 0)
360 throw Exception("Not a valid ELF file.");
361 fELFClass = ident[EI_CLASS];
363 if (fELFClass == ELFCLASS64)
364 _ParseELFHeader<Elf64_Ehdr, Elf64_Shdr>();
365 else
366 _ParseELFHeader<Elf32_Ehdr, Elf32_Shdr>();
369 bool FindSectionByName(const char* name, SectionInfo& foundInfo)
371 // can't find the section by name without section names
372 if (!fSectionHeaderStrings)
373 return false;
375 // iterate through the section headers
376 for (size_t i = 0; i < fSectionHeaderCount; i++) {
377 SectionInfo info;
379 bool result;
380 if (fELFClass == ELFCLASS64)
381 result = _ReadSectionHeader<Elf64_Shdr>(i, info);
382 else
383 result = _ReadSectionHeader<Elf32_Shdr>(i, info);
385 if (result) {
386 //printf("section %3d: offset: %7d, size: %7d, name: %s\n", i, info.offset, info.size, info.name);
387 if (strcmp(info.name, name) == 0) {
388 foundInfo = info;
389 return true;
394 return false;
397 void Read(off_t position, void* buffer, size_t size,
398 const char *errorMessage = NULL)
400 if (lseek(fFD, position, SEEK_SET) < 0)
401 throw Exception(errorMessage);
403 ssize_t bytesRead = read(fFD, buffer, size);
404 if (bytesRead < 0)
405 throw Exception(errorMessage);
407 if ((size_t)bytesRead != size) {
408 if (errorMessage) {
409 throw Exception("%s Read too few bytes (%d/%d).",
410 errorMessage, (int)bytesRead, (int)size);
411 } else {
412 throw Exception("Read too few bytes (%ld/%lu).",
413 (int)bytesRead, (int)size);
418 void Write(off_t position, const void* buffer, size_t size,
419 const char *errorMessage = NULL)
421 if (lseek(fFD, position, SEEK_SET) < 0)
422 throw Exception(errorMessage);
424 ssize_t bytesWritten = write(fFD, buffer, size);
425 if (bytesWritten < 0)
426 throw Exception(errorMessage);
428 if ((size_t)bytesWritten != size) {
429 if (errorMessage) {
430 throw Exception("%s Wrote too few bytes (%d/%d).",
431 errorMessage, (int)bytesWritten, (int)size);
432 } else {
433 throw Exception("Wrote too few bytes (%ld/%lu).",
434 (int)bytesWritten, (int)size);
439 off_t FileSize()
441 off_t currentPos = lseek(fFD, 0, SEEK_END);
442 if (currentPos < 0)
443 return -1;
445 return lseek(fFD, currentPos, SEEK_SET);
448 template<typename Type>
449 Type GetValue(Type& value);
451 private:
452 template<typename EhdrType, typename ShdrType>
453 void _ParseELFHeader();
455 template<typename ShdrType>
456 bool _ReadSectionHeader(int index, SectionInfo& info);
458 // _SwapUInt16
459 static inline uint16_t _SwapUInt16(uint16_t value)
461 return ((value & 0xff) << 8) | (value >> 8);
464 // _SwapUInt32
465 static inline uint32_t _SwapUInt32(uint32_t value)
467 return ((uint32_t)_SwapUInt16(value & 0xffff) << 16)
468 | _SwapUInt16(uint16_t(value >> 16));
471 // _SwapUInt64
472 static inline uint64_t _SwapUInt64(uint64_t value)
474 return ((uint64_t)_SwapUInt32(value & 0xffffffff) << 32)
475 | _SwapUInt32(uint32_t(value >> 32));
478 private:
479 int fFD;
480 uint8_t fELFClass;
481 bool fHostEndianess;
482 off_t fFileSize;
483 size_t fELFHeaderSize;
484 off_t fSectionHeaderTableOffset;
485 size_t fSectionHeaderSize;
486 size_t fSectionHeaderCount;
487 char* fSectionHeaderStrings;
488 uint32_t fSectionHeaderStringsLength;
492 template<>
493 int16_t ELFObject::GetValue(int16_t& value)
495 return (fHostEndianess ? value : _SwapUInt16(value));
499 template<>
500 uint16_t ELFObject::GetValue(uint16_t& value)
502 return (fHostEndianess ? value : _SwapUInt16(value));
506 template<>
507 int32_t ELFObject::GetValue(int32_t& value)
509 return (fHostEndianess ? value : _SwapUInt32(value));
513 template<>
514 uint32_t ELFObject::GetValue(uint32_t& value)
516 return (fHostEndianess ? value : _SwapUInt32(value));
520 template<>
521 int64_t ELFObject::GetValue(int64_t& value)
523 return (fHostEndianess ? value : _SwapUInt64(value));
527 template<>
528 uint64_t ELFObject::GetValue(uint64_t& value)
530 return (fHostEndianess ? value : _SwapUInt64(value));
534 template<typename EhdrType, typename ShdrType>
535 void ELFObject::_ParseELFHeader()
537 // read ELF header
538 EhdrType fileHeader;
539 Read(0, &fileHeader, sizeof(EhdrType), "Failed to read ELF header.");
541 // check data encoding (endianess)
542 switch (fileHeader.e_ident[EI_DATA]) {
543 case ELFDATA2LSB:
544 fHostEndianess = (htonl(1) != 1);
545 break;
546 case ELFDATA2MSB:
547 fHostEndianess = (htonl(1) == 1);
548 break;
549 default:
550 case ELFDATANONE:
551 throw Exception(EIO, "Unsupported ELF data encoding.");
552 break;
555 // get the header values
556 fELFHeaderSize = GetValue(fileHeader.e_ehsize);
557 fSectionHeaderTableOffset = GetValue(fileHeader.e_shoff);
558 fSectionHeaderSize = GetValue(fileHeader.e_shentsize);
559 fSectionHeaderCount = GetValue(fileHeader.e_shnum);
560 bool hasSectionHeaderTable = (fSectionHeaderTableOffset != 0);
562 // check the sanity of the header values
563 // ELF header size
564 if (fELFHeaderSize < sizeof(EhdrType)) {
565 throw Exception(EIO,
566 "Invalid ELF header: invalid ELF header size: %lu.",
567 fELFHeaderSize);
570 // section header table offset and entry count/size
571 if (hasSectionHeaderTable) {
572 if (fSectionHeaderTableOffset < (off_t)fELFHeaderSize
573 || fSectionHeaderTableOffset > fFileSize) {
574 throw Exception(EIO, "Invalid ELF header: invalid section "
575 "header table offset: %llu.",
576 fSectionHeaderTableOffset);
578 size_t sectionHeaderTableSize
579 = fSectionHeaderSize * fSectionHeaderCount;
580 if (fSectionHeaderSize < (off_t)sizeof(ShdrType)
581 || fSectionHeaderTableOffset + (off_t)sectionHeaderTableSize
582 > fFileSize) {
583 throw Exception(EIO, "Invalid ELF header: section header "
584 "table exceeds file: %llu.",
585 fSectionHeaderTableOffset
586 + sectionHeaderTableSize);
590 // load section header string section
591 uint16_t sectionHeaderStringSectionIndex
592 = GetValue(fileHeader.e_shstrndx);
593 if (sectionHeaderStringSectionIndex != SHN_UNDEF) {
594 if (sectionHeaderStringSectionIndex >= fSectionHeaderCount) {
595 throw Exception(EIO, "Invalid ELF header: invalid section "
596 "header string section index: %u.",
597 sectionHeaderStringSectionIndex);
600 // get the section info
601 SectionInfo info;
602 if (_ReadSectionHeader<ShdrType>(sectionHeaderStringSectionIndex,
603 info)) {
604 fSectionHeaderStrings = new char[info.size + 1];
605 Read(info.offset, fSectionHeaderStrings, info.size,
606 "Failed to read section header string section.");
607 fSectionHeaderStringsLength = info.size;
608 // null-terminate to be on the safe side
609 fSectionHeaderStrings[info.size] = '\0';
616 template<typename ShdrType>
617 bool ELFObject::_ReadSectionHeader(int index, SectionInfo& info)
619 off_t shOffset = fSectionHeaderTableOffset
620 + index * fSectionHeaderSize;
621 ShdrType sectionHeader;
622 Read(shOffset, &sectionHeader, sizeof(ShdrType),
623 "Failed to read ELF section header.");
625 // get the header values
626 uint32_t type = GetValue(sectionHeader.sh_type);
627 off_t offset = GetValue(sectionHeader.sh_offset);
628 size_t size = GetValue(sectionHeader.sh_size);
629 uint32_t nameIndex = GetValue(sectionHeader.sh_name);
631 // check the values
632 // SHT_NULL marks the header unused,
633 if (type == SHT_NULL)
634 return false;
636 // SHT_NOBITS sections take no space in the file
637 if (type != SHT_NOBITS) {
638 if (offset < (off_t)fELFHeaderSize || offset > fFileSize) {
639 throw Exception(EIO, "Invalid ELF section header: "
640 "invalid section offset: %llu.", offset);
642 off_t sectionEnd = offset + size;
643 if (sectionEnd > fFileSize) {
644 throw Exception(EIO, "Invalid ELF section header: "
645 "section exceeds file: %llu.", sectionEnd);
649 // get name, if we have a string section
650 if (fSectionHeaderStrings) {
651 if (nameIndex >= (uint32_t)fSectionHeaderStringsLength) {
652 throw Exception(EIO, "Invalid ELF section header: "
653 "invalid name index: %lu.", nameIndex);
655 info.name = fSectionHeaderStrings + nameIndex;
656 } else {
657 info.name = "";
660 info.type = type;
661 info.offset = offset;
662 info.size = size;
665 return true;
669 // main
671 main(int argc, const char* const* argv)
673 sArgc = argc;
674 sArgv = argv;
676 if (argc < 3)
677 print_usage_and_exit(true);
679 // parameters
680 const char* fileName = argv[1];
681 const char* revisionString = argv[2];
683 try {
684 ELFObject elfObject;
685 elfObject.SetTo(fileName);
687 // find haiku revision section
688 SectionInfo info;
689 if (!elfObject.FindSectionByName("_haiku_revision", info)) {
690 fprintf(stderr, "haiku revision section not found\n");
691 exit(1);
694 // write revision string to section
695 elfObject.Write(info.offset, revisionString,
696 min((size_t)SYSTEM_REVISION_LENGTH, strlen(revisionString) + 1),
697 "Failed to write revision.");
699 } catch (Exception exception) {
700 if (exception.Description() == "") {
701 fprintf(stderr, "%s\n", strerror(exception.Error()));
702 } else {
703 fprintf(stderr, "%s: %s\n", exception.Description().c_str(),
704 strerror(exception.Error()));
706 exit(1);
709 return 0;