1 // attributes.cc 2 // Class to manage partition attribute codes. These are binary bit fields, 3 // of which only four are currently (2/2011) documented on Wikipedia, and 4 // two others found from other sources. 5 6 /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed 7 under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 8 9 #define __STDC_LIMIT_MACROS 10 #ifndef __STDC_CONSTANT_MACROS 11 #define __STDC_CONSTANT_MACROS 12 #endif 13 14 #include <stdint.h> 15 #include <stdio.h> 16 #include <iostream> 17 #include <sstream> 18 19 #include "attributes.h" 20 #include "support.h" 21 22 using namespace std; 23 24 string Attributes::atNames[NUM_ATR]; 25 int Attributes::numAttrs = 0; 26 //Attributes::staticInit Attributes::staticInitializer; 27 28 // Default constructor 29 Attributes::Attributes(void) { 30 numAttrs++; 31 if (numAttrs == 1) 32 Setup(); 33 attributes = 0; 34 } // constructor 35 36 // Alternate constructor 37 Attributes::Attributes(const uint64_t a) { 38 numAttrs++; 39 if (numAttrs == 1) 40 Setup(); 41 attributes = a; 42 } // alternate constructor 43 44 // Destructor. 45 Attributes::~Attributes(void) { 46 numAttrs--; 47 } // Attributes destructor 48 49 void Attributes::Setup(void) { 50 ostringstream temp; 51 52 // Most bits are undefined, so start by giving them an 53 // appropriate name 54 for (int i = 0; i < NUM_ATR; i++) { 55 temp.str(""); 56 temp << "Undefined bit #" << i; 57 Attributes::atNames[i] = temp.str(); 58 } // for 59 60 // Now reset those names that are defined.... 61 atNames[0] = "system partition"; // required for computer to operate 62 atNames[1] = "hide from EFI"; 63 atNames[2] = "legacy BIOS bootable"; 64 atNames[60] = "read-only"; 65 atNames[62] = "hidden"; 66 atNames[63] = "do not automount"; 67 } // Attributes::Setup() 68 69 // Display current attributes to user 70 void Attributes::DisplayAttributes(void) { 71 uint32_t i; 72 int numSet = 0; 73 74 cout << "Attribute value is "; 75 cout.setf(ios::uppercase); 76 cout.fill('0'); 77 cout.width(16); 78 cout << hex << attributes << dec << ". Set fields are:\n"; 79 for (i = 0; i < NUM_ATR; i++) { 80 if ((UINT64_C(1) << i) & attributes) { 81 cout << i << " (" << GetAttributeName(i) << ")" << "\n"; 82 numSet++; 83 } // if 84 } // for 85 cout.fill(' '); 86 if (numSet == 0) 87 cout << " No fields set\n"; 88 cout << "\n"; 89 } // Attributes::DisplayAttributes() 90 91 // Display attributes for a partition. Note that partNum is just passed for 92 // immediate display; it's not used to access a particular partition. 93 void Attributes::ShowAttributes(const uint32_t partNum) { 94 uint32_t bitNum; 95 bool bitset; 96 97 for (bitNum = 0; bitNum < 64; bitNum++) { 98 bitset = (UINT64_C(1) << bitNum) & attributes; 99 if (bitset) { 100 cout << partNum+1 << ":" << bitNum << ":" << bitset 101 << " (" << GetAttributeName(bitNum) << ")" << endl; 102 } // if 103 } // for 104 } // Attributes::ShowAttributes 105 106 // Prompt user for attribute changes 107 void Attributes::ChangeAttributes(void) { 108 int response; 109 uint64_t bitValue; 110 111 cout << "Known attributes are:\n"; 112 ListAttributes(); 113 cout << "\n"; 114 115 do { 116 DisplayAttributes(); 117 response = GetNumber(0, NUM_ATR, 64, 118 "Toggle which attribute field (0-63, 64 or <Enter> to exit): "); 119 if (response != 64) { 120 bitValue = UINT64_C(1) << response; // Find the integer value of the bit 121 if (bitValue & attributes) { // bit is set 122 attributes &= ~bitValue; // so unset it 123 cout << "Have disabled the '" << atNames[response] << "' attribute.\n"; 124 } else { // bit is not set 125 attributes |= bitValue; // so set it 126 cout << "Have enabled the '" << atNames[response] << "' attribute.\n"; 127 } // if/else 128 } // if 129 } while (response != 64); 130 } // Attributes::ChangeAttributes() 131 132 // Display all defined attributes on the screen (omits undefined bits). 133 void Attributes::ListAttributes(void) { 134 uint32_t bitNum; 135 string tempAttr; 136 137 for (bitNum = 0; bitNum < NUM_ATR; bitNum++) { 138 tempAttr = GetAttributeName(bitNum); 139 if (tempAttr.substr(0, 15) != "Undefined bit #" ) 140 cout << bitNum << ": " << Attributes::GetAttributeName(bitNum) << "\n"; 141 } // for 142 } // Attributes::ListAttributes 143 144 // multifaceted attributes access 145 // returns true upon success, false upon failure 146 bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits) { 147 148 // attribute access opcode 149 typedef enum { 150 ao_or, ao_nand, ao_xor, ao_assignall, // operate on all attributes (bitmask) 151 ao_unknown, // must be after bitmask operators and before bitnum operators 152 ao_set, ao_clear, ao_toggle, ao_get // operate on a single attribute (bitnum) 153 } attribute_opcode_t; // typedef enum 154 155 // translate attribute operator into an attribute opcode 156 attribute_opcode_t attributeOpcode = ao_unknown; { // opcode is not known yet 157 if (attributeOperator == "or") attributeOpcode = ao_or; 158 else if (attributeOperator == "nand") attributeOpcode = ao_nand; 159 else if (attributeOperator == "xor") attributeOpcode = ao_xor; 160 else if (attributeOperator == "=") attributeOpcode = ao_assignall; 161 else if (attributeOperator == "set") attributeOpcode = ao_set; 162 else if (attributeOperator == "clear") attributeOpcode = ao_clear; 163 else if (attributeOperator == "toggle") attributeOpcode = ao_toggle; 164 else if (attributeOperator == "get") attributeOpcode = ao_get; 165 else { 166 cerr << "Unknown attributes operator: " << attributeOperator << endl; 167 return false; 168 } // else 169 } // attributeOpcode 170 171 // get bit mask if operating on entire attribute set 172 uint64_t attributeBitMask; { if (attributeOpcode < ao_unknown) { 173 if (1 != sscanf (attributeBits.c_str(), "%qx", (long long unsigned int*) &attributeBitMask)) { 174 cerr << "Could not convert hex attribute mask" << endl; 175 return false; 176 } // if 177 }} // attributeBitMask, if 178 179 // get bit number and calculate bit mask if operating on a single attribute 180 int bitNum; { if (attributeOpcode > ao_unknown) { 181 if (1 != sscanf (attributeBits.c_str(), "%d", &bitNum)) { 182 cerr << "Could not convert bit number" << endl; 183 return false; 184 } // if 185 const uint64_t one = 1; 186 attributeBitMask = one << bitNum; 187 }} // bitNum, if 188 189 switch (attributeOpcode) { 190 // assign all attributes at once 191 case ao_assignall: attributes = attributeBitMask; break; 192 193 // set individual attribute(s) 194 case ao_set: 195 case ao_or: attributes |= attributeBitMask; break; 196 197 // clear individual attribute(s) 198 case ao_clear: 199 case ao_nand: attributes &= ~attributeBitMask; break; 200 201 // toggle individual attribute(s) 202 case ao_toggle: 203 case ao_xor: attributes ^= attributeBitMask; break; 204 205 // display a single attribute 206 case ao_get: { 207 cout << partNum+1 << ":" << bitNum << ":" 208 << bool (attributeBitMask & attributes) << endl; 209 break; 210 } // case ao_get 211 212 default: break; // will never get here 213 } // switch 214 215 return true; 216 } // Attributes::OperateOnAttributes() 217 218 /******************************* 219 * * 220 * Non-class support functions * 221 * * 222 *******************************/ 223 224 // Display attributes 225 ostream & operator<<(ostream & os, const Attributes & data) { 226 os << data.GetAttributes(); 227 return os; 228 } // operator<<() 229