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