xref: /third_party/gptfdisk/attributes.cc (revision cf200d32)
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
22using namespace std;
23
24string Attributes::atNames[NUM_ATR];
25int Attributes::numAttrs = 0;
26//Attributes::staticInit Attributes::staticInitializer;
27
28// Default constructor
29Attributes::Attributes(void) {
30   numAttrs++;
31   if (numAttrs == 1)
32      Setup();
33   attributes = 0;
34} // constructor
35
36// Alternate constructor
37Attributes::Attributes(const uint64_t a) {
38   numAttrs++;
39   if (numAttrs == 1)
40      Setup();
41   attributes = a;
42} // alternate constructor
43
44// Destructor.
45Attributes::~Attributes(void) {
46   numAttrs--;
47} // Attributes destructor
48
49void 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
70void 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.
93void 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
107void 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).
133void 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
146bool 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
225ostream & operator<<(ostream & os, const Attributes & data) {
226   os << data.GetAttributes();
227   return os;
228} // operator<<()
229