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