Vis innlegg

Denne delen lar deg se alle innlegg laget av dette medlemmet. Merk at du bare kan se innlegg gjort i områder du har tilgang til.

Emner - Floyd-ATC

Sider: [1] 2 3 ... 12
Generelt teknisk / Rust: How to test a module that uses TcpStream?
« på: 27. April 2023, 14:06 pm »
How do you make a module testable that requires a std::net::TcpStream?

I had this problem with a (toy) project of mine that used a struct to encapsulate a BufReader and a BufWriter, presenting only the following in order to make it impossible to accidentally leak data into or out of the raw stream:

Kode: [Velg]
    pub fn new(TcpStream) -> Self
    pub fn reader(&mut self) -> &mut BufReader<TcpStream>
    pub fn writer(&mut self) -> &mut BufWriter<TcpStream>
    pub fn close(&mut self)

My initial though was to use generics to allow any type of stream but this turned out to be both really hard (because std::net::TcpStream uses .try_clone() rather than implementing the Clone trait, and it uses .shutdown(Shutdown) instead of .close()) and it would have required all the modules that depended on this one to deal with the generics that weren't needed to begin with. What started as a simple problem was now becoming really complicated in my mind.

I could turn it around by saying that my component now just implements a new trait, but this would not only require a whole lot of extra code just to implement, it would still require all the other modules to deal with the extra generics and most importantly: it would actually bring me no closer to the original goal: Testing this really quite simple module right here.

During my evening walk, it finally dawned on me that the people who designed the IP stack already thought of this exact problem (as well as many other problems) decades ago and they implemented a solution so simple it's easy to forget about it and make things harder than they need be:

The loopback address.

Specifying a port number of 0 means the operating system gets to pick an unused port for you. So I simply added one more function, a double constructor that creates a pair of object instances connected to each other:

