1e7b4ff9317fc4e551cf974684eaa88697de5a28srs// attributes.cc
2e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Class to manage partition attribute codes. These are binary bit fields,
364cbd171067eb34054741bfcd73f0b91d727a371srs// of which only four are currently (2/2011) documented on Wikipedia, and
464cbd171067eb34054741bfcd73f0b91d727a371srs// two others found from other sources.
5e7b4ff9317fc4e551cf974684eaa88697de5a28srs
6e3ee733ff8690af7568dac665bc20ecf869dea1dRoderick W. Smith/* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed
7221e08768de7fe42ba533ca22baf671420569c07srs  under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
8221e08768de7fe42ba533ca22baf671420569c07srs
9e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_LIMIT_MACROS
10e7b4ff9317fc4e551cf974684eaa88697de5a28srs#define __STDC_CONSTANT_MACROS
11e7b4ff9317fc4e551cf974684eaa88697de5a28srs
12e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdint.h>
13e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include <stdio.h>
14fed16d043a14e8b86c97a6413aec7281fefcbcb5srs#include <iostream>
1508bb0da07953af605b4918e268272de15ac151aasrs#include <sstream>
169ddc14bb9b154518e2b8384d3f4571cf657c7920srs
17e7b4ff9317fc4e551cf974684eaa88697de5a28srs#include "attributes.h"
189ddc14bb9b154518e2b8384d3f4571cf657c7920srs#include "support.h"
19e7b4ff9317fc4e551cf974684eaa88697de5a28srs
20e7b4ff9317fc4e551cf974684eaa88697de5a28srsusing namespace std;
21e7b4ff9317fc4e551cf974684eaa88697de5a28srs
229ddc14bb9b154518e2b8384d3f4571cf657c7920srsstring Attributes::atNames[NUM_ATR];
230873e9d0e9345a2c4418b4718db525c9f1111c83srsint Attributes::numAttrs = 0;
240873e9d0e9345a2c4418b4718db525c9f1111c83srs//Attributes::staticInit Attributes::staticInitializer;
250873e9d0e9345a2c4418b4718db525c9f1111c83srs
260873e9d0e9345a2c4418b4718db525c9f1111c83srs// Default constructor
270873e9d0e9345a2c4418b4718db525c9f1111c83srsAttributes::Attributes(void) {
280873e9d0e9345a2c4418b4718db525c9f1111c83srs   numAttrs++;
290873e9d0e9345a2c4418b4718db525c9f1111c83srs   if (numAttrs == 1)
300873e9d0e9345a2c4418b4718db525c9f1111c83srs      Setup();
310873e9d0e9345a2c4418b4718db525c9f1111c83srs   attributes = 0;
320873e9d0e9345a2c4418b4718db525c9f1111c83srs} // constructor
330873e9d0e9345a2c4418b4718db525c9f1111c83srs
340873e9d0e9345a2c4418b4718db525c9f1111c83srs// Alternate constructor
350873e9d0e9345a2c4418b4718db525c9f1111c83srsAttributes::Attributes(const uint64_t a) {
360873e9d0e9345a2c4418b4718db525c9f1111c83srs   numAttrs++;
370873e9d0e9345a2c4418b4718db525c9f1111c83srs   if (numAttrs == 1)
380873e9d0e9345a2c4418b4718db525c9f1111c83srs      Setup();
390873e9d0e9345a2c4418b4718db525c9f1111c83srs   attributes = a;
400873e9d0e9345a2c4418b4718db525c9f1111c83srs} // alternate constructor
41e7b4ff9317fc4e551cf974684eaa88697de5a28srs
420873e9d0e9345a2c4418b4718db525c9f1111c83srs// Destructor.
430873e9d0e9345a2c4418b4718db525c9f1111c83srsAttributes::~Attributes(void) {
440873e9d0e9345a2c4418b4718db525c9f1111c83srs   numAttrs--;
450873e9d0e9345a2c4418b4718db525c9f1111c83srs} // Attributes destructor
460873e9d0e9345a2c4418b4718db525c9f1111c83srs
470873e9d0e9345a2c4418b4718db525c9f1111c83srsvoid Attributes::Setup(void) {
489ddc14bb9b154518e2b8384d3f4571cf657c7920srs   ostringstream temp;
490873e9d0e9345a2c4418b4718db525c9f1111c83srs
50e7b4ff9317fc4e551cf974684eaa88697de5a28srs   // Most bits are undefined, so start by giving them an
51e7b4ff9317fc4e551cf974684eaa88697de5a28srs   // appropriate name
529ddc14bb9b154518e2b8384d3f4571cf657c7920srs   for (int i = 0; i < NUM_ATR; i++) {
539ddc14bb9b154518e2b8384d3f4571cf657c7920srs      temp.str("");
5408bb0da07953af605b4918e268272de15ac151aasrs      temp << "Undefined bit #" << i;
559ddc14bb9b154518e2b8384d3f4571cf657c7920srs      Attributes::atNames[i] = temp.str();
56e7b4ff9317fc4e551cf974684eaa88697de5a28srs   } // for
57e7b4ff9317fc4e551cf974684eaa88697de5a28srs
58e7b4ff9317fc4e551cf974684eaa88697de5a28srs   // Now reset those names that are defined....
590873e9d0e9345a2c4418b4718db525c9f1111c83srs   atNames[0] = "system partition"; // required for computer to operate
600873e9d0e9345a2c4418b4718db525c9f1111c83srs   atNames[1] = "hide from EFI";
610873e9d0e9345a2c4418b4718db525c9f1111c83srs   atNames[2] = "legacy BIOS bootable";
620873e9d0e9345a2c4418b4718db525c9f1111c83srs   atNames[60] = "read-only";
630873e9d0e9345a2c4418b4718db525c9f1111c83srs   atNames[62] = "hidden";
640873e9d0e9345a2c4418b4718db525c9f1111c83srs   atNames[63] = "do not automount";
650873e9d0e9345a2c4418b4718db525c9f1111c83srs}  // Attributes::Setup()
66e7b4ff9317fc4e551cf974684eaa88697de5a28srs
67e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Display current attributes to user
68e7b4ff9317fc4e551cf974684eaa88697de5a28srsvoid Attributes::DisplayAttributes(void) {
699ddc14bb9b154518e2b8384d3f4571cf657c7920srs   uint32_t i;
709ddc14bb9b154518e2b8384d3f4571cf657c7920srs   int numSet = 0;
71e7b4ff9317fc4e551cf974684eaa88697de5a28srs
72fed16d043a14e8b86c97a6413aec7281fefcbcb5srs   cout << "Attribute value is ";
73fed16d043a14e8b86c97a6413aec7281fefcbcb5srs   cout.setf(ios::uppercase);
74fed16d043a14e8b86c97a6413aec7281fefcbcb5srs   cout.fill('0');
75fed16d043a14e8b86c97a6413aec7281fefcbcb5srs   cout.width(16);
76fed16d043a14e8b86c97a6413aec7281fefcbcb5srs   cout << hex << attributes << dec << ". Set fields are:\n";
77e7b4ff9317fc4e551cf974684eaa88697de5a28srs   for (i = 0; i < NUM_ATR; i++) {
789ddc14bb9b154518e2b8384d3f4571cf657c7920srs      if ((UINT64_C(1) << i) & attributes) {
790873e9d0e9345a2c4418b4718db525c9f1111c83srs         cout << i << " (" << GetAttributeName(i) << ")" << "\n";
809ddc14bb9b154518e2b8384d3f4571cf657c7920srs         numSet++;
81e7b4ff9317fc4e551cf974684eaa88697de5a28srs      } // if
82e7b4ff9317fc4e551cf974684eaa88697de5a28srs   } // for
83fed16d043a14e8b86c97a6413aec7281fefcbcb5srs   cout.fill(' ');
849ddc14bb9b154518e2b8384d3f4571cf657c7920srs   if (numSet == 0)
859ddc14bb9b154518e2b8384d3f4571cf657c7920srs      cout << "  No fields set\n";
869ddc14bb9b154518e2b8384d3f4571cf657c7920srs   cout << "\n";
87e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // Attributes::DisplayAttributes()
88e7b4ff9317fc4e551cf974684eaa88697de5a28srs
890873e9d0e9345a2c4418b4718db525c9f1111c83srs// Display attributes for a partition. Note that partNum is just passed for
900873e9d0e9345a2c4418b4718db525c9f1111c83srs// immediate display; it's not used to access a particular partition.
910873e9d0e9345a2c4418b4718db525c9f1111c83srsvoid Attributes::ShowAttributes(const uint32_t partNum) {
920873e9d0e9345a2c4418b4718db525c9f1111c83srs   uint32_t bitNum;
930873e9d0e9345a2c4418b4718db525c9f1111c83srs   bool bitset;
940873e9d0e9345a2c4418b4718db525c9f1111c83srs
950873e9d0e9345a2c4418b4718db525c9f1111c83srs   for (bitNum = 0; bitNum < 64; bitNum++) {
960873e9d0e9345a2c4418b4718db525c9f1111c83srs      bitset = (UINT64_C(1) << bitNum) & attributes;
970873e9d0e9345a2c4418b4718db525c9f1111c83srs      if (bitset) {
980873e9d0e9345a2c4418b4718db525c9f1111c83srs         cout << partNum+1 << ":" << bitNum << ":" << bitset
990873e9d0e9345a2c4418b4718db525c9f1111c83srs         << " (" << GetAttributeName(bitNum) << ")" << endl;
1000873e9d0e9345a2c4418b4718db525c9f1111c83srs      } // if
1010873e9d0e9345a2c4418b4718db525c9f1111c83srs   } // for
1020873e9d0e9345a2c4418b4718db525c9f1111c83srs} // Attributes::ShowAttributes
1030873e9d0e9345a2c4418b4718db525c9f1111c83srs
104e7b4ff9317fc4e551cf974684eaa88697de5a28srs// Prompt user for attribute changes
105e7b4ff9317fc4e551cf974684eaa88697de5a28srsvoid Attributes::ChangeAttributes(void) {
1069ddc14bb9b154518e2b8384d3f4571cf657c7920srs   int response;
107e7b4ff9317fc4e551cf974684eaa88697de5a28srs   uint64_t bitValue;
108e7b4ff9317fc4e551cf974684eaa88697de5a28srs
109fed16d043a14e8b86c97a6413aec7281fefcbcb5srs   cout << "Known attributes are:\n";
1109ddc14bb9b154518e2b8384d3f4571cf657c7920srs   ListAttributes();
1119ddc14bb9b154518e2b8384d3f4571cf657c7920srs   cout << "\n";
112e7b4ff9317fc4e551cf974684eaa88697de5a28srs
113e7b4ff9317fc4e551cf974684eaa88697de5a28srs   do {
1149ddc14bb9b154518e2b8384d3f4571cf657c7920srs      DisplayAttributes();
1150873e9d0e9345a2c4418b4718db525c9f1111c83srs      response = GetNumber(0, NUM_ATR, 64,
1160873e9d0e9345a2c4418b4718db525c9f1111c83srs                           "Toggle which attribute field (0-63, 64 or <Enter> to exit): ");
117e7b4ff9317fc4e551cf974684eaa88697de5a28srs      if (response != 64) {
1189ddc14bb9b154518e2b8384d3f4571cf657c7920srs         bitValue = UINT64_C(1) << response; // Find the integer value of the bit
1199ddc14bb9b154518e2b8384d3f4571cf657c7920srs         if (bitValue & attributes) { // bit is set
1209ddc14bb9b154518e2b8384d3f4571cf657c7920srs            attributes &= ~bitValue; // so unset it
1219ddc14bb9b154518e2b8384d3f4571cf657c7920srs	         cout << "Have disabled the '" << atNames[response] << "' attribute.\n";
122e7b4ff9317fc4e551cf974684eaa88697de5a28srs         } else { // bit is not set
1239ddc14bb9b154518e2b8384d3f4571cf657c7920srs            attributes |= bitValue; // so set it
124fed16d043a14e8b86c97a6413aec7281fefcbcb5srs            cout << "Have enabled the '" << atNames[response] << "' attribute.\n";
125e7b4ff9317fc4e551cf974684eaa88697de5a28srs         } // if/else
126e7b4ff9317fc4e551cf974684eaa88697de5a28srs      } // if
127e7b4ff9317fc4e551cf974684eaa88697de5a28srs   } while (response != 64);
128e7b4ff9317fc4e551cf974684eaa88697de5a28srs} // Attributes::ChangeAttributes()
129e7b4ff9317fc4e551cf974684eaa88697de5a28srs
1309ddc14bb9b154518e2b8384d3f4571cf657c7920srs// Display all defined attributes on the screen (omits undefined bits).
1319ddc14bb9b154518e2b8384d3f4571cf657c7920srsvoid Attributes::ListAttributes(void) {
1329ddc14bb9b154518e2b8384d3f4571cf657c7920srs   uint32_t bitNum;
1339ddc14bb9b154518e2b8384d3f4571cf657c7920srs   string tempAttr;
1349ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1359ddc14bb9b154518e2b8384d3f4571cf657c7920srs   for (bitNum = 0; bitNum < NUM_ATR; bitNum++) {
1369ddc14bb9b154518e2b8384d3f4571cf657c7920srs      tempAttr = GetAttributeName(bitNum);
1379ddc14bb9b154518e2b8384d3f4571cf657c7920srs      if (tempAttr.substr(0, 15) != "Undefined bit #" )
1389ddc14bb9b154518e2b8384d3f4571cf657c7920srs         cout << bitNum << ": " << Attributes::GetAttributeName(bitNum) << "\n";
1399ddc14bb9b154518e2b8384d3f4571cf657c7920srs   } // for
1409ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // Attributes::ListAttributes
1419ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1429ddc14bb9b154518e2b8384d3f4571cf657c7920srs// multifaceted attributes access
1439ddc14bb9b154518e2b8384d3f4571cf657c7920srs// returns true upon success, false upon failure
1449ddc14bb9b154518e2b8384d3f4571cf657c7920srsbool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits) {
1459ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1469ddc14bb9b154518e2b8384d3f4571cf657c7920srs   // attribute access opcode
1479ddc14bb9b154518e2b8384d3f4571cf657c7920srs   typedef enum {
1489ddc14bb9b154518e2b8384d3f4571cf657c7920srs      ao_or, ao_nand, ao_xor, ao_assignall,  // operate on all attributes (bitmask)
1499ddc14bb9b154518e2b8384d3f4571cf657c7920srs      ao_unknown, // must be after bitmask operators and before bitnum operators
1509ddc14bb9b154518e2b8384d3f4571cf657c7920srs      ao_set, ao_clear, ao_toggle, ao_get    // operate on a single attribute (bitnum)
1519ddc14bb9b154518e2b8384d3f4571cf657c7920srs   } attribute_opcode_t; // typedef enum
1529ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1539ddc14bb9b154518e2b8384d3f4571cf657c7920srs   // translate attribute operator into an attribute opcode
1549ddc14bb9b154518e2b8384d3f4571cf657c7920srs   attribute_opcode_t attributeOpcode = ao_unknown; { // opcode is not known yet
1559ddc14bb9b154518e2b8384d3f4571cf657c7920srs      if      (attributeOperator == "or")      attributeOpcode = ao_or;
1569ddc14bb9b154518e2b8384d3f4571cf657c7920srs      else if (attributeOperator == "nand")    attributeOpcode = ao_nand;
1579ddc14bb9b154518e2b8384d3f4571cf657c7920srs      else if (attributeOperator == "xor")     attributeOpcode = ao_xor;
1589ddc14bb9b154518e2b8384d3f4571cf657c7920srs      else if (attributeOperator == "=")       attributeOpcode = ao_assignall;
1599ddc14bb9b154518e2b8384d3f4571cf657c7920srs      else if (attributeOperator == "set")     attributeOpcode = ao_set;
1609ddc14bb9b154518e2b8384d3f4571cf657c7920srs      else if (attributeOperator == "clear")   attributeOpcode = ao_clear;
1619ddc14bb9b154518e2b8384d3f4571cf657c7920srs      else if (attributeOperator == "toggle")  attributeOpcode = ao_toggle;
1629ddc14bb9b154518e2b8384d3f4571cf657c7920srs      else if (attributeOperator == "get")     attributeOpcode = ao_get;
1639ddc14bb9b154518e2b8384d3f4571cf657c7920srs      else {
1649ddc14bb9b154518e2b8384d3f4571cf657c7920srs         cerr << "Unknown attributes operator: " << attributeOperator << endl;
1659ddc14bb9b154518e2b8384d3f4571cf657c7920srs         return false;
1669ddc14bb9b154518e2b8384d3f4571cf657c7920srs      } // else
1679ddc14bb9b154518e2b8384d3f4571cf657c7920srs   } // attributeOpcode
1689ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1699ddc14bb9b154518e2b8384d3f4571cf657c7920srs   // get bit mask if operating on entire attribute set
1709ddc14bb9b154518e2b8384d3f4571cf657c7920srs   uint64_t attributeBitMask; { if (attributeOpcode < ao_unknown) {
1719ddc14bb9b154518e2b8384d3f4571cf657c7920srs      if (1 != sscanf (attributeBits.c_str(), "%qx", (long long unsigned int*) &attributeBitMask)) {
1729ddc14bb9b154518e2b8384d3f4571cf657c7920srs         cerr << "Could not convert hex attribute mask" << endl;
1739ddc14bb9b154518e2b8384d3f4571cf657c7920srs         return false;
1749ddc14bb9b154518e2b8384d3f4571cf657c7920srs      } // if
1759ddc14bb9b154518e2b8384d3f4571cf657c7920srs   }} // attributeBitMask, if
1769ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1779ddc14bb9b154518e2b8384d3f4571cf657c7920srs   // get bit number and calculate bit mask if operating on a single attribute
1789ddc14bb9b154518e2b8384d3f4571cf657c7920srs   int bitNum; { if (attributeOpcode > ao_unknown) {
1799ddc14bb9b154518e2b8384d3f4571cf657c7920srs      if (1 != sscanf (attributeBits.c_str(), "%d", &bitNum)) {
1809ddc14bb9b154518e2b8384d3f4571cf657c7920srs         cerr << "Could not convert bit number" << endl;
1819ddc14bb9b154518e2b8384d3f4571cf657c7920srs         return false;
1829ddc14bb9b154518e2b8384d3f4571cf657c7920srs      } // if
1839ddc14bb9b154518e2b8384d3f4571cf657c7920srs      const uint64_t one = 1;
1849ddc14bb9b154518e2b8384d3f4571cf657c7920srs      attributeBitMask = one << bitNum;
1859ddc14bb9b154518e2b8384d3f4571cf657c7920srs   }} // bitNum, if
1869ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1879ddc14bb9b154518e2b8384d3f4571cf657c7920srs   switch (attributeOpcode) {
1889ddc14bb9b154518e2b8384d3f4571cf657c7920srs      // assign all attributes at once
1899ddc14bb9b154518e2b8384d3f4571cf657c7920srs      case ao_assignall:  attributes = attributeBitMask;    break;
1909ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1919ddc14bb9b154518e2b8384d3f4571cf657c7920srs      // set individual attribute(s)
1929ddc14bb9b154518e2b8384d3f4571cf657c7920srs      case ao_set:
1939ddc14bb9b154518e2b8384d3f4571cf657c7920srs      case ao_or:         attributes |= attributeBitMask;   break;
1949ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1959ddc14bb9b154518e2b8384d3f4571cf657c7920srs      // clear individual attribute(s)
1969ddc14bb9b154518e2b8384d3f4571cf657c7920srs      case ao_clear:
1979ddc14bb9b154518e2b8384d3f4571cf657c7920srs      case ao_nand:       attributes &= ~attributeBitMask;  break;
1989ddc14bb9b154518e2b8384d3f4571cf657c7920srs
1999ddc14bb9b154518e2b8384d3f4571cf657c7920srs      // toggle individual attribute(s)
2009ddc14bb9b154518e2b8384d3f4571cf657c7920srs      case ao_toggle:
2019ddc14bb9b154518e2b8384d3f4571cf657c7920srs      case ao_xor:        attributes ^= attributeBitMask;   break;
2029ddc14bb9b154518e2b8384d3f4571cf657c7920srs
2039ddc14bb9b154518e2b8384d3f4571cf657c7920srs      // display a single attribute
2049ddc14bb9b154518e2b8384d3f4571cf657c7920srs      case ao_get: {
205ab4b0438394df4ae6bdea86194e254d7d35fdea0srs         cout << partNum+1 << ":" << bitNum << ":"
206ab4b0438394df4ae6bdea86194e254d7d35fdea0srs              << bool (attributeBitMask & attributes) << endl;
2079ddc14bb9b154518e2b8384d3f4571cf657c7920srs         break;
2089ddc14bb9b154518e2b8384d3f4571cf657c7920srs      } // case ao_get
2099ddc14bb9b154518e2b8384d3f4571cf657c7920srs
2109ddc14bb9b154518e2b8384d3f4571cf657c7920srs      default: break; // will never get here
2119ddc14bb9b154518e2b8384d3f4571cf657c7920srs   } // switch
2129ddc14bb9b154518e2b8384d3f4571cf657c7920srs
2139ddc14bb9b154518e2b8384d3f4571cf657c7920srs   return true;
2149ddc14bb9b154518e2b8384d3f4571cf657c7920srs} // Attributes::OperateOnAttributes()
2150873e9d0e9345a2c4418b4718db525c9f1111c83srs
2160873e9d0e9345a2c4418b4718db525c9f1111c83srs/*******************************
2170873e9d0e9345a2c4418b4718db525c9f1111c83srs*                             *
2180873e9d0e9345a2c4418b4718db525c9f1111c83srs* Non-class support functions *
2190873e9d0e9345a2c4418b4718db525c9f1111c83srs*                             *
2200873e9d0e9345a2c4418b4718db525c9f1111c83srs*******************************/
2210873e9d0e9345a2c4418b4718db525c9f1111c83srs
2220873e9d0e9345a2c4418b4718db525c9f1111c83srs// Display attributes
2230873e9d0e9345a2c4418b4718db525c9f1111c83srsostream & operator<<(ostream & os, const Attributes & data) {
2240873e9d0e9345a2c4418b4718db525c9f1111c83srs   os << data.GetAttributes();
2250873e9d0e9345a2c4418b4718db525c9f1111c83srs   return os;
226699941e25a1fcf0beec124203747c8ed20842989srs} // operator<<()
227