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