Kode: [Velg]
    // Convenience function for testing
    pub fn loopback() -> Result<(Self, Self), std::io::Error> {
        let listener = TcpListener::bind("")?;

        // From viewpoint of the client
        let server_addr = listener.local_addr()?;
        let server = TcpStream::connect(server_addr)?;

        // From viewpoint of the server
        let (client, client_addr) = listener.accept()?;

        let conn1 = Self::new(server, server_addr);
        let conn2 = Self::new(client, client_addr);
        return Ok((conn1, conn2));

Not only did this make it trivial to test this module, it also made it dead simple to test all those other modules that depended on this one! The idea is easily transferred to other types of scenarios where you have to test code that uses TcpStream directly:

Kode: [Velg]
mod tests {
    use super::*;

    fn loopback() -> Result<(std::net::TcpStream, std::net::TcpStream), std::io::Error> {
        let listener = std::net::TcpListener::bind("")?;
        let server = std::net::TcpStream::connect(listener.local_addr().unwrap())?;
        let (client, _) = listener.accept()?;
        return Ok((server, client));

    // Actual tests here, just call loopback() whenever you need a pair of streams connected to each other
    // Put data into one, read it out of the other.
    // ...


Final note: On certain very locked-down platforms you may have to relax local firewall rules in order to allow loopback traffic, but no sane person would ever test their network code on a machine anywhere near production anyway so if this turns out to be a problem then maybe you should re-evaluate how and where you do things.

Eco / Vote "No"
« på: 18. Juli 2021, 10:24 am »
To spillere fra Nederland, dikkenoob nl og TTV_Goodpuma, forsøker å ratifisere en ribbet grunnlov som vil gjøre dem til "president" og "vice precident" med all makt. Ingen spillere vil kunne fremme lovforslag eller påvirke noe som helst hvis denne loven går igjennom vil det være vanskelig å rekruttere flere spillere. Jeg vil derfor ikke ha annet valg enn å slette den som administrator, noe jeg helst vil slippe.

Logg inn. Stem "Nei".

Eco / Eksperimentell Eco-server "ATC Sanctuary"
« på: 16. Juli 2021, 08:37 am »
Jeg har satt opp en eksperimentell Eco-server, foreløpig med "no collaboration" men vi får se hva det er stemning for hvis det kommer spillere på den. Meteoren slår ned om først et år, så dette er en server ment for langsiktig og virkelighetstro bygging med hensyn til miljøet.

Jeg har NULL erfaring med det politiske aspektet ved Eco så hvis noen er interessert i å prøve seg er det bare å joine.

Rent teknisk, serveren står på 40 Mbps idag men gigabit fiber kommer i løpet av sommeren :-)

I wanted to use TLS on a regular socket file descriptor and could not find a single man-page or example explaining how to construct the BIO* that let me do cleartext BIO_read() and BIO_write() on a HTTPS socket.

After much experimenting, I finally figured it out. Making a note here for future reference.

Kode: [Velg]
// context is a smart pointer to a CTX* structure containing certs etc.
// server_fd is a plain TCP socket descriptor in "listen" mode
// returns client_fd that your application must close
// Use BIO_read() and BIO_write() to communicate with the client,
// you *MUST NOT* read/write on client_fd
int Socket::accept(const Context& context, int server_fd)
  this->verify_flag = -1;
  this->ssl = nullptr;
  this->bio = nullptr;

  // TCP accept
  int client_fd = Net::accept(server_fd);
  if (client_fd != -1) {
    // TCP accept successful

    // Create a BIO chain and get the SSL pointer
    BIO* raw = BIO_new_socket(client_fd, BIO_NOCLOSE);
    BIO* ssl = BIO_new_ssl(context.get(), 0); // 0=server, 1=client
    this->bio = BIO_push(ssl, raw);
    BIO_get_ssl(ssl, &this->ssl);
    // SSL protocol accept
    int rc = SSL_accept(this->ssl);
    if (rc <= 0) {
      // 0 = SSL failure, <0 = connection failure
      client_fd = -1;

    std::cout << "calling SSL_get_verify_result()" << std::endl;
    this->verify_flag = SSL_get_verify_result(this->ssl);
  return client_fd;

Generelt teknisk / C++ unique_ptr wrapper for strdup()
« på: 29. ſeptember 2020, 11:48 am »
How to wrap a char* from strdup() in a smart pointer to guarantee it gets freed?

Kode: [Velg]
#include <memory>
typedef std::unique_ptr<char, decltype(&std::free)> char_ptr;

char_ptr make_char_ptr(const std::string str)
  return char_ptr(strdup(, std::free);


char_ptr foo = make_char_ptr("bar");
foo.get(); // char* pointer to a copy of "bar"

// pointer automatically gets freed when 'foo' goes out of scope
// or can be freed manually with

This question seems to be a FAQ that nobody seems to understand or answer correctly, instead answering a lot of other questions dealing with clock irregularity and loss of precision when dealing with nanoseconds. Neither of which matter when you're using double precision and only want milliseconds for moving a game object on the screen or whatever and the occasional jitter or skew from a timesync event isn't going to bring about the end of civilization as we know it.

So here's how I finally managed to solve it with my fairly limited C++ skill:
Kode: [Velg]
double now() {
  auto time = std::chrono::system_clock::now().time_since_epoch();
  std::chrono::seconds seconds = std::chrono::duration_cast< std::chrono::seconds >(time);
  std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(time);
  return (double) seconds.count() + ((double) (ms.count() % 1000)/1000.0);

Sample output:
Kode: [Velg]
1577703729.406= Unix timestamp in seconds as a double with millisecond precision.

There you have it.

Useful in pretty much any formula that deals with time in seconds, yet somehow not documented anywhere and unbelievably verbose for a modern library supposedly written specifically to deal exclusively with time.

Generelt teknisk / intermittent dhclient bad udp checksum
« på: 12. November 2018, 08:01 am »
Running a CentOS 7.3 router with DHCP address from my ISP, I would sometimes get an IP address, sometimes not. Sometimes the IP address would get assigned but then fail to renew, causing seemingly random loss of connectivity. Rebooting would sometimes fix it, sometimes not. Very annoying.

Studying the problem over time, tcpdump revealed that the UDP checksum on outgoing packets from dhclient would periodically have bad checksums. Not empty, just incorrect. Why this happens only sometimes and not all the time is beyond me, it's probably just a stupid bug in dhclient but I found the following workaround:

Kode: [Velg]
firewall-cmd --permanent --direct --add-rule ipv4 mangle POSTROUTING 0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
This will recalculate the UDP checksum on all outgoing UDP/68 traffic and not touch anything else. Reload firewalld with "systemctl reload firewalld" or reboot for the change to take effect, then verify with tcpdump.

Kode: [Velg]
tcpdump -i ens160 -nn -vv port 68(Substitute ens160 with your external interface, obviously)

It's also possible to activate the change by repeating the firewall-cmd without the "--permanent" clause ofcourse, but I usually just reboot to make absolutely sure I didn't break anything while experimenting --  this may not be feasible in your environment BUT on the other hand, if you are reading this then chances are you are already experiencing random service interruptions so.... You decide.

Google Chrome will complain loudly if run as root, telling you to add --no-sandbox manually and then showing you a warning that this is a really bad idea. Imagine if you could have Gnome solve the problem for you?

Well, you can. First of all, understand that running a web browser as root IS a bad idea, because there will always be security vulnerabilities. However, since Linux is a modern operating system, it's quite possible to be logged in as root and still run the web browser as a less privileged process:

First, create a separate user account that will be used for web browsing. For example: "anonymous".
Make sure you give this user a really REALLY strong password. You will never need to actually use it.

Now copy the file "/usr/share/applications/google-chrome.desktop" to "/root/.local/share/applications/google-chrome.desktop"

Edit all the lines starting with "Exec=" by inserting "gksu -wu anonymous". For example:
Kode: [Velg]
Exec=gksu -wu anonymous /usr/bin/google-chrome-stable %U

Now log out and log back in to restart the Gnome shell, and you should be able to start Chrome without any hassle. Use the command "ps auxfw | grep chrome" to verify that the processes run as "anonymous" and not as "root". Remember that any manual changes to the browser settings etc. must be made under "/home/anonymous".

Spent several weeks banging my head against the wall with this problem. When trying to start "atom" it just never appeared. When trying with "atom -f" (to run in the foreground) I would get the following error messages:
Kode: [Velg]
[] Running without the SUID sandbox! See https:
[] Multiple instances of AudioManager detected
[] Multiple instances of AudioManager detected
[] X IO error received (X server probably went away)

I focused on the first error message for a long time and found all sorts of red herrings, closed bug reports and no actual solutions. Finally it dawned on me that the actual problem was the LAST error message. I access my desktop via X2GO and therefore have a pretty special DISPLAY environment variable. Maybe that had something to do with it?

Kode: [Velg]
# cp /usr/lib/x86_64-linux-gnu/ /opt/atom
# sed -i 's/BIG-REQUESTS/_IG-REQUESTS/' /opt/atom/

...and suddenly atom worked.

Generelt teknisk / CentOS 7 nmap-ncat does not support SOCKS5
« på: 16. Oktober 2016, 19:59 pm »
Tunneling an ssh session through a SOCKS5 proxy (e.g. using Tor) should be possible by adding the following to your
Kode: [Velg]
/etc/ssh/ssh_config file:

Kode: [Velg]
Host *
        CheckHostIP no
        Compression yes
        Protocol 2
        ProxyCommand ncat --nodns --proxy-type socks5 --proxy %h %p

Unfortunately, RHEL7/CentOS 7 ships with a rather antiquated version of nmap-ncat (a modern replacement for the now unmaintained BSD netcat) and this version only supports socks4.

Trying to use socks4 is similar to using no proxy at all, it fails with the following rather cryptic error message:
Kode: [Velg]
get_sock_port: getnameinfo NI_NUMERICSERV failed: ai_family not supported
Uninstall the useless version of nmap-ncat:
Kode: [Velg]
yum erase nmap-ncatDownload the newest RPM from
Install it. Example:
Kode: [Velg]
yum localinstall ncat-7.30-1.x86_64.rpmFix your
Kode: [Velg]
/etc/ssh/ssh_config as shown above.

Generelt teknisk / Powershell: Round to nearest integer
« på: 14. Oktober 2016, 10:07 am »
For some bizarre reason, Microsoft decided that Powershell should by default use "Banker's rounding" which by their logic is more "natural" than what people "entrenched in C" (as well as any other programming language and elementary school level mathematics) would expect.

Long story short, Powershell will by default round both 1.5 and 2.5 to 2, 3.5 and 4.5 to 4 etc.

Workaround? Define the following function to get the universally expected "round UP from .5" behaviour:

Kode: [Velg]
function round( $value, [MidpointRounding]$mode = 'AwayFromZero' ) {
  [Math]::Round( $value, $mode )

Kode: [Velg]
PS> [int]3.5
PS> [int]4.5
PS> round 3.5
PS> round 4.5

In these two code snippets, the "continue" keyword does quite the opposite of what it's supposed to:
Kode: [Velg]
PS C:\> ('a','b','c') | % { $_; continue }
Kode: [Velg]
PS C:\> ('a','b','c') | foreach { $_; continue }

When spelling the code out like you would in a sane scripting language, it works as expected:
Kode: [Velg]
PS C:\> foreach ($i in ('a','b','c')) { $i; continue }

Go figure.
Kode: [Velg]
PS C> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      -1     -1

Screeps / A method for tile based path caching in Screeps
« på: 12. ſeptember 2016, 19:51 pm »

Because path finding is one of the most CPU intensive ("expensive") operations in Screeps, the need to re-use paths is a well known topic. Generally speaking, the following factors must be considered when choosing a cache strategy:

- CPU cost of learning new paths (insert)
- CPU cost of changing existing paths (update)
- CPU cost of looking up paths (select)
- CPU cost of pruning outdated entries (delete)
- Storage space

For any caching scheme to worthwhile, we must assume that each path in the cache should ideally be inserted once and selected as many times as possible. Because changes are inevitable and there is no absolute way to determine how often an individual path will be selected, the scheme must allow update and delete operations to be carried out with reasonable performance.

Most scripting languages offer built-in data types that fulfill all of these requirements but in Screeps there is another factor which severely limits the options: Storage performance.

Because all information in Screeps Memory must be serialized before storage and deserialized before use, the total number of objects in Memory soon becomes an important factor in addition to the already tight restrictions on storage space. Add to this the fact that data structures like arrays and hash tables introduce storage overhead when serialized, and it soon becomes obvious that storing fewer and bigger strings is favorable over smaller and more numerous variables.

What's in a path

An important realization is that an individual path from Pos1 to Pos2 contains much more information than just how to get from Pos1 to Pos2. Given a cluster 10 positions around Pos1 in one room and a second cluster of 10 positions around Pos2 in another room, it is fair to assume that the majority of the steps in each of the 10*10=100 possible paths between the two clusters will actually be the same. This is especially true if there is a road between the two clusters. Storing multiple instances of the same information is not only a waste of storage space (and therefore a waste of CPU resources to serialize/deserialize) but also means more information has to be processed when performing insert/update/delete and select operations.

Possible solutions

This leads to the obvious solution that information should be stored per tile so that each tile contains information about how to reach other tiles from there. At this point one might think in terms of a simple nested hash:

   cache[from_tile][to_tile] = direction

There is a number of problems with this approach. First, let's say we have 10 rooms, each room may have up to 2500 tiles (of which atleast 1% are in use). A very conservative estimate of 250 first level entries with 250 second level entries means we have 62500 objects in memory that need to be serialized and deserialized each tick. It soon becomes obvious that with all the information needed to uniquely identify each position this puts us well above the 2048K limit even before we put in any directions. One might therefore consider normalizing the information by separating information per room:
   cache[from_room][from_tile][to_room][to_tile] = direction

This eliminates the need to spell out each room name 250+250 times but we still have over 62500 objects in memory and use a non-trivial amount of storage space just to store structural characters such as "{},:".

Custom serialization

In response to this, a common idea is to consider other ways to serialize and deserialize Memory. I do not suggest doing this, because of several reasons:

- Performance is unlikely to be that much better unless you place severe limitations on what can be stored in memory.
- The built-in Memory access scheme relies on the possibility to access Memory in a certain way. We must either accomodate this or reimplement everything, hopefully without hurting performance.
- It is much more beneficial to address the fundamental problem and reduce the number of tiny objects we need to store. In a way, this means applying our own idea of serialization but targeting only a specific part of the data structure.

Packing information as densely as possible

One critical bit of information about the Memory object in Screeps is that it can handle UTF-16 characters. At first glance, this may seem irrelevant because room names and tile coordinates do not contain special characters, but coupled with Javascript's built-in methods for storing and retrieving UTF-16 character codes this gives us a rather convenient way to store and retrieve 16-bit values (albeit with a few important restrictions, google UTF BOM for details.)

Why is this useful? Consider the fact that a single tile coordinate can be expressed using 6+6 bits (remember, 6 bits can store a single number from 0 to 63) and a direction can be expressed using 3 bits. We have to keep in mind that certain special character codes in UTF-16 are invalid but it turns out that we can actually use the 16th bit as long as we keep those 4 highest bits in the range between 0 and 8 inclusive.

This puts us at 16 bits (2 bytes) per tile even with the direction, but we can do even better than that. If a tile happens to contain directions to multiple consecutive destinations we can choose to store them as a "span", similar to how Run Length Encoding works. Distinguishing between a span and an individual destination can be done using a "magic" direction of 0:

   code1 = x1 + (y1*50) | (1<<12) // 0x1000   Single destination with direction=1

   code1 = x1 + (y1*50) | 0       // 0x0000   Span begins at x1,y1
   code2 = x2 + (y2*50) | (3<<12) // 0x3000   Span ends at x2,y2 with direction=3

Strings of these codes can be stored for each tile, effectively reducing the number of objects to serialize/deserialize by atleast a factor of 250. For rooms with a large amount of walkable tiles, this factor can be even higher.

An alternative to the x+50y approach is to use bit shifting exclusively:

   code1 = x1 | (y1<<6) | (1<<12)

I have not bothered with benchmarking these to see which one is faster. My guess is that the difference in terms of CPU time is negligible.

Implementing access

Even if the problem of storage space and serialization/deserialization performance has been solved, there is still the non-trivial matter of implementing efficient methods to insert/update/select and delete information. These are our findings:

- The codes should always be sorted by tile address (x+50y). This eliminates the need to search the entire string to the end in both the case of a cache miss and a new insert, because the search can be aborted as soon as a higher address is encountered. The search is always carried out on the packed data structure to search the shortest string possible.

- Only when an insert/update is needed, the packed format (with spans) should be unpacked (without spans) so individual addresses can be inserted, updated or appended as needed. The unpacked data structure must be sparse, otherwise the compression operation will require a constant loop of 2500 iterations even for a string with no actual information in it.

- Only when all modifications have been made, the unpacked structure should be packed (with spans). This is the most expensive algorithm of the three in terms of CPU time because the entire unpacked string must be processed. It is therefore beneficial to put as much information into the string at once rather than making small, incremental changes.

Pseudocode for learning

Kode: [Velg]
for each tile T1 in path including start(1)
  stop if T1 is in a different room from start(2)
  get next direction as D
  fetch routing table for tile T1
  for each tile T2 in path including target(3)
    update table T1; move in direction D to reach T2
  store routing table for tile T1

1) The path will typically start with the first move, not the first tile. We need to put information into the first tile because that's where creeps will (hopefully) start later too.
2) The pathfinder may provide suboptimal results for rooms where we do not have vision. Instead of trying to deal with this in each case, simply learn the path leading to the next room and recalculate the path once we get there and see the roads etc. This also serves as a safeguard against the script spending ages on learning just one very long path.
3) The creep will probably want a path leading to the target later on, not the tiles in between, so don't forget this crucial little detail. The information about the tiles in between are just a nice bonus. You may want to try reducing the cache size and learning time by only learning the ultimate destination but in my experience this reduces the overall efficiency by causing more path searches. (See "What's in a path".)

Actual results

My current implementation runs at GCL4 with path information for 11 rooms and 40+ creeps. My total Memory is around 200 Kbytes total but I can pretty much decide how much memory to use by adjusting the cache age. My current setting is 1800 ticks, which seems to work pretty well. According to screeps-profiler, the average time to move creeps is 0.370ms, this includes pathfinding, learning, routing and the occasional fallback to moveTo/ignoreCreeps:false for collision avoidance. I use the new Pathfinder and typically see between 0 and 3 path searches per tick. Take info account that I am relatively inexperienced with both Javascript and Screeps so your results may differ. Anyway, this is what my current data structure looks like:

Kode: [Velg]
    r Container object for routing information
      E##N## One hash per room
        xxyy Tile coordinates formatted as 4 digits, one hash per tile
          mru Game.time of last access
          local String of UTF16 characters for this room
          E##N## String of UTF16 characters for destination room
          E##N## String of UTF16 characters for destination room

Possible improvements

- This is just one possible storage structure, but I strongly recommended to store one string per combination of rooms, together with cache control data such as a MRU timestamp. This makes it trivial to discard data for any single room or tile when needed.

- Cache invalidation such as handling blocked paths resulting from new structures or using new roads is a huge topic and the full discussion is well beyond the scope of this document. One simple strategy is to introduce a small random chance to recalculate paths even if cached information exists. Another strategy is to drop random tiles from the cache to trigger recalculation.

- The suggested concept of spans form horizontal "stripes" of adjacent tiles. One possible improvement might be to form rectangular areas, either by using a more complicated algorithm to begin with or by splitting and combining adjacent "stripes" in a second pass. It is unclear if this added complexity would provide a net savings in terms of CPU performance and/or storage space.

- It might be worthwhile to store other information (such as path cost) together with the routing information in the form of trailing characters. Although the non-trivial increase in complexity and memory use would require serious consideration, this could be helpful if one wanted to write a modified pathfinder capable of taking cached information into account. 

I'm sharing this in the hope that you will find it useful. If you discover a cool way to improve the efficiency or find a stupid fault in my logic, your in-game feedback would be greatly appreciated. Preferably in the form of a message, not an invasion.

Cloulez aka. FloydATC

Shamelessly stolen from Rodney Barnhardt,

1.Connect to the serial port with the following settings:
o 9600 baud
o 8 data bits
o none/no parity
o 1 stop bit
o none/no flow control

2.Reboot the Data Domain system
3.During RAM test hit one of the following keys (BIOS version depends on which one works)
d.ESC 2
4.Enter the password, which from what you say, yours should be: d500d
5.Select Server Management (or advanced) and then Console Redirection
6.Set Legacy OS Redirection to ON (MAKE SURE NO OTHER CHANGES ARE MADE!)
7.It will look like it is rebooting, hit the TAB key at the boot screen
8.Type “p” at the prompt and enter the following password: ddrc0s (that is a zero)
9.Select “a” to append the boot-serial option
10.Make the following change by adding this to the kernel boot line: goto-bash console=ttyS0 (this is a zero)
11.Hit ENTER to save the change and then press “b” to continue booting.
12.When the reboot halts, enter the following commands /bin/sh x
b.ln –s /bin/bash  /bin/sh
c.dd_bootmodule  --reassemble-only
13.Use the following command to get the root name: cat  /proc/cmdline
14.Depending on what is returned, you will use the following to mount the device:
a.If root=/dev/root-pl1, use dd_dg00p15
b.If root=/dev/root-pl2, use dd_dg00p5
c.If root=/dev/dd_dg00p15, use dd_dg00p15
15.Mount using the results from above. EXAMPLE: mount  /dev/dd_dg00p5
16.Edit the shadow file in vi by typing : vi  /sysroot/etc/shadow
17.Remove the encrypted password from the sysadmin account. The line will look something like this: “sysadmin:#3465@^fg/$GJITFD:13371:0:99999:7:::” After editing, it should look like the following:”sysadmin::13371:0:99999:7::: 
18.Enter :wq to save and exit the editor
19.Then enter the following commands to properly exit and reboot:
a.sync; sync; sync
c.umount  /sysroot
20.Once the system has rebooted, create a new password with the following command: user change password sysadmin

Generelt teknisk / Accessing the shell on DataDomain DD510
« på: 25. Juli 2016, 19:11 pm »
Shamelessly stolen from

Please note: use of engineering mode allows you to do major amounts of damage to your data with a frightening degree of ease and rapidity. Don’t try to access engineering mode unless you’re fully prepared to have to re-install your DataDomain – inclusive of destroying what’s left of the data on it.

Accessing SE Mode:
SSH to the DataDomain.
Login with an account that has system administrator privileges (this may be one of the default accounts your array was installed with, a local account you’ve set up for the purpose or an Active Directory managed account that has been placed into a Active Directory security-group that has been granted the system administrator role on the DataDomain
Get the array’s serial number. The easiest way to do this is type `system show serialno` at the default command prompt
Access SE mode by typing `priv set se`. You will be prompted for a password – the password is the serial number from the prior step.
At this point, your command prompt will change to “SE@<ARRAYNAME>” where “<ARRAYNAME>” will be the nodename of your DataDomain. While in this mode, an additional command-set will be enabled. These commands are accessed by typing “se”. You can get a further listing of the “se” sub-commands in much the same way you can get help at the normal system administration shell (in this particular case: by typing “se ?”).
Accessing the SE BASH Shell:
Once you’re in SE mode, the following command-sequence will allow you to access the engineering mode’s BASH shell:

Type “uname”
Type “fi st”
Type “df”
Type <CTRL>-C three times
Type “shell-escape”
At this point, a warning banner will come up to remind you of the jeopardy you’ve put your configuration in. The prompt will also change to include a warning. This is DataDomain’s way of reminding you, at every step, the danger of the access-level you’ve entered.

Once you’ve gotten the engineering BASH shell, you have pretty much unfettered access to the guts of the DataDomain. The BASH shell is pretty much the same as you’d encounter on a stock Linux system. Most of the GNU utilities you’re used to using will be there and will work the same way they do on Linux. You won’t have man pages, so, if you forget flags to a given shell command, look them up on a Linux host that has the man pages installed.

In addition to the standard Linux commands will be some DataDomain-specific commands. These are the commands that are accessible from the “se” command and its subcommands. The primary use-case for exercising these commands in BASH mode is that the BASH mode is pretty much as fully-scriptable as a root prompt on a normal Linux host. In other words, take all the danger and power of SE mode and wrap it in the sweaty-dynamite of an automated script (you can do a lot of modifications/damage by horsing the se sub-commands to a BASH `find` command or script).

Sider: [1] 2 3 ... 12