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
Attributes(void)29 Attributes::Attributes(void) {
30 numAttrs++;
31 if (numAttrs == 1)
32 Setup();
33 attributes = 0;
34 } // constructor
35
36 // Alternate constructor
Attributes(const uint64_t a)37 Attributes::Attributes(const uint64_t a) {
38 numAttrs++;
39 if (numAttrs == 1)
40 Setup();
41 attributes = a;
42 } // alternate constructor
43
44 // Destructor.
~Attributes(void)45 Attributes::~Attributes(void) {
46 numAttrs--;
47 } // Attributes destructor
48
Setup(void)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
DisplayAttributes(void)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.
ShowAttributes(const uint32_t partNum)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
ChangeAttributes(void)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).
ListAttributes(void)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
OperateOnAttributes(const uint32_t partNum,const string & attributeOperator,const string & attributeBits)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
operator <<(ostream & os,const Attributes & data)225 ostream & operator<<(ostream & os, const Attributes & data) {
226 os << data.GetAttributes();
227 return os;
228 } // operator<<()
